From 05c2e3b5d4a57a801c51f9ca5a648dd878a94713 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Sat, 29 Nov 2025 16:58:18 -0800 Subject: [PATCH 01/12] mappers and dto for workout schedules --- .../controller/CoachingController.java | 2 ++ .../coaching/ClientAgreementSnippetDto.java | 11 ++++++++ .../dto/coaching/ClientViewResponseDto.java | 17 ++++++++++++ .../dto/scheduling/ExerciseDto.java | 15 +++++++++++ .../dto/scheduling/MovementDto.java | 14 ++++++++++ .../dto/scheduling/TrainingScheduleDto.java | 14 ++++++++++ .../dto/scheduling/WorkoutDto.java | 19 +++++++++++++ .../clientservice/mapper/ExerciseMapper.java | 25 +++++++++++++++++ .../clientservice/mapper/MovementMapper.java | 14 ++++++++++ .../mapper/TrainingScheduleMapper.java | 14 ++++++++++ .../clientservice/mapper/WorkoutMapper.java | 27 +++++++++++++++++++ .../cm/clientservice/model/ClientProfile.java | 27 ------------------- .../cm/clientservice/model/CoachProfile.java | 24 ----------------- ...outSchedule.java => TrainingSchedule.java} | 0 14 files changed, 172 insertions(+), 51 deletions(-) create mode 100644 client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/MovementDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/TrainingScheduleMapper.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java delete mode 100644 client-service/src/main/java/com/cm/clientservice/model/ClientProfile.java delete mode 100644 client-service/src/main/java/com/cm/clientservice/model/CoachProfile.java rename client-service/src/main/java/com/cm/clientservice/model/schedule/{WorkoutSchedule.java => TrainingSchedule.java} (100%) diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java new file mode 100644 index 0000000..02b2068 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -0,0 +1,2 @@ +package com.cm.clientservice.controller;public class CoachController { +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java b/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java new file mode 100644 index 0000000..b2f9323 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java @@ -0,0 +1,11 @@ +package com.cm.clientservice.dto.coaching; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ClientAgreementSnippetDto { + + +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java new file mode 100644 index 0000000..fc17a53 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java @@ -0,0 +1,17 @@ +package com.cm.clientservice.dto.coaching; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ClientViewResponseDto { + + private ClientAgreementSnippetDto clientAgreementSnippetDto; + + private String firstName; + private String lastName; + private String email; + private String id; + private String dateOfBirth; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java new file mode 100644 index 0000000..96e0faa --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java @@ -0,0 +1,15 @@ +package com.cm.clientservice.dto.scheduling; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ExerciseDto { + + private String id; + private MovementDto movement; + private String numSets; + private String numReps; + private String coachNotes; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/MovementDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/MovementDto.java new file mode 100644 index 0000000..03feab9 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/MovementDto.java @@ -0,0 +1,14 @@ +package com.cm.clientservice.dto.scheduling; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MovementDto { + private String id; + private String name; + private String description; +} + + diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java new file mode 100644 index 0000000..57a05a9 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java @@ -0,0 +1,14 @@ +package com.cm.clientservice.dto.scheduling; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class TrainingScheduleDto { + + private String id; + private List workouts; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java new file mode 100644 index 0000000..ece886f --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java @@ -0,0 +1,19 @@ +package com.cm.clientservice.dto.scheduling; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class WorkoutDto { + + private String id; + + private List exercises; + + private String date; + private String workoutNotes; + private String isCompleted; +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java new file mode 100644 index 0000000..ae38491 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java @@ -0,0 +1,25 @@ +package com.cm.clientservice.mapper; + +import com.cm.clientservice.dto.scheduling.ExerciseDto; +import com.cm.clientservice.model.schedule.Exercise; + +import java.util.List; + +public class ExerciseMapper { + public static List toDto(List exercises) { + return exercises.stream() + .map(ExerciseMapper::toDto) + .toList(); + } + + public static ExerciseDto toDto(Exercise exercise){ + ExerciseDto dto = new ExerciseDto(); + + dto.setId(exercise.getId().toString()); + dto.setMovement(MovementMapper.toDto(exercise.getMovement())); + dto.setCoachNotes(exercise.getCoachNotes()); + dto.setNumReps(String.valueOf(exercise.getNumReps())); + dto.setNumSets(String.valueOf(exercise.getNumSets())); + return dto; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java new file mode 100644 index 0000000..9cdc257 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java @@ -0,0 +1,14 @@ +package com.cm.clientservice.mapper; +import com.cm.clientservice.dto.scheduling.MovementDto; +import com.cm.clientservice.model.schedule.Movement; + +public class MovementMapper { + + public static MovementDto toDto(Movement movement){ + MovementDto dto = new MovementDto(); + dto.setId(movement.getId().toString()); + dto.setName(movement.getName()); + dto.setDescription(movement.getDescription()); + return dto; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/TrainingScheduleMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/TrainingScheduleMapper.java new file mode 100644 index 0000000..8af60fb --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/TrainingScheduleMapper.java @@ -0,0 +1,14 @@ +package com.cm.clientservice.mapper; +import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; +import com.cm.clientservice.model.schedule.TrainingSchedule; + +public class TrainingScheduleMapper { + + public static TrainingScheduleDto toDto(TrainingSchedule trainingSchedule) { + TrainingScheduleDto dto = new TrainingScheduleDto(); + + dto.setId(String.valueOf(trainingSchedule.getId())); + dto.setWorkouts(WorkoutMapper.toDto(trainingSchedule.getWorkouts())); + return dto; + } +} \ No newline at end of file diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java new file mode 100644 index 0000000..2497508 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java @@ -0,0 +1,27 @@ +package com.cm.clientservice.mapper; + +import com.cm.clientservice.dto.scheduling.WorkoutDto; +import com.cm.clientservice.model.schedule.Workout; + +import java.util.List; +public class WorkoutMapper { + + public static List toDto(List workouts){ + return workouts + .stream() + .map(WorkoutMapper::toDto) + .toList(); + } + + public static WorkoutDto toDto(Workout workout){ + WorkoutDto dto = new WorkoutDto(); + + dto.setId(String.valueOf(workout.getId())); + dto.setDate(workout.getDate().toString()); + dto.setWorkoutNotes(workout.getWorkoutNotes()); + dto.setIsCompleted(workout.getIsCompleted().toString()); + dto.setExercises(ExerciseMapper.toDto(workout.getExercises())); + + return dto; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/model/ClientProfile.java b/client-service/src/main/java/com/cm/clientservice/model/ClientProfile.java deleted file mode 100644 index 7a75c6c..0000000 --- a/client-service/src/main/java/com/cm/clientservice/model/ClientProfile.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.cm.clientservice.model; - -import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; -import java.util.UUID; - -@Entity -@Getter -@Setter -public class ClientProfile { - - @Id - @GeneratedValue - private UUID id; - - @ManyToMany - @JoinTable( - name = "client_coach_map", - joinColumns = @JoinColumn(name = "client_profile_id"), - inverseJoinColumns = @JoinColumn(name = "coach_profile_id") - ) - private List coaches; -} diff --git a/client-service/src/main/java/com/cm/clientservice/model/CoachProfile.java b/client-service/src/main/java/com/cm/clientservice/model/CoachProfile.java deleted file mode 100644 index df64424..0000000 --- a/client-service/src/main/java/com/cm/clientservice/model/CoachProfile.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.cm.clientservice.model; -import jakarta.persistence.*; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; -import java.util.UUID; - -@Entity -@Getter -@Setter -public class CoachProfile { - - @Id - @GeneratedValue - private UUID id; - - @ManyToMany(mappedBy = "coaches") - private List clients; - - @NotNull - private String biography; -} \ No newline at end of file diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/WorkoutSchedule.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java similarity index 100% rename from client-service/src/main/java/com/cm/clientservice/model/schedule/WorkoutSchedule.java rename to client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java From f7e4400abd7627e18aabc2919e66559ac73770d8 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Sat, 29 Nov 2025 18:11:47 -0800 Subject: [PATCH 02/12] mappers for client agreement and related. also some models --- .../coaching/ClientAgreementSnippetDto.java | 11 ---------- .../dto/coaching/ClientViewResponseDto.java | 17 ---------------- .../dto/contract/AgreementTemplateDto.java | 15 ++++++++++++++ .../dto/contract/CoachClientAgreementDto.java | 13 ++++++++++++ .../contract/AgreementTemplateMapper.java | 20 +++++++++++++++++++ .../contract/CoachClientAgreementMapper.java | 16 +++++++++++++++ .../java/com/cm/clientservice/model/User.java | 18 ++++++++++++----- .../model/contract/AgreementTemplate.java | 4 ++-- .../model/contract/CoachClientAgreement.java | 11 +++++----- .../model/schedule/TrainingSchedule.java | 2 +- .../clientservice/model/schedule/Workout.java | 4 ++-- .../CoachClientAgreementRepository.java | 2 ++ .../service/CoachClientAgreementService.java | 2 ++ 13 files changed, 91 insertions(+), 44 deletions(-) delete mode 100644 client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java delete mode 100644 client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java create mode 100644 client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java create mode 100644 client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java diff --git a/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java b/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java deleted file mode 100644 index b2f9323..0000000 --- a/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientAgreementSnippetDto.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.cm.clientservice.dto.coaching; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class ClientAgreementSnippetDto { - - -} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java deleted file mode 100644 index fc17a53..0000000 --- a/client-service/src/main/java/com/cm/clientservice/dto/coaching/ClientViewResponseDto.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.cm.clientservice.dto.coaching; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class ClientViewResponseDto { - - private ClientAgreementSnippetDto clientAgreementSnippetDto; - - private String firstName; - private String lastName; - private String email; - private String id; - private String dateOfBirth; -} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateDto.java new file mode 100644 index 0000000..0f003b3 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateDto.java @@ -0,0 +1,15 @@ +package com.cm.clientservice.dto.contract; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AgreementTemplateDto { + private String id; + private String authorId; + private String paymentAmount; + private String daysBetweenPayments; + private String termsAndConditions; + private String version; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java new file mode 100644 index 0000000..960c85e --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java @@ -0,0 +1,13 @@ +package com.cm.clientservice.dto.contract; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CoachClientAgreementDto { + private String coachId; + private String clientId; + private String startDate; + private AgreementTemplateDto agreementTemplateDto; +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java new file mode 100644 index 0000000..2722dff --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java @@ -0,0 +1,20 @@ +package com.cm.clientservice.mapper.contract; + +import com.cm.clientservice.dto.contract.AgreementTemplateDto; +import com.cm.clientservice.model.contract.AgreementTemplate; + +public class AgreementTemplateMapper { + + public static AgreementTemplateDto toDto(AgreementTemplate agreementTemplate){ + AgreementTemplateDto dto = new AgreementTemplateDto(); + + dto.setId(agreementTemplate.getId().toString()); + dto.setVersion(agreementTemplate.getVersion().toString()); + dto.setPaymentAmount(agreementTemplate.getPaymentAmount().toString()); + dto.setTermsAndConditions(agreementTemplate.getTermsAndConditions()); + dto.setDaysBetweenPayments(agreementTemplate.getDaysBetweenPayments().toString()); + dto.setAuthorId(agreementTemplate.getAuthor().getId().toString()); + + return dto; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java new file mode 100644 index 0000000..db124a8 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java @@ -0,0 +1,16 @@ +package com.cm.clientservice.mapper.contract; +import com.cm.clientservice.dto.contract.CoachClientAgreementDto; +import com.cm.clientservice.model.contract.CoachClientAgreement; + +public class CoachClientAgreementMapper { + public static CoachClientAgreementDto toDto(CoachClientAgreement agreement) { + CoachClientAgreementDto dto = new CoachClientAgreementDto(); + + dto.setAgreementTemplateDto(AgreementTemplateMapper.toDto(agreement.getAgreementTemplate())); + dto.setClientId(agreement.getClient().getId().toString()); + dto.setCoachId(agreement.getCoach().getId().toString()); + dto.setStartDate(agreement.getStartDate().toString()); + + return dto; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/model/User.java b/client-service/src/main/java/com/cm/clientservice/model/User.java index 1b552df..eaf763d 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/User.java +++ b/client-service/src/main/java/com/cm/clientservice/model/User.java @@ -1,5 +1,8 @@ package com.cm.clientservice.model; +import com.cm.clientservice.model.contract.AgreementTemplate; +import com.cm.clientservice.model.contract.CoachClientAgreement; +import com.cm.clientservice.model.schedule.TrainingSchedule; import jakarta.persistence.*; import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; @@ -44,11 +47,16 @@ public class User { @NotBlank private String address; - @OneToOne - @JoinColumn(name = "coach_profile_id") - private CoachProfile coachProfile; + @OneToMany(mappedBy = "coach") + private List coachAgreements; + + @OneToMany(mappedBy = "client") + private List clientAgreements; + + @OneToMany(mappedBy = "author") + private List authoredTemplates; @OneToOne - @JoinColumn(name = "client_profile_id") - private ClientProfile clientProfile; + @JoinColumn(name="training_schedule_id") + private TrainingSchedule trainingSchedule; } diff --git a/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java b/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java index e49e1aa..d78d47f 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java +++ b/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java @@ -1,6 +1,6 @@ package com.cm.clientservice.model.contract; -import com.cm.clientservice.model.CoachProfile; +import com.cm.clientservice.model.User; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; @@ -22,7 +22,7 @@ public class AgreementTemplate { @NotNull(message = "Original author must be included for agreement template.") @ManyToOne @JoinColumn(name = "coach_profile_id") - private CoachProfile author; + private User author; @NotNull(message = "Need to specify if author will allow public template reuse.") private Boolean allowPublicTemplateReuse; diff --git a/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java b/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java index ab67f6d..fb9c9a7 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java +++ b/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java @@ -1,7 +1,6 @@ package com.cm.clientservice.model.contract; -import com.cm.clientservice.model.ClientProfile; -import com.cm.clientservice.model.CoachProfile; +import com.cm.clientservice.model.User; import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import lombok.Getter; @@ -23,14 +22,14 @@ public class CoachClientAgreement { private UUID id; @ManyToOne - @JoinColumn(name = "client_profile_id") + @JoinColumn(name = "client_id") @NotNull(message = "Client profile must be included in coach-client agreement. ") - private ClientProfile clientProfile; + private User client; @ManyToOne - @JoinColumn(name = "coach_profile_id") + @JoinColumn(name = "coach_id") @NotNull(message = "Coach profile must be included in coach-client agreement. ") - private CoachProfile coachProfile; + private User coach; @ManyToOne @JoinColumn(name = "agreement_template_id") diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java index 3718998..d34a160 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java @@ -9,7 +9,7 @@ @Entity @Getter @Setter -public class WorkoutSchedule { +public class TrainingSchedule { @Id @GeneratedValue diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java index e437f1e..210dc68 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java @@ -1,7 +1,7 @@ package com.cm.clientservice.model.schedule; import jakarta.persistence.*; -import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.PositiveOrZero; import lombok.Getter; import lombok.Setter; @@ -32,5 +32,5 @@ public class Workout { private String workoutNotes; @NotNull - private boolean isCompleted; + private Boolean isCompleted; } diff --git a/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java b/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java new file mode 100644 index 0000000..e85f724 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java @@ -0,0 +1,2 @@ +package com.cm.clientservice.repository;public interface CoachClientAgreementRepository { +} diff --git a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java new file mode 100644 index 0000000..5f83dc7 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java @@ -0,0 +1,2 @@ +package com.cm.clientservice.service;public class CoachClientAgreementService { +} From 5f961ca7bfec0db7bc27c061007f681e768802e4 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Sun, 30 Nov 2025 23:13:22 -0800 Subject: [PATCH 03/12] coaching and client endpoints and services small amount of work for getting schedules --- .../controller/ClientController.java | 45 ++++++++-- .../controller/CoachingController.java | 84 ++++++++++++++++++- .../controller/UserController.java | 17 +--- .../TrainingScheduleNotFoundException.java | 7 ++ .../UnauthorizedScheduleAccessException.java | 7 ++ .../CoachClientAgreementRepository.java | 12 ++- .../repository/UserRepository.java | 4 - .../service/CoachClientAgreementService.java | 28 ++++++- .../cm/clientservice/service/UserService.java | 71 +++++++++++++--- 9 files changed, 239 insertions(+), 36 deletions(-) create mode 100644 client-service/src/main/java/com/cm/clientservice/exception/TrainingScheduleNotFoundException.java create mode 100644 client-service/src/main/java/com/cm/clientservice/exception/UnauthorizedScheduleAccessException.java diff --git a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java index f7d789f..e1cb61e 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java @@ -1,17 +1,45 @@ package com.cm.clientservice.controller; + +/** + * Spec: + * + * Coaches should be able to create a new Agreement Template for them to use + * + * + * + * Coaches should be able to propose a CoachClientAgreement to a user. + * - Require both parties to sign before continuing + * - Dependency on the BillingService to take billing info and schedule payments + * + * Coaches should be able to cancel a CoachClientAgreement + * - Notify the client of the cancelation + * + * Coaches should be able to propose edits to a CoachClientAgreement while running + * - Require both party signing to continue. + * + * Coaches should be able to + * + * + * + */ + import com.cm.clientservice.dto.UserResponseDTO; +import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.service.UserService; -import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; +import java.util.UUID; @RestController -@RequestMapping("/clients") +@RequestMapping("/client") +@Tag(name="client", description = "API for clients to manage their experience.") public class ClientController { private final UserService userService; @@ -21,9 +49,14 @@ public ClientController(UserService userService){ } @GetMapping("/coaches") - @Operation(summary = "Get all users") - public ResponseEntity> getAllCoachUsers(){ - List users = userService.getAllCoachUsers(); - return ResponseEntity.ok().body(users); + public ResponseEntity> getClientsCoaches(@RequestHeader("X-AUTH-ID") String authId){ + List coaches = userService.getCoachesOfClient(UUID.fromString(authId)); + return ResponseEntity.ok().body(coaches); + } + + @GetMapping("/schedule") + public ResponseEntity getTrainingSchedule(@RequestHeader("X-AUTH-ID") String authId){ + TrainingScheduleDto trainingScheduleDto = userService.getTrainingSchedule(UUID.fromString(authId)); + return ResponseEntity.ok().body(trainingScheduleDto); } } diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index 02b2068..711bf11 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -1,2 +1,84 @@ -package com.cm.clientservice.controller;public class CoachController { +package com.cm.clientservice.controller; + +import com.cm.clientservice.dto.UserRequestDTO; +import com.cm.clientservice.dto.UserResponseDTO; +import com.cm.clientservice.dto.contract.AgreementTemplateDto; +import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; +import com.cm.clientservice.model.contract.AgreementTemplate; +import com.cm.clientservice.model.contract.CoachClientAgreement; +import com.cm.clientservice.service.UserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.UUID; + +@RestController("/coaching") +@Tag(name = "coaching", description = "API for coaching management.") +public class CoachingController { + + private final UserService userService; + + public CoachingController(UserService userService){ + this.userService = userService; + } + + @GetMapping("/clients") + @Operation(summary= "") + public ResponseEntity> getClients(@RequestHeader("X-AUTH-ID") String authId){ + + List clients = userService.getClientsOfCoach(UUID.fromString(authId)); + return ResponseEntity.ok().body(clients); + } + + @GetMapping("/client-schedule/{clientId}") + @Operation(summary = "Get the clients training schedule for the coach to view. ") + public ResponseEntity getClientSchedule(@RequestHeader("X-AUTH-ID") String authId, + @PathVariable String clientId){ + + TrainingScheduleDto trainingScheduleDto = + userService.getClientSchedule(UUID.fromString(clientId), UUID.fromString(authId)); + + return ResponseEntity.ok().body(trainingScheduleDto); + } + + //TODO: this + public ResponseEntity addClient(@RequestHeader("X-AUTH-ID") String authId, + @RequestBody UserRequestDTO userRequestDTO, + @RequestBody CoachClientAgreement coachClientAgreement){ + return null; + } + + //TODO: this + public ResponseEntity removeClient(@RequestHeader() String authId, + @RequestBody UserRequestDTO userRequestDTO, + @RequestBody CoachClientAgreement coachClientAgreement){ + // Alert the user they have been dropped. + // Alert billing service that the contract is being terminated. + return null; + } + + + // These should probably go in their own controller. + //TODO: This should be accessed only by accounts that have a coaching profile. + public ResponseEntity createAgreementTemplate(){ + return null; + } + + // TODO: This should be accessed only by accounts that have a coaching profile + public ResponseEntity deleteAgreementTemplate(){ + return null; + } + + // TODO: This should be accessed only by accounts that have a coach prifkle. + public ResponseEntity updateAgreementTemplate(){ + return null; + } + + // TODO: This should be accessed only by accounts that have a coach profile. + public ResponseEntity> getCoachAgreementTemplates(){ + return null; + } } diff --git a/client-service/src/main/java/com/cm/clientservice/controller/UserController.java b/client-service/src/main/java/com/cm/clientservice/controller/UserController.java index 60fb3d2..9584289 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/UserController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/UserController.java @@ -1,5 +1,4 @@ package com.cm.clientservice.controller; - import com.cm.clientservice.dto.validators.CreateUserValidationGroup; import com.cm.clientservice.service.UserService; import jakarta.validation.groups.Default; @@ -17,8 +16,8 @@ import java.util.UUID; @RestController -@RequestMapping("/clients") -@Tag(name="Clients", description = "API for managing Clients") +@RequestMapping("/users") +@Tag(name="Users", description = "API for managing Users") public class UserController { private final Logger log = LoggerFactory.getLogger(UserController.class); @@ -28,6 +27,7 @@ public UserController(UserService userService){ this.userService = userService; } + @PostMapping @Operation(summary = "Create a user.") public ResponseEntity createUser( @@ -35,7 +35,6 @@ public ResponseEntity createUser( @RequestBody UserRequestDTO userRequestDTO, @RequestHeader("X-AUTH-ID") String auth_id ){ - log.debug("AUTH ID IS {}", auth_id); UserResponseDTO userResponseDTO = userService.createUser(userRequestDTO, auth_id); return ResponseEntity.ok().body(userResponseDTO); } @@ -48,6 +47,7 @@ public ResponseEntity> getAllUsers(){ return ResponseEntity.ok().body(users); } + @PutMapping("/") @Operation(summary = "Update a user") public ResponseEntity updateUser(@RequestHeader("X-AUTH-ID") String id, @@ -64,19 +64,10 @@ public ResponseEntity updateUser(@RequestHeader("X-AUTH-ID") St } - @GetMapping("/user-clients/{id}") - @Operation(summary = "Get all the clients of a user.") - public ResponseEntity> getAllUsersClients(@PathVariable UUID id){ - //TODO: Implement me and replace tis - return ResponseEntity.ok().body(List.of(new UserResponseDTO())); - } - - @DeleteMapping("/{id}") @Operation(summary = "Delete a user.") public ResponseEntity deleteUser(@PathVariable UUID id){ userService.deleteUser(id); return ResponseEntity.noContent().build(); } - } diff --git a/client-service/src/main/java/com/cm/clientservice/exception/TrainingScheduleNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/TrainingScheduleNotFoundException.java new file mode 100644 index 0000000..1e416a1 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/exception/TrainingScheduleNotFoundException.java @@ -0,0 +1,7 @@ +package com.cm.clientservice.exception; + +public class TrainingScheduleNotFoundException extends RuntimeException{ + public TrainingScheduleNotFoundException(String message){ + super(message); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/exception/UnauthorizedScheduleAccessException.java b/client-service/src/main/java/com/cm/clientservice/exception/UnauthorizedScheduleAccessException.java new file mode 100644 index 0000000..fe62e61 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/exception/UnauthorizedScheduleAccessException.java @@ -0,0 +1,7 @@ +package com.cm.clientservice.exception; + +public class UnauthorizedScheduleAccessException extends RuntimeException{ + public UnauthorizedScheduleAccessException(String message){ + super(message); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java b/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java index e85f724..a8d1c80 100644 --- a/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java +++ b/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java @@ -1,2 +1,12 @@ -package com.cm.clientservice.repository;public interface CoachClientAgreementRepository { +package com.cm.clientservice.repository; + +import com.cm.clientservice.model.contract.CoachClientAgreement; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.UUID; + +public interface CoachClientAgreementRepository extends JpaRepository { + List findAllByCoach_Id(UUID id); + boolean existsCoachClientAgreementByClient_IdAndCoach_Id(UUID client_id, UUID coach_id); } diff --git a/client-service/src/main/java/com/cm/clientservice/repository/UserRepository.java b/client-service/src/main/java/com/cm/clientservice/repository/UserRepository.java index 8bdc12b..a69b758 100644 --- a/client-service/src/main/java/com/cm/clientservice/repository/UserRepository.java +++ b/client-service/src/main/java/com/cm/clientservice/repository/UserRepository.java @@ -1,8 +1,6 @@ package com.cm.clientservice.repository; import com.cm.clientservice.model.User; import org.springframework.data.jpa.repository.JpaRepository; - -import java.util.List; import java.util.Optional; import java.util.UUID; @@ -12,7 +10,5 @@ public interface UserRepository extends JpaRepository { boolean existsByEmailAndIdNot(String email, UUID id); - List findByCoachProfileIsNotNull(); - Optional findByAuthId(UUID authId); } diff --git a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java index 5f83dc7..6a344c4 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java @@ -1,2 +1,28 @@ -package com.cm.clientservice.service;public class CoachClientAgreementService { +package com.cm.clientservice.service; +import com.cm.clientservice.model.contract.CoachClientAgreement; +import com.cm.clientservice.repository.CoachClientAgreementRepository; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +@Service +public class CoachClientAgreementService { + + private final CoachClientAgreementRepository coachClientAgreementRepository; + + public CoachClientAgreementService(CoachClientAgreementRepository coachClientAgreementRepository){ + this.coachClientAgreementRepository = coachClientAgreementRepository; + } + + public List getCoachClientAgreements(UUID coachId){ + + return coachClientAgreementRepository.findAllByCoach_Id(coachId); + } + + public boolean isUserAClientOfCoach(UUID userId, UUID coachId){ + return coachClientAgreementRepository + .existsCoachClientAgreementByClient_IdAndCoach_Id(userId, coachId); + } + } diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index d9ee028..91718ec 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -3,9 +3,13 @@ import com.cm.clientservice.dto.OutgoingEmailUpdateDTO; import com.cm.clientservice.dto.UserRequestDTO; import com.cm.clientservice.dto.UserResponseDTO; +import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.exception.EmailAlreadyExistsException; +import com.cm.clientservice.exception.UnauthorizedScheduleAccessException; import com.cm.clientservice.exception.UserNotFoundException; +import com.cm.clientservice.mapper.TrainingScheduleMapper; import com.cm.clientservice.mapper.UserMapper; +import com.cm.clientservice.model.schedule.TrainingSchedule; import com.cm.clientservice.repository.UserRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; @@ -21,14 +25,20 @@ public class UserService { private final UserRepository userRepository; + private final CoachClientAgreementService coachClientAgreementService; + private final TrainingScheduleService trainingScheduleService; private final WebClient webClient; public UserService(UserRepository userRepository, WebClient.Builder webClientBuilder, - @Value("${auth.service.url}") String authServiceUrl){ + @Value("${auth.service.url}") String authServiceUrl, + CoachClientAgreementService coachClientAgreementService, + TrainingScheduleService trainingScheduleService){ this.userRepository = userRepository; this.webClient = webClientBuilder.baseUrl(authServiceUrl).build(); + this.coachClientAgreementService = coachClientAgreementService; + this.trainingScheduleService = trainingScheduleService; } @@ -58,13 +68,6 @@ public List getAllUsers(){ .toList(); } - public List getAllCoachUsers(){ - List users = userRepository.findByCoachProfileIsNotNull(); - - return users.stream() - .map(UserMapper::toDTO) - .toList(); - } public UserResponseDTO updateUser(UUID authId, UserRequestDTO userRequestDTO, String token){ // Find the user that has the authId @@ -88,8 +91,7 @@ public UserResponseDTO updateUser(UUID authId, UserRequestDTO userRequestDTO, St outgoingEmailUpdateDTO.setOldEmail(user.getEmail()); outgoingEmailUpdateDTO.setNewEmail(userRequestDTO.getEmail()); - // Make a request to the auth service to update the email of the user with this email. - // Now check if the token they supplied was valid using our endpoint of auth service. + // Let auth service update their email for signing in. webClient.put() .uri("/auth/update-email") .header(HttpHeaders.AUTHORIZATION, token) @@ -109,5 +111,54 @@ public UserResponseDTO updateUser(UUID authId, UserRequestDTO userRequestDTO, St return UserMapper.toDTO(updatedUser); } + public List getClientsOfCoach(UUID coachAuthId){ + UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( + () -> new UserNotFoundException("Coach was not found with authId: " + coachAuthId)).getId(); + return coachClientAgreementService + .getCoachClientAgreements(coachId) + .stream() + .map(a -> UserMapper.toDTO(a.getClient())) + .distinct() + .toList(); + } + + public List getCoachesOfClient(UUID clientAuthId) { + UUID clientId = userRepository.findByAuthId(clientAuthId).orElseThrow( + () -> new UserNotFoundException("Client was not found with authId: " + clientAuthId)).getId(); + + return coachClientAgreementService + .getCoachClientAgreements(clientId) + .stream() + .map(a -> UserMapper.toDTO(a.getCoach())) + .distinct() + .toList(); + } + + // TODO: Fix this, right now it is using the authId of the coach. + public TrainingScheduleDto getClientSchedule(UUID clientId, UUID coachAuthId){ + UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( + () -> new UserNotFoundException("Coach was not found with authId: " + coachAuthId)) + .getId(); + + if (!coachClientAgreementService.isUserAClientOfCoach(clientId, coachId)) { + throw new UnauthorizedScheduleAccessException("The user with id: " + coachId + " is not a coach of user with id: " + clientId); + } + + TrainingSchedule schedule = userRepository.findById(clientId).orElseThrow( + () -> new UserNotFoundException("Client was not found with ID: " + clientId)).getTrainingSchedule(); + + return TrainingScheduleMapper.toDto(schedule); + } + + public TrainingScheduleDto getTrainingSchedule(UUID authId){ + + TrainingSchedule schedule = + userRepository.findByAuthId(authId) + .orElseThrow( + () -> new UserNotFoundException("User not found with authID: " + authId)) + .getTrainingSchedule(); + + return TrainingScheduleMapper.toDto(schedule); + } } From 09e789babc5d62ec6a051fba1971e43b4b4edae2 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Mon, 1 Dec 2025 18:51:09 -0800 Subject: [PATCH 04/12] remove workout from training schedule --- .../controller/ClientController.java | 15 +++++++++---- .../controller/CoachingController.java | 14 +++++++----- .../model/schedule/TrainingSchedule.java | 8 +++---- .../clientservice/model/schedule/Workout.java | 7 +++++- .../TrainingScheduleRepository.java | 9 ++++++++ .../service/TrainingScheduleService.java | 22 +++++++++++++++++++ .../cm/clientservice/service/UserService.java | 21 +++++++++++++++++- 7 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 client-service/src/main/java/com/cm/clientservice/repository/TrainingScheduleRepository.java create mode 100644 client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java diff --git a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java index e1cb61e..136321b 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java @@ -29,10 +29,7 @@ import com.cm.clientservice.service.UserService; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.UUID; @@ -59,4 +56,14 @@ public ResponseEntity getTrainingSchedule(@RequestHeader("X TrainingScheduleDto trainingScheduleDto = userService.getTrainingSchedule(UUID.fromString(authId)); return ResponseEntity.ok().body(trainingScheduleDto); } + + @DeleteMapping("/schedule/workout/{id}") + public ResponseEntity deleteWorkoutFromSchedule(@RequestHeader("X-AUTH-ID") String authId, + @PathVariable String id){ + + TrainingScheduleDto trainingScheduleDto = + userService.removeWorkoutFromSchedule(UUID.fromString(authId), UUID.fromString(id)); + + return ResponseEntity.ok().body(trainingScheduleDto); + } } diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index 711bf11..43e943f 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -44,15 +44,19 @@ public ResponseEntity getClientSchedule(@RequestHeader("X-A return ResponseEntity.ok().body(trainingScheduleDto); } - //TODO: this - public ResponseEntity addClient(@RequestHeader("X-AUTH-ID") String authId, - @RequestBody UserRequestDTO userRequestDTO, + @PostMapping("/propose-agreement/{clientId}") + public ResponseEntity proposeClientAgreement(@RequestHeader("X-AUTH-ID") String authId, + @PathVariable String clientId, @RequestBody CoachClientAgreement coachClientAgreement){ + + // This endpoint will allow for a coach to propose a client agreement to a user. + + return null; } - //TODO: this - public ResponseEntity removeClient(@RequestHeader() String authId, + @PostMapping("/break-agreement") + public ResponseEntity breakClientAgreement(@RequestHeader("X-AUTH-ID") String authId, @RequestBody UserRequestDTO userRequestDTO, @RequestBody CoachClientAgreement coachClientAgreement){ // Alert the user they have been dropped. diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java index d34a160..2cd7367 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java @@ -3,6 +3,7 @@ import lombok.Getter; import lombok.Setter; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -15,9 +16,6 @@ public class TrainingSchedule { @GeneratedValue private UUID id; - @ManyToMany - @JoinTable(name = "trainingschedule_workout", - joinColumns = @JoinColumn(name = "trainingschedule_id"), - inverseJoinColumns = @JoinColumn(name = "workout_id")) - private List workouts; + @OneToMany(mappedBy = "parentSchedule", cascade = CascadeType.ALL, orphanRemoval = true) + private List workouts = new ArrayList<>(); } diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java index 210dc68..2fa6371 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java @@ -6,6 +6,7 @@ import lombok.Setter; import java.time.LocalDate; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -23,7 +24,7 @@ public class Workout { joinColumns = @JoinColumn(name = "workout_id"), inverseJoinColumns = @JoinColumn(name = "exercise_id") ) - private List exercises; + private List exercises = new ArrayList<>(); @NotNull private LocalDate date; @@ -33,4 +34,8 @@ public class Workout { @NotNull private Boolean isCompleted; + + @ManyToOne + @JoinColumn(name = "training_schedule_id") + private TrainingSchedule parentSchedule; } diff --git a/client-service/src/main/java/com/cm/clientservice/repository/TrainingScheduleRepository.java b/client-service/src/main/java/com/cm/clientservice/repository/TrainingScheduleRepository.java new file mode 100644 index 0000000..2e94ef7 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/repository/TrainingScheduleRepository.java @@ -0,0 +1,9 @@ +package com.cm.clientservice.repository; + +import com.cm.clientservice.model.schedule.TrainingSchedule; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.UUID; + +public interface TrainingScheduleRepository extends JpaRepository { +} diff --git a/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java new file mode 100644 index 0000000..b02a4e1 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java @@ -0,0 +1,22 @@ +package com.cm.clientservice.service; + +import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; +import com.cm.clientservice.mapper.TrainingScheduleMapper; +import com.cm.clientservice.model.schedule.TrainingSchedule; +import com.cm.clientservice.repository.TrainingScheduleRepository; +import org.springframework.stereotype.Service; + +@Service +public class TrainingScheduleService { + + private final TrainingScheduleRepository trainingScheduleRepository; + + public TrainingScheduleService(TrainingScheduleRepository trainingScheduleRepository){ + this.trainingScheduleRepository = trainingScheduleRepository; + } + + public TrainingScheduleDto saveSchedule(TrainingSchedule trainingSchedule){ + TrainingSchedule newSchedule = trainingScheduleRepository.save(trainingSchedule); + return TrainingScheduleMapper.toDto(newSchedule); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index 91718ec..b8a02cd 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -10,6 +10,7 @@ import com.cm.clientservice.mapper.TrainingScheduleMapper; import com.cm.clientservice.mapper.UserMapper; import com.cm.clientservice.model.schedule.TrainingSchedule; +import com.cm.clientservice.model.schedule.Workout; import com.cm.clientservice.repository.UserRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; @@ -20,6 +21,7 @@ import java.time.LocalDate; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; @Service public class UserService { @@ -135,7 +137,6 @@ public List getCoachesOfClient(UUID clientAuthId) { .toList(); } - // TODO: Fix this, right now it is using the authId of the coach. public TrainingScheduleDto getClientSchedule(UUID clientId, UUID coachAuthId){ UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( () -> new UserNotFoundException("Coach was not found with authId: " + coachAuthId)) @@ -161,4 +162,22 @@ public TrainingScheduleDto getTrainingSchedule(UUID authId){ return TrainingScheduleMapper.toDto(schedule); } + + public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID workoutId) { + // Get the user. + TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( + () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) + .getTrainingSchedule(); + + // Get their schedule and filter out the workout mentioned. + List workouts = trainingSchedule + .getWorkouts() + .stream() + .filter(s -> !(s.getId().equals( workoutId))) + .collect(Collectors.toList()); + + trainingSchedule.setWorkouts(workouts); + + return trainingScheduleService.saveSchedule(trainingSchedule); + } } From 3ac69a2477c4e54cc96df3050dea6066abd740b1 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Mon, 1 Dec 2025 23:00:43 -0800 Subject: [PATCH 05/12] a client can add a workout to their TrainingSchedule --- .../controller/ClientController.java | 10 +++++ .../dto/scheduling/ExerciseDto.java | 15 ------- .../dto/scheduling/TrainingScheduleDto.java | 3 +- .../dto/scheduling/WorkoutDto.java | 19 -------- .../exercise/ExerciseRequestDto.java | 13 ++++++ .../exercise/ExerciseResponseDto.java | 15 +++++++ .../movement/MovementCreateRequestDto.java | 6 +++ .../MovementResponseDto.java} | 4 +- .../movement/MovementReuseRequestDto.java | 10 +++++ .../scheduling/workout/WorkoutRequestDto.java | 25 +++++++++++ .../workout/WorkoutResponseDto.java | 17 +++++++ .../clientservice/mapper/ExerciseMapper.java | 25 ----------- .../clientservice/mapper/MovementMapper.java | 14 ------ .../clientservice/mapper/WorkoutMapper.java | 27 ----------- .../mapper/schedule/ExerciseMapper.java | 42 +++++++++++++++++ .../mapper/schedule/MovementMapper.java | 25 +++++++++++ .../TrainingScheduleMapper.java | 2 +- .../mapper/schedule/WorkoutMapper.java | 45 +++++++++++++++++++ .../model/schedule/Exercise.java | 4 ++ .../model/schedule/Movement.java | 5 +-- .../model/schedule/TrainingSchedule.java | 2 +- .../clientservice/model/schedule/Workout.java | 9 +--- .../service/TrainingScheduleService.java | 2 +- .../cm/clientservice/service/UserService.java | 17 ++++++- 24 files changed, 237 insertions(+), 119 deletions(-) delete mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java delete mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseResponseDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java rename client-service/src/main/java/com/cm/clientservice/dto/scheduling/{MovementDto.java => movement/MovementResponseDto.java} (62%) create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementReuseRequestDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutRequestDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutResponseDto.java delete mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java delete mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java delete mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/schedule/ExerciseMapper.java create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java rename client-service/src/main/java/com/cm/clientservice/mapper/{ => schedule}/TrainingScheduleMapper.java (91%) create mode 100644 client-service/src/main/java/com/cm/clientservice/mapper/schedule/WorkoutMapper.java diff --git a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java index 136321b..ae0986c 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java @@ -26,6 +26,7 @@ import com.cm.clientservice.dto.UserResponseDTO; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; +import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; import com.cm.clientservice.service.UserService; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.http.ResponseEntity; @@ -66,4 +67,13 @@ public ResponseEntity deleteWorkoutFromSchedule(@RequestHea return ResponseEntity.ok().body(trainingScheduleDto); } + + @PostMapping("/schedule/workout") + public ResponseEntity addWorkoutToSchedule(@RequestHeader("X-AUTH-ID") String authId, + @RequestBody WorkoutRequestDto workoutDto){ + TrainingScheduleDto trainingScheduleDto = + userService.addWorkoutToSchedule(UUID.fromString(authId), workoutDto); + + return ResponseEntity.ok().body(trainingScheduleDto); + } } diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java deleted file mode 100644 index 96e0faa..0000000 --- a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/ExerciseDto.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.cm.clientservice.dto.scheduling; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class ExerciseDto { - - private String id; - private MovementDto movement; - private String numSets; - private String numReps; - private String coachNotes; -} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java index 57a05a9..4fc1b33 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java @@ -1,5 +1,6 @@ package com.cm.clientservice.dto.scheduling; +import com.cm.clientservice.dto.scheduling.workout.WorkoutResponseDto; import lombok.Getter; import lombok.Setter; @@ -10,5 +11,5 @@ public class TrainingScheduleDto { private String id; - private List workouts; + private List workouts; } diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java deleted file mode 100644 index ece886f..0000000 --- a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/WorkoutDto.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.cm.clientservice.dto.scheduling; - -import lombok.Getter; -import lombok.Setter; - -import java.util.List; - -@Getter -@Setter -public class WorkoutDto { - - private String id; - - private List exercises; - - private String date; - private String workoutNotes; - private String isCompleted; -} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java new file mode 100644 index 0000000..9277b7f --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java @@ -0,0 +1,13 @@ +package com.cm.clientservice.dto.scheduling.exercise; +import com.cm.clientservice.dto.scheduling.movement.MovementReuseRequestDto; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ExerciseRequestDto { + private MovementReuseRequestDto movement; + private String numSets; + private String numReps; + private String coachNotes; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseResponseDto.java new file mode 100644 index 0000000..d2c6aa8 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseResponseDto.java @@ -0,0 +1,15 @@ +package com.cm.clientservice.dto.scheduling.exercise; + +import com.cm.clientservice.dto.scheduling.movement.MovementResponseDto; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ExerciseResponseDto { + private String id; + private MovementResponseDto movement; + private String numSets; + private String numReps; + private String coachNotes; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java new file mode 100644 index 0000000..d5e7a07 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java @@ -0,0 +1,6 @@ +package com.cm.clientservice.dto.scheduling.movement; + +public class MovementCreateRequestDto { + private String name; + private String description; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/MovementDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementResponseDto.java similarity index 62% rename from client-service/src/main/java/com/cm/clientservice/dto/scheduling/MovementDto.java rename to client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementResponseDto.java index 03feab9..63cfb6f 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/MovementDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementResponseDto.java @@ -1,11 +1,11 @@ -package com.cm.clientservice.dto.scheduling; +package com.cm.clientservice.dto.scheduling.movement; import lombok.Getter; import lombok.Setter; @Getter @Setter -public class MovementDto { +public class MovementResponseDto { private String id; private String name; private String description; diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementReuseRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementReuseRequestDto.java new file mode 100644 index 0000000..55fa688 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementReuseRequestDto.java @@ -0,0 +1,10 @@ +package com.cm.clientservice.dto.scheduling.movement; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public final class MovementReuseRequestDto{ + private String id; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutRequestDto.java new file mode 100644 index 0000000..f758888 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutRequestDto.java @@ -0,0 +1,25 @@ +package com.cm.clientservice.dto.scheduling.workout; +import com.cm.clientservice.dto.scheduling.exercise.ExerciseRequestDto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import java.util.List; + +@Getter +@Setter +public class WorkoutRequestDto { + @NotNull(message = "Exercises should not be null.") + private List exercises; + + private String date; + + @NotNull(message = "Workout notes should not be null.") + private String workoutNotes; + + @NotBlank(message = "Completion flag should not be blank.") + private String isCompleted; + + @NotNull + private String trainingScheduleId; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutResponseDto.java new file mode 100644 index 0000000..b271d25 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/workout/WorkoutResponseDto.java @@ -0,0 +1,17 @@ +package com.cm.clientservice.dto.scheduling.workout; + +import com.cm.clientservice.dto.scheduling.exercise.ExerciseResponseDto; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +public class WorkoutResponseDto { + private String id; + private List exercises; + private String date; + private String workoutNotes; + private String isCompleted; +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java deleted file mode 100644 index ae38491..0000000 --- a/client-service/src/main/java/com/cm/clientservice/mapper/ExerciseMapper.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.cm.clientservice.mapper; - -import com.cm.clientservice.dto.scheduling.ExerciseDto; -import com.cm.clientservice.model.schedule.Exercise; - -import java.util.List; - -public class ExerciseMapper { - public static List toDto(List exercises) { - return exercises.stream() - .map(ExerciseMapper::toDto) - .toList(); - } - - public static ExerciseDto toDto(Exercise exercise){ - ExerciseDto dto = new ExerciseDto(); - - dto.setId(exercise.getId().toString()); - dto.setMovement(MovementMapper.toDto(exercise.getMovement())); - dto.setCoachNotes(exercise.getCoachNotes()); - dto.setNumReps(String.valueOf(exercise.getNumReps())); - dto.setNumSets(String.valueOf(exercise.getNumSets())); - return dto; - } -} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java deleted file mode 100644 index 9cdc257..0000000 --- a/client-service/src/main/java/com/cm/clientservice/mapper/MovementMapper.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.cm.clientservice.mapper; -import com.cm.clientservice.dto.scheduling.MovementDto; -import com.cm.clientservice.model.schedule.Movement; - -public class MovementMapper { - - public static MovementDto toDto(Movement movement){ - MovementDto dto = new MovementDto(); - dto.setId(movement.getId().toString()); - dto.setName(movement.getName()); - dto.setDescription(movement.getDescription()); - return dto; - } -} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java deleted file mode 100644 index 2497508..0000000 --- a/client-service/src/main/java/com/cm/clientservice/mapper/WorkoutMapper.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.cm.clientservice.mapper; - -import com.cm.clientservice.dto.scheduling.WorkoutDto; -import com.cm.clientservice.model.schedule.Workout; - -import java.util.List; -public class WorkoutMapper { - - public static List toDto(List workouts){ - return workouts - .stream() - .map(WorkoutMapper::toDto) - .toList(); - } - - public static WorkoutDto toDto(Workout workout){ - WorkoutDto dto = new WorkoutDto(); - - dto.setId(String.valueOf(workout.getId())); - dto.setDate(workout.getDate().toString()); - dto.setWorkoutNotes(workout.getWorkoutNotes()); - dto.setIsCompleted(workout.getIsCompleted().toString()); - dto.setExercises(ExerciseMapper.toDto(workout.getExercises())); - - return dto; - } -} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/schedule/ExerciseMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/ExerciseMapper.java new file mode 100644 index 0000000..663f7e7 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/ExerciseMapper.java @@ -0,0 +1,42 @@ +package com.cm.clientservice.mapper.schedule; +import com.cm.clientservice.dto.scheduling.exercise.ExerciseRequestDto; +import com.cm.clientservice.dto.scheduling.exercise.ExerciseResponseDto; +import com.cm.clientservice.model.schedule.Exercise; + +import java.util.List; + +public class ExerciseMapper { + public static List toDto(List exercises) { + return exercises.stream() + .map(ExerciseMapper::toDto) + .toList(); + } + + public static ExerciseResponseDto toDto(Exercise exercise){ + ExerciseResponseDto dto = new ExerciseResponseDto(); + + dto.setId(exercise.getId().toString()); + dto.setMovement(MovementMapper.toDto(exercise.getMovement())); + dto.setCoachNotes(exercise.getCoachNotes()); + dto.setNumReps(String.valueOf(exercise.getNumReps())); + dto.setNumSets(String.valueOf(exercise.getNumSets())); + return dto; + } + + public static List toModel(List exerciseDtos) { + return exerciseDtos.stream() + .map(ExerciseMapper::toModel) + .toList(); + } + + public static Exercise toModel(ExerciseRequestDto exerciseDto){ + Exercise exercise = new Exercise(); + + exercise.setCoachNotes(exerciseDto.getCoachNotes()); + exercise.setMovement(MovementMapper.toModel(exerciseDto.getMovement())); + exercise.setNumSets(Integer.parseInt(exerciseDto.getNumSets())); + exercise.setNumReps(Integer.parseInt(exerciseDto.getNumReps())); + + return exercise; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java new file mode 100644 index 0000000..08c7576 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java @@ -0,0 +1,25 @@ +package com.cm.clientservice.mapper.schedule; +import com.cm.clientservice.dto.scheduling.movement.MovementResponseDto; +import com.cm.clientservice.dto.scheduling.movement.MovementReuseRequestDto; +import com.cm.clientservice.model.schedule.Movement; + +import java.util.UUID; + +public class MovementMapper { + + public static MovementResponseDto toDto(Movement movement){ + MovementResponseDto dto = new MovementResponseDto(); + dto.setId(movement.getId().toString()); + dto.setName(movement.getName()); + dto.setDescription(movement.getDescription()); + return dto; + } + + public static Movement toModel(MovementReuseRequestDto movementDto) { + Movement movement = new Movement(); + + movement.setId(UUID.fromString(movementDto.getId())); + + return movement; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/TrainingScheduleMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/TrainingScheduleMapper.java similarity index 91% rename from client-service/src/main/java/com/cm/clientservice/mapper/TrainingScheduleMapper.java rename to client-service/src/main/java/com/cm/clientservice/mapper/schedule/TrainingScheduleMapper.java index 8af60fb..ac2b3f4 100644 --- a/client-service/src/main/java/com/cm/clientservice/mapper/TrainingScheduleMapper.java +++ b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/TrainingScheduleMapper.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.mapper; +package com.cm.clientservice.mapper.schedule; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.model.schedule.TrainingSchedule; diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/schedule/WorkoutMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/WorkoutMapper.java new file mode 100644 index 0000000..6420207 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/WorkoutMapper.java @@ -0,0 +1,45 @@ +package com.cm.clientservice.mapper.schedule; + +import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; +import com.cm.clientservice.dto.scheduling.workout.WorkoutResponseDto; +import com.cm.clientservice.model.schedule.Exercise; +import com.cm.clientservice.model.schedule.Workout; + +import java.time.LocalDate; +import java.util.List; + +public class WorkoutMapper { + + public static List toDto(List workouts){ + return workouts + .stream() + .map(WorkoutMapper::toDto) + .toList(); + } + + public static WorkoutResponseDto toDto(Workout workout){ + WorkoutResponseDto dto = new WorkoutResponseDto(); + + dto.setId(String.valueOf(workout.getId())); + dto.setDate(workout.getDate().toString()); + dto.setWorkoutNotes(workout.getWorkoutNotes()); + dto.setIsCompleted(workout.getIsCompleted().toString()); + dto.setExercises(ExerciseMapper.toDto(workout.getExercises())); + + return dto; + } + + public static Workout toModel(WorkoutRequestDto workoutRequestDto){ + Workout workout = new Workout(); + + workout.setIsCompleted(Boolean.valueOf(workoutRequestDto.getIsCompleted())); + workout.setDate(LocalDate.parse(workoutRequestDto.getDate())); + workout.setWorkoutNotes(workoutRequestDto.getWorkoutNotes()); + + List exercises = ExerciseMapper.toModel(workoutRequestDto.getExercises()); + for (Exercise e : exercises) e.setWorkout(workout); + workout.setExercises(exercises); + + return workout; + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/Exercise.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/Exercise.java index 4fe8f97..ab5e13c 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/Exercise.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/Exercise.java @@ -27,4 +27,8 @@ public class Exercise { @NotNull private String coachNotes; + + @ManyToOne + @JoinColumn(name = "workout_id") + private Workout workout; } diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/Movement.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/Movement.java index 3df1d65..b4a2fd9 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/Movement.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/Movement.java @@ -1,8 +1,5 @@ package com.cm.clientservice.model.schedule; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; +import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Getter; diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java index 2cd7367..72c9e30 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java @@ -16,6 +16,6 @@ public class TrainingSchedule { @GeneratedValue private UUID id; - @OneToMany(mappedBy = "parentSchedule", cascade = CascadeType.ALL, orphanRemoval = true) + @OneToMany(mappedBy = "trainingSchedule", cascade = CascadeType.ALL, orphanRemoval = true) private List workouts = new ArrayList<>(); } diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java index 2fa6371..96aafb7 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java @@ -18,12 +18,7 @@ public class Workout { @GeneratedValue private UUID id; - @ManyToMany - @JoinTable( - name = "workout_exercise", - joinColumns = @JoinColumn(name = "workout_id"), - inverseJoinColumns = @JoinColumn(name = "exercise_id") - ) + @OneToMany(mappedBy = "workout", cascade = CascadeType.ALL, orphanRemoval = true) private List exercises = new ArrayList<>(); @NotNull @@ -37,5 +32,5 @@ public class Workout { @ManyToOne @JoinColumn(name = "training_schedule_id") - private TrainingSchedule parentSchedule; + private TrainingSchedule trainingSchedule; } diff --git a/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java index b02a4e1..44555bb 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java @@ -1,7 +1,7 @@ package com.cm.clientservice.service; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; -import com.cm.clientservice.mapper.TrainingScheduleMapper; +import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; import com.cm.clientservice.model.schedule.TrainingSchedule; import com.cm.clientservice.repository.TrainingScheduleRepository; import org.springframework.stereotype.Service; diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index b8a02cd..aa5e020 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -4,11 +4,13 @@ import com.cm.clientservice.dto.UserRequestDTO; import com.cm.clientservice.dto.UserResponseDTO; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; +import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; import com.cm.clientservice.exception.EmailAlreadyExistsException; import com.cm.clientservice.exception.UnauthorizedScheduleAccessException; import com.cm.clientservice.exception.UserNotFoundException; -import com.cm.clientservice.mapper.TrainingScheduleMapper; +import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; import com.cm.clientservice.mapper.UserMapper; +import com.cm.clientservice.mapper.schedule.WorkoutMapper; import com.cm.clientservice.model.schedule.TrainingSchedule; import com.cm.clientservice.model.schedule.Workout; import com.cm.clientservice.repository.UserRepository; @@ -164,7 +166,6 @@ public TrainingScheduleDto getTrainingSchedule(UUID authId){ } public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID workoutId) { - // Get the user. TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) .getTrainingSchedule(); @@ -180,4 +181,16 @@ public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID wor return trainingScheduleService.saveSchedule(trainingSchedule); } + + public TrainingScheduleDto addWorkoutToSchedule(UUID clientAuthId, WorkoutRequestDto workoutDto) { + TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( + () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) + .getTrainingSchedule(); + + Workout workout = WorkoutMapper.toModel(workoutDto); + workout.setTrainingSchedule(trainingSchedule); + trainingSchedule.getWorkouts().add(workout); + + return trainingScheduleService.saveSchedule(trainingSchedule); + } } From 0224e33a115b82501466abdda2d7f0192e54bc12 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Mon, 1 Dec 2025 23:22:42 -0800 Subject: [PATCH 06/12] Coach should be able to add to clients training schedule --- .../controller/CoachingController.java | 22 +++++++++++++++++++ .../cm/clientservice/service/UserService.java | 18 +++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index 43e943f..d21d031 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -4,6 +4,7 @@ import com.cm.clientservice.dto.UserResponseDTO; import com.cm.clientservice.dto.contract.AgreementTemplateDto; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; +import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; import com.cm.clientservice.model.contract.AgreementTemplate; import com.cm.clientservice.model.contract.CoachClientAgreement; import com.cm.clientservice.service.UserService; @@ -44,6 +45,27 @@ public ResponseEntity getClientSchedule(@RequestHeader("X-A return ResponseEntity.ok().body(trainingScheduleDto); } + @DeleteMapping("/client-schedule/workout/{id}") + public ResponseEntity deleteWorkoutFromSchedule(@RequestHeader("X-AUTH-ID") String authId, + @PathVariable String id){ + + TrainingScheduleDto trainingScheduleDto = + userService.removeWorkoutFromSchedule(UUID.fromString(authId), UUID.fromString(id)); + + return ResponseEntity.ok().body(trainingScheduleDto); + } + + @PostMapping("/client-schedule/{clientId}/workout") + public ResponseEntity addWorkoutToSchedule(@RequestHeader("X-AUTH-ID") String authId, + @PathVariable String clientId, + @RequestBody WorkoutRequestDto workoutDto){ + TrainingScheduleDto trainingScheduleDto = + userService.addWorkoutToClientsSchedule(UUID.fromString(authId), UUID.fromString(clientId), workoutDto); + + return ResponseEntity.ok().body(trainingScheduleDto); + } + + @PostMapping("/propose-agreement/{clientId}") public ResponseEntity proposeClientAgreement(@RequestHeader("X-AUTH-ID") String authId, @PathVariable String clientId, diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index aa5e020..461d174 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -187,10 +187,28 @@ public TrainingScheduleDto addWorkoutToSchedule(UUID clientAuthId, WorkoutReques () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) .getTrainingSchedule(); + return addWorkoutToScheduleHelper(workoutDto, trainingSchedule); + } + + private TrainingScheduleDto addWorkoutToScheduleHelper(WorkoutRequestDto workoutDto, TrainingSchedule trainingSchedule){ Workout workout = WorkoutMapper.toModel(workoutDto); workout.setTrainingSchedule(trainingSchedule); trainingSchedule.getWorkouts().add(workout); return trainingScheduleService.saveSchedule(trainingSchedule); } + + public TrainingScheduleDto addWorkoutToClientsSchedule(UUID coachAuthId, UUID clientId, WorkoutRequestDto workoutDto) { + UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( + () -> new UserNotFoundException("Coach not found with authId: " + coachAuthId)).getId(); + + if(!coachClientAgreementService.isUserAClientOfCoach(clientId, coachId)){ + throw new UnauthorizedScheduleAccessException("The user with id: " + coachId + " is not a coach of user with id: " + clientId); + } + + TrainingSchedule trainingSchedule = userRepository.findById(clientId).orElseThrow( + () -> new UserNotFoundException("User not found with id: " + clientId)).getTrainingSchedule(); + + return addWorkoutToScheduleHelper(workoutDto, trainingSchedule); + } } From c6446910cd863f87c6c04f06d1c76a266c443784 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Tue, 2 Dec 2025 16:55:04 -0800 Subject: [PATCH 07/12] movement service controller repo and not found exception. --- .../clients/addWorkoutToSchedule.http | 0 .../clients/deleteWorkoutFromSchedule.http | 0 .../clients/getClientsCoaches.http | 0 .../clients/getTrainingSchedule.http | 0 .../controller/MovementController.java | 35 +++++++++++++++++ .../exercise/ExerciseRequestDto.java | 8 +++- .../movement/MovementCreateRequestDto.java | 8 ++++ .../exception/MovementNotFoundException.java | 7 ++++ .../repository/MovementRepository.java | 11 ++++++ .../service/MovementService.java | 38 +++++++++++++++++++ 10 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 api-request/client-service/clients/addWorkoutToSchedule.http create mode 100644 api-request/client-service/clients/deleteWorkoutFromSchedule.http create mode 100644 api-request/client-service/clients/getClientsCoaches.http create mode 100644 api-request/client-service/clients/getTrainingSchedule.http create mode 100644 client-service/src/main/java/com/cm/clientservice/controller/MovementController.java create mode 100644 client-service/src/main/java/com/cm/clientservice/exception/MovementNotFoundException.java create mode 100644 client-service/src/main/java/com/cm/clientservice/repository/MovementRepository.java create mode 100644 client-service/src/main/java/com/cm/clientservice/service/MovementService.java diff --git a/api-request/client-service/clients/addWorkoutToSchedule.http b/api-request/client-service/clients/addWorkoutToSchedule.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/clients/deleteWorkoutFromSchedule.http b/api-request/client-service/clients/deleteWorkoutFromSchedule.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/clients/getClientsCoaches.http b/api-request/client-service/clients/getClientsCoaches.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/clients/getTrainingSchedule.http b/api-request/client-service/clients/getTrainingSchedule.http new file mode 100644 index 0000000..e69de29 diff --git a/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java b/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java new file mode 100644 index 0000000..214f934 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java @@ -0,0 +1,35 @@ +package com.cm.clientservice.controller; +import com.cm.clientservice.dto.scheduling.movement.MovementCreateRequestDto; +import com.cm.clientservice.dto.scheduling.movement.MovementResponseDto; +import com.cm.clientservice.service.MovementService; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.UUID; + +@RestController +@RequestMapping("/clients/movements") +@Tag(name="movements", description = "API for management of movements. ") +public class MovementController { + + private final MovementService movementService; + public MovementController(MovementService movementService){ + this.movementService = movementService; + } + + @PostMapping + public ResponseEntity createMovement(@RequestBody MovementCreateRequestDto movementCreateRequestDto){ + MovementResponseDto movementResponseDto = + movementService.createMovement(movementCreateRequestDto); + + return ResponseEntity.ok().body(movementResponseDto); + } + + @GetMapping("/id/{movementId}") + public ResponseEntity getMovementById(@PathVariable String movementId){ + MovementResponseDto movementResponseDto = + movementService.getMovementById(UUID.fromString(movementId)); + + return ResponseEntity.ok().body(movementResponseDto); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java index 9277b7f..3c69ff9 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java @@ -1,13 +1,19 @@ package com.cm.clientservice.dto.scheduling.exercise; import com.cm.clientservice.dto.scheduling.movement.MovementReuseRequestDto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; @Getter @Setter public class ExerciseRequestDto { + @NotNull private MovementReuseRequestDto movement; + @NotBlank private String numSets; + @NotBlank private String numReps; + @NotNull private String coachNotes; -} +} \ No newline at end of file diff --git a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java index d5e7a07..6fc5600 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java @@ -1,6 +1,14 @@ package com.cm.clientservice.dto.scheduling.movement; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter public class MovementCreateRequestDto { + @NotNull private String name; + @NotNull private String description; } diff --git a/client-service/src/main/java/com/cm/clientservice/exception/MovementNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/MovementNotFoundException.java new file mode 100644 index 0000000..4ed2440 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/exception/MovementNotFoundException.java @@ -0,0 +1,7 @@ +package com.cm.clientservice.exception; + +public class MovementNotFoundException extends RuntimeException { + public MovementNotFoundException(String message){ + super(message); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/repository/MovementRepository.java b/client-service/src/main/java/com/cm/clientservice/repository/MovementRepository.java new file mode 100644 index 0000000..f8011b1 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/repository/MovementRepository.java @@ -0,0 +1,11 @@ +package com.cm.clientservice.repository; + +import com.cm.clientservice.model.schedule.Movement; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; +import java.util.UUID; + +public interface MovementRepository extends JpaRepository { + Optional findMovementByName(String name); +} diff --git a/client-service/src/main/java/com/cm/clientservice/service/MovementService.java b/client-service/src/main/java/com/cm/clientservice/service/MovementService.java new file mode 100644 index 0000000..cbebda8 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/service/MovementService.java @@ -0,0 +1,38 @@ +package com.cm.clientservice.service; + +import com.cm.clientservice.dto.scheduling.movement.MovementCreateRequestDto; +import com.cm.clientservice.dto.scheduling.movement.MovementResponseDto; +import com.cm.clientservice.exception.MovementNotFoundException; +import com.cm.clientservice.mapper.schedule.MovementMapper; +import com.cm.clientservice.model.schedule.Movement; +import com.cm.clientservice.repository.MovementRepository; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +@Service +public class MovementService { + + private final MovementRepository movementRepository; + + public MovementService(MovementRepository movementRepository){ + this.movementRepository = movementRepository; + } + + public MovementResponseDto createMovement(MovementCreateRequestDto movementCreateRequestDto) { + Movement movement = new Movement(); + movement.setName(movementCreateRequestDto.getName()); + movement.setDescription(movementCreateRequestDto.getDescription()); + + Movement newMovement = movementRepository.save(movement); + + return MovementMapper.toDto(newMovement); + } + + public MovementResponseDto getMovementById(UUID movementId) { + Movement movement = movementRepository.findById(movementId).orElseThrow( + () -> new MovementNotFoundException("Movement not found with id: " + movementId)); + + return MovementMapper.toDto(movement); + } +} From 9758d6ab4a8a7a0d2845347cbfc33a4a49316329 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Tue, 2 Dec 2025 18:52:42 -0800 Subject: [PATCH 08/12] api requests working for add workout, delete workout, get-clients-coaches, gettrainingschedule --- .../{changeEmail.http => change-email.http} | 0 ...angePassword.http => change-password.http} | 0 api-request/auth-service/login.http | 2 +- api-request/auth-service/register.http | 2 +- .../clients/add-workout-to-schedule.http | 23 ++++++++++++++++++ .../clients/addWorkoutToSchedule.http | 0 .../clients/delete-workout-from-schedule.http | 2 ++ .../clients/deleteWorkoutFromSchedule.http | 0 .../clients/get-clients-coaches.http | 2 ++ .../clients/get-training-schedule.http | 5 ++++ .../clients/getClientsCoaches.http | 0 .../clients/getTrainingSchedule.http | 0 api-request/client-service/create-user.http | 5 ++-- api-request/client-service/delete-user.http | 2 +- api-request/client-service/get-users.http | 2 +- .../movements/create-movement.http | 10 ++++++++ .../movements/get-movement.http | 2 ++ .../controller/ClientController.java | 8 +++---- .../controller/CoachingController.java | 2 +- .../controller/MovementController.java | 2 +- .../controller/UserController.java | 6 ++--- .../exception/WorkoutNotFoundException.java | 7 ++++++ .../java/com/cm/clientservice/model/User.java | 2 +- .../cm/clientservice/service/UserService.java | 23 +++++++++++------- client-service/src/main/resources/data.sql | 24 ------------------- 25 files changed, 82 insertions(+), 49 deletions(-) rename api-request/auth-service/{changeEmail.http => change-email.http} (100%) rename api-request/auth-service/{changePassword.http => change-password.http} (100%) create mode 100644 api-request/client-service/clients/add-workout-to-schedule.http delete mode 100644 api-request/client-service/clients/addWorkoutToSchedule.http create mode 100644 api-request/client-service/clients/delete-workout-from-schedule.http delete mode 100644 api-request/client-service/clients/deleteWorkoutFromSchedule.http create mode 100644 api-request/client-service/clients/get-clients-coaches.http create mode 100644 api-request/client-service/clients/get-training-schedule.http delete mode 100644 api-request/client-service/clients/getClientsCoaches.http delete mode 100644 api-request/client-service/clients/getTrainingSchedule.http create mode 100644 api-request/client-service/movements/create-movement.http create mode 100644 api-request/client-service/movements/get-movement.http create mode 100644 client-service/src/main/java/com/cm/clientservice/exception/WorkoutNotFoundException.java delete mode 100644 client-service/src/main/resources/data.sql diff --git a/api-request/auth-service/changeEmail.http b/api-request/auth-service/change-email.http similarity index 100% rename from api-request/auth-service/changeEmail.http rename to api-request/auth-service/change-email.http diff --git a/api-request/auth-service/changePassword.http b/api-request/auth-service/change-password.http similarity index 100% rename from api-request/auth-service/changePassword.http rename to api-request/auth-service/change-password.http diff --git a/api-request/auth-service/login.http b/api-request/auth-service/login.http index 082ff99..c55771f 100644 --- a/api-request/auth-service/login.http +++ b/api-request/auth-service/login.http @@ -3,7 +3,7 @@ POST http://localhost:4004/api/auth/login Content-Type: application/json { - "email": "test_email@gmail.com", + "email": "test_email3@gmail.com", "password": "c++_4_life!" } diff --git a/api-request/auth-service/register.http b/api-request/auth-service/register.http index daed131..dc0a690 100644 --- a/api-request/auth-service/register.http +++ b/api-request/auth-service/register.http @@ -2,6 +2,6 @@ POST http://localhost:4004/api/auth/register Content-Type: application/json { - "email": "test_email@gmail.com", + "email": "test_email3@gmail.com", "password": "c++_4_life!" } diff --git a/api-request/client-service/clients/add-workout-to-schedule.http b/api-request/client-service/clients/add-workout-to-schedule.http new file mode 100644 index 0000000..209f3df --- /dev/null +++ b/api-request/client-service/clients/add-workout-to-schedule.http @@ -0,0 +1,23 @@ +POST http://localhost:4004/api/clients/client/schedule/workout +Authorization: Bearer {{token}} +Content-Type: application/json + + +{ + "exercises" : [ + { + "movement" : { + "id" : "{{created_movement_id}}" + }, + "numSets" : "3", + "numReps" : "10", + "coachNotes" : "Take these easy if you need to." + } + ], + "date" : "2025-10-20", + "workoutNotes" : "Hey this is the note. Do good.", + "isCompleted" : "False", + "trainingScheduleId" : "" +} + + diff --git a/api-request/client-service/clients/addWorkoutToSchedule.http b/api-request/client-service/clients/addWorkoutToSchedule.http deleted file mode 100644 index e69de29..0000000 diff --git a/api-request/client-service/clients/delete-workout-from-schedule.http b/api-request/client-service/clients/delete-workout-from-schedule.http new file mode 100644 index 0000000..7bc64f3 --- /dev/null +++ b/api-request/client-service/clients/delete-workout-from-schedule.http @@ -0,0 +1,2 @@ +DELETE http://localhost:4004/api/clients/client/schedule/workout/fde2ca82-1a26-4767-adc9-8fbbdfc119e0 +Authorization: Bearer {{token}} \ No newline at end of file diff --git a/api-request/client-service/clients/deleteWorkoutFromSchedule.http b/api-request/client-service/clients/deleteWorkoutFromSchedule.http deleted file mode 100644 index e69de29..0000000 diff --git a/api-request/client-service/clients/get-clients-coaches.http b/api-request/client-service/clients/get-clients-coaches.http new file mode 100644 index 0000000..2e1a029 --- /dev/null +++ b/api-request/client-service/clients/get-clients-coaches.http @@ -0,0 +1,2 @@ +GET http://localhost:4004/api/clients/client/coaches +Authorization: Bearer {{token}} \ No newline at end of file diff --git a/api-request/client-service/clients/get-training-schedule.http b/api-request/client-service/clients/get-training-schedule.http new file mode 100644 index 0000000..c26dc70 --- /dev/null +++ b/api-request/client-service/clients/get-training-schedule.http @@ -0,0 +1,5 @@ +### Get request to get a users training schedule. +GET http://localhost:4004/api/clients/client/schedule +Authorization: Bearer {{token}} + +> {% client.global.set("training_schedule_id", response.body.id) %} diff --git a/api-request/client-service/clients/getClientsCoaches.http b/api-request/client-service/clients/getClientsCoaches.http deleted file mode 100644 index e69de29..0000000 diff --git a/api-request/client-service/clients/getTrainingSchedule.http b/api-request/client-service/clients/getTrainingSchedule.http deleted file mode 100644 index e69de29..0000000 diff --git a/api-request/client-service/create-user.http b/api-request/client-service/create-user.http index 3e54968..d8610da 100644 --- a/api-request/client-service/create-user.http +++ b/api-request/client-service/create-user.http @@ -1,13 +1,12 @@ ### Post request to create a user. -POST http://localhost:4004/api/clients +POST http://localhost:4004/api/clients/users Authorization: Bearer {{token}} -X-AUTH-ID: a7920032-59cf-461f-a293-6944954d3747 Content-Type: application/json { "firstName": "Test", "lastName": "User", - "email": "test_user@test.com", + "email": "test_user3@test.com", "address": "123 Test-Request Ave, 493201, WA, USA.", "dateOfBirth": "2000-01-01", "registeredDate": "2025-01-01" diff --git a/api-request/client-service/delete-user.http b/api-request/client-service/delete-user.http index 552427c..2072e0f 100644 --- a/api-request/client-service/delete-user.http +++ b/api-request/client-service/delete-user.http @@ -1,2 +1,2 @@ -DELETE http://localhost:4004/api/clients/a526c437-cd19-48a2-9804-fdbe091c0b38 +DELETE http://localhost:4004/api/clients/users/a526c437-cd19-48a2-9804-fdbe091c0b38 Authorization: Bearer {{token}} diff --git a/api-request/client-service/get-users.http b/api-request/client-service/get-users.http index 5b47f54..038efc5 100644 --- a/api-request/client-service/get-users.http +++ b/api-request/client-service/get-users.http @@ -1,3 +1,3 @@ ### GET request to get the users. -GET http://localhost:4004/api/clients +GET http://localhost:4004/api/clients/users Authorization: Bearer {{token}} \ No newline at end of file diff --git a/api-request/client-service/movements/create-movement.http b/api-request/client-service/movements/create-movement.http new file mode 100644 index 0000000..fbbb056 --- /dev/null +++ b/api-request/client-service/movements/create-movement.http @@ -0,0 +1,10 @@ +POST http://localhost:4004/api/clients/movements +Authorization: Bearer {{token}} +Content-Type: application/json + +{ + "name" : "Deadlift", + "description" : "Sumo or bust." +} + +> {% client.global.set("created_movement_id", response.body.id) %} diff --git a/api-request/client-service/movements/get-movement.http b/api-request/client-service/movements/get-movement.http new file mode 100644 index 0000000..ac56bf3 --- /dev/null +++ b/api-request/client-service/movements/get-movement.http @@ -0,0 +1,2 @@ +GET http://localhost:4004/api/clients/movements/{{created_movement_id}} +Authorization: Bearer {{token}} diff --git a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java index ae0986c..8be10a4 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java @@ -36,7 +36,7 @@ import java.util.UUID; @RestController -@RequestMapping("/client") +@RequestMapping("clients/client") @Tag(name="client", description = "API for clients to manage their experience.") public class ClientController { @@ -58,12 +58,12 @@ public ResponseEntity getTrainingSchedule(@RequestHeader("X return ResponseEntity.ok().body(trainingScheduleDto); } - @DeleteMapping("/schedule/workout/{id}") + @DeleteMapping("/schedule/workout/{workoutId}") public ResponseEntity deleteWorkoutFromSchedule(@RequestHeader("X-AUTH-ID") String authId, - @PathVariable String id){ + @PathVariable String workoutId){ TrainingScheduleDto trainingScheduleDto = - userService.removeWorkoutFromSchedule(UUID.fromString(authId), UUID.fromString(id)); + userService.removeWorkoutFromSchedule(UUID.fromString(authId), UUID.fromString(workoutId)); return ResponseEntity.ok().body(trainingScheduleDto); } diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index d21d031..b5b3eae 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -16,7 +16,7 @@ import java.util.List; import java.util.UUID; -@RestController("/coaching") +@RestController("clients/coaching") @Tag(name = "coaching", description = "API for coaching management.") public class CoachingController { diff --git a/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java b/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java index 214f934..13cec7f 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java @@ -25,7 +25,7 @@ public ResponseEntity createMovement(@RequestBody MovementC return ResponseEntity.ok().body(movementResponseDto); } - @GetMapping("/id/{movementId}") + @GetMapping("/{movementId}") public ResponseEntity getMovementById(@PathVariable String movementId){ MovementResponseDto movementResponseDto = movementService.getMovementById(UUID.fromString(movementId)); diff --git a/client-service/src/main/java/com/cm/clientservice/controller/UserController.java b/client-service/src/main/java/com/cm/clientservice/controller/UserController.java index 9584289..f11ee9b 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/UserController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/UserController.java @@ -16,7 +16,7 @@ import java.util.UUID; @RestController -@RequestMapping("/users") +@RequestMapping("clients/users") @Tag(name="Users", description = "API for managing Users") public class UserController { private final Logger log = LoggerFactory.getLogger(UserController.class); @@ -58,9 +58,9 @@ public ResponseEntity updateUser(@RequestHeader("X-AUTH-ID") St String token = authHeader.substring(tokenStartIdx); UUID authId = UUID.fromString(id); - userService.updateUser(authId, userRequestDTO, token); + UserResponseDTO updatedUser = userService.updateUser(authId, userRequestDTO, token); - return ResponseEntity.ok().body(new UserResponseDTO()); + return ResponseEntity.ok().body(updatedUser); } diff --git a/client-service/src/main/java/com/cm/clientservice/exception/WorkoutNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/WorkoutNotFoundException.java new file mode 100644 index 0000000..90fd28e --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/exception/WorkoutNotFoundException.java @@ -0,0 +1,7 @@ +package com.cm.clientservice.exception; + +public class WorkoutNotFoundException extends RuntimeException{ + public WorkoutNotFoundException(String message){ + super(message); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/model/User.java b/client-service/src/main/java/com/cm/clientservice/model/User.java index eaf763d..0aab62e 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/User.java +++ b/client-service/src/main/java/com/cm/clientservice/model/User.java @@ -56,7 +56,7 @@ public class User { @OneToMany(mappedBy = "author") private List authoredTemplates; - @OneToOne + @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="training_schedule_id") private TrainingSchedule trainingSchedule; } diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index 461d174..752bd6f 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -8,6 +8,7 @@ import com.cm.clientservice.exception.EmailAlreadyExistsException; import com.cm.clientservice.exception.UnauthorizedScheduleAccessException; import com.cm.clientservice.exception.UserNotFoundException; +import com.cm.clientservice.exception.WorkoutNotFoundException; import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; import com.cm.clientservice.mapper.UserMapper; import com.cm.clientservice.mapper.schedule.WorkoutMapper; @@ -21,6 +22,7 @@ import org.springframework.web.reactive.function.client.WebClient; import java.time.LocalDate; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -55,6 +57,10 @@ public UserResponseDTO createUser(UserRequestDTO userRequestDTO, String auth_id) User newUser = UserMapper.toModel(userRequestDTO); newUser.setAuthId(UUID.fromString(auth_id)); + + TrainingSchedule schedule = new TrainingSchedule(); + newUser.setTrainingSchedule(schedule); + newUser = userRepository.save(newUser); return UserMapper.toDTO(newUser); @@ -72,7 +78,6 @@ public List getAllUsers(){ .toList(); } - public UserResponseDTO updateUser(UUID authId, UserRequestDTO userRequestDTO, String token){ // Find the user that has the authId User user = userRepository.findByAuthId(authId).orElseThrow( @@ -170,14 +175,16 @@ public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID wor () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) .getTrainingSchedule(); - // Get their schedule and filter out the workout mentioned. - List workouts = trainingSchedule - .getWorkouts() - .stream() - .filter(s -> !(s.getId().equals( workoutId))) - .collect(Collectors.toList()); + List workouts = trainingSchedule.getWorkouts(); + + Workout workoutToRemove = + workouts.stream() + .filter(w -> w.getId().equals(workoutId)) + .findFirst() + .orElseThrow( + () -> new WorkoutNotFoundException("Workout not found with id: " + workoutId)); - trainingSchedule.setWorkouts(workouts); + workouts.remove(workoutToRemove); return trainingScheduleService.saveSchedule(trainingSchedule); } diff --git a/client-service/src/main/resources/data.sql b/client-service/src/main/resources/data.sql deleted file mode 100644 index fa4f92d..0000000 --- a/client-service/src/main/resources/data.sql +++ /dev/null @@ -1,24 +0,0 @@ --- Ensure the 'users' table exists -CREATE TABLE IF NOT EXISTS users -( - id UUID PRIMARY KEY, - first_name VARCHAR(255) NOT NULL, - last_name VARCHAR(255) NOT NULL, - email VARCHAR(255) UNIQUE NOT NULL, - address VARCHAR(255) NOT NULL, - date_of_birth DATE NOT NULL, - registration_date DATE NOT NULL - ); - --- Insert well-known UUIDs for specific users -INSERT INTO users (id, first_name, last_name, email, address, date_of_birth, registration_date) -SELECT '123e4567-e89b-12d3-a456-426614174000', - 'Larry', - 'David', - 'larry.david@example.com', - '123 Main St, Springfield', - '1985-06-15', - '2024-01-10' - WHERE NOT EXISTS (SELECT 1 - FROM users - WHERE id = '123e4567-e89b-12d3-a456-426614174000'); From 71f41c19301305e5cbf2f9b2c54da9bf827231ee Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Tue, 2 Dec 2025 21:16:32 -0800 Subject: [PATCH 09/12] dto for agreement and contract ironed out a little. Also small bug fix in user service --- .../coaches/get-client-schedule.http | 0 .../client-service/coaches/get-clients.http | 0 .../controller/CoachingController.java | 18 +++++------ .../contract/AgreementTemplateRequestDto.java | 30 +++++++++++++++++++ ...java => AgreementTemplateResponseDto.java} | 3 +- .../dto/contract/CoachClientAgreementDto.java | 13 -------- .../CoachClientAgreementRequestDto.java | 16 ++++++++++ .../CoachClientAgreementResponseDto.java | 19 ++++++++++++ .../contract/AgreementTemplateMapper.java | 20 +++++++++++-- .../contract/CoachClientAgreementMapper.java | 25 +++++++++++++--- .../model/contract/AgreementTemplate.java | 3 ++ .../model/contract/CoachClientAgreement.java | 9 ++++-- .../model/schedule/TrainingSchedule.java | 4 +++ .../cm/clientservice/service/UserService.java | 2 +- 14 files changed, 128 insertions(+), 34 deletions(-) create mode 100644 api-request/client-service/coaches/get-client-schedule.http create mode 100644 api-request/client-service/coaches/get-clients.http create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateRequestDto.java rename client-service/src/main/java/com/cm/clientservice/dto/contract/{AgreementTemplateDto.java => AgreementTemplateResponseDto.java} (79%) delete mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java diff --git a/api-request/client-service/coaches/get-client-schedule.http b/api-request/client-service/coaches/get-client-schedule.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/coaches/get-clients.http b/api-request/client-service/coaches/get-clients.http new file mode 100644 index 0000000..e69de29 diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index b5b3eae..2b69229 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -2,7 +2,7 @@ import com.cm.clientservice.dto.UserRequestDTO; import com.cm.clientservice.dto.UserResponseDTO; -import com.cm.clientservice.dto.contract.AgreementTemplateDto; +import com.cm.clientservice.dto.contract.AgreementTemplateResponseDto; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; import com.cm.clientservice.model.contract.AgreementTemplate; @@ -34,7 +34,7 @@ public ResponseEntity> getClients(@RequestHeader("X-AUTH-I return ResponseEntity.ok().body(clients); } - @GetMapping("/client-schedule/{clientId}") + @GetMapping("/clients/{clientId}/schedule") @Operation(summary = "Get the clients training schedule for the coach to view. ") public ResponseEntity getClientSchedule(@RequestHeader("X-AUTH-ID") String authId, @PathVariable String clientId){ @@ -45,8 +45,8 @@ public ResponseEntity getClientSchedule(@RequestHeader("X-A return ResponseEntity.ok().body(trainingScheduleDto); } - @DeleteMapping("/client-schedule/workout/{id}") - public ResponseEntity deleteWorkoutFromSchedule(@RequestHeader("X-AUTH-ID") String authId, + @DeleteMapping("/clients/{clientId}/schedule/workout/{id}") + public ResponseEntity deleteWorkoutFromClientSchedule(@RequestHeader("X-AUTH-ID") String authId, @PathVariable String id){ TrainingScheduleDto trainingScheduleDto = @@ -55,8 +55,8 @@ public ResponseEntity deleteWorkoutFromSchedule(@RequestHea return ResponseEntity.ok().body(trainingScheduleDto); } - @PostMapping("/client-schedule/{clientId}/workout") - public ResponseEntity addWorkoutToSchedule(@RequestHeader("X-AUTH-ID") String authId, + @PostMapping("/clients/{clientId}/schedule/workout") + public ResponseEntity addWorkoutToClientSchedule(@RequestHeader("X-AUTH-ID") String authId, @PathVariable String clientId, @RequestBody WorkoutRequestDto workoutDto){ TrainingScheduleDto trainingScheduleDto = @@ -89,12 +89,12 @@ public ResponseEntity breakClientAgreement(@RequestHeader("X-AU // These should probably go in their own controller. //TODO: This should be accessed only by accounts that have a coaching profile. - public ResponseEntity createAgreementTemplate(){ + public ResponseEntity createAgreementTemplate(){ return null; } // TODO: This should be accessed only by accounts that have a coaching profile - public ResponseEntity deleteAgreementTemplate(){ + public ResponseEntity deleteAgreementTemplate(){ return null; } @@ -104,7 +104,7 @@ public ResponseEntity updateAgreementTemplate(){ } // TODO: This should be accessed only by accounts that have a coach profile. - public ResponseEntity> getCoachAgreementTemplates(){ + public ResponseEntity> getCoachAgreementTemplates(){ return null; } } diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateRequestDto.java new file mode 100644 index 0000000..b4e077c --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateRequestDto.java @@ -0,0 +1,30 @@ +package com.cm.clientservice.dto.contract; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AgreementTemplateRequestDto { + + @NotBlank + private String templateName; + + @NotNull + @PositiveOrZero + private String paymentAmount; + + @NotNull + @Positive + private String daysBetweenPayments; + + @NotBlank + private String termsAndConditions; + + @NotBlank + private String allowPublicTemplateReuse; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateResponseDto.java similarity index 79% rename from client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateDto.java rename to client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateResponseDto.java index 0f003b3..8e0273b 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateResponseDto.java @@ -5,8 +5,9 @@ @Getter @Setter -public class AgreementTemplateDto { +public class AgreementTemplateResponseDto { private String id; + private String templateName; private String authorId; private String paymentAmount; private String daysBetweenPayments; diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java deleted file mode 100644 index 960c85e..0000000 --- a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementDto.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.cm.clientservice.dto.contract; - -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class CoachClientAgreementDto { - private String coachId; - private String clientId; - private String startDate; - private AgreementTemplateDto agreementTemplateDto; -} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java new file mode 100644 index 0000000..d48df35 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java @@ -0,0 +1,16 @@ +package com.cm.clientservice.dto.contract; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CoachClientAgreementRequestDto { + @NotNull + private String clientId; + @NotNull + private String startDate; + @NotNull + private AgreementTemplateRequestDto agreementTemplateDto; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java new file mode 100644 index 0000000..edc88d8 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java @@ -0,0 +1,19 @@ +package com.cm.clientservice.dto.contract; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CoachClientAgreementResponseDto { + private String id; + + private String clientId; + private String coachId; + + private String startDate; + private AgreementTemplateResponseDto agreementTemplateResponseDto; + + private String clientIsInAgreement; + private String coachIsInAgreement; +} diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java index 2722dff..c3139e4 100644 --- a/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java +++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java @@ -1,12 +1,13 @@ package com.cm.clientservice.mapper.contract; -import com.cm.clientservice.dto.contract.AgreementTemplateDto; +import com.cm.clientservice.dto.contract.AgreementTemplateRequestDto; +import com.cm.clientservice.dto.contract.AgreementTemplateResponseDto; import com.cm.clientservice.model.contract.AgreementTemplate; public class AgreementTemplateMapper { - public static AgreementTemplateDto toDto(AgreementTemplate agreementTemplate){ - AgreementTemplateDto dto = new AgreementTemplateDto(); + public static AgreementTemplateResponseDto toDto(AgreementTemplate agreementTemplate){ + AgreementTemplateResponseDto dto = new AgreementTemplateResponseDto(); dto.setId(agreementTemplate.getId().toString()); dto.setVersion(agreementTemplate.getVersion().toString()); @@ -14,7 +15,20 @@ public static AgreementTemplateDto toDto(AgreementTemplate agreementTemplate){ dto.setTermsAndConditions(agreementTemplate.getTermsAndConditions()); dto.setDaysBetweenPayments(agreementTemplate.getDaysBetweenPayments().toString()); dto.setAuthorId(agreementTemplate.getAuthor().getId().toString()); + dto.setTemplateName(agreementTemplate.getTemplateName()); return dto; } + + public static AgreementTemplate toModel(AgreementTemplateRequestDto dto) { + AgreementTemplate template = new AgreementTemplate(); + + template.setPaymentAmount(Double.parseDouble(dto.getPaymentAmount())); + template.setTermsAndConditions(dto.getTermsAndConditions()); + template.setAllowPublicTemplateReuse(Boolean.valueOf(dto.getAllowPublicTemplateReuse())); + template.setDaysBetweenPayments(Integer.parseInt(dto.getDaysBetweenPayments())); + template.setTemplateName(dto.getTemplateName()); + + return template; + } } diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java index db124a8..a87a23e 100644 --- a/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java +++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java @@ -1,16 +1,33 @@ package com.cm.clientservice.mapper.contract; -import com.cm.clientservice.dto.contract.CoachClientAgreementDto; +import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; +import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; import com.cm.clientservice.model.contract.CoachClientAgreement; +import java.time.LocalDate; + public class CoachClientAgreementMapper { - public static CoachClientAgreementDto toDto(CoachClientAgreement agreement) { - CoachClientAgreementDto dto = new CoachClientAgreementDto(); + public static CoachClientAgreementResponseDto toDto(CoachClientAgreement agreement) { + CoachClientAgreementResponseDto dto = new CoachClientAgreementResponseDto(); - dto.setAgreementTemplateDto(AgreementTemplateMapper.toDto(agreement.getAgreementTemplate())); + dto.setAgreementTemplateResponseDto(AgreementTemplateMapper.toDto(agreement.getAgreementTemplate())); dto.setClientId(agreement.getClient().getId().toString()); dto.setCoachId(agreement.getCoach().getId().toString()); dto.setStartDate(agreement.getStartDate().toString()); + dto.setId(agreement.getId().toString()); + dto.setClientIsInAgreement(agreement.getClientIsInAgreement().toString()); + dto.setCoachIsInAgreement(agreement.getCoachIsInAgreement().toString()); return dto; } + + public static CoachClientAgreement toModel(CoachClientAgreementRequestDto dto){ + CoachClientAgreement agreement = new CoachClientAgreement(); + + agreement.setAgreementTemplate(AgreementTemplateMapper.toModel(dto.getAgreementTemplateDto())); + agreement.setClientIsInAgreement(Boolean.FALSE); + agreement.setCoachIsInAgreement(Boolean.TRUE); + agreement.setStartDate(LocalDate.parse(dto.getStartDate())); + + return agreement; + } } diff --git a/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java b/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java index d78d47f..5a0fb80 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java +++ b/client-service/src/main/java/com/cm/clientservice/model/contract/AgreementTemplate.java @@ -19,6 +19,9 @@ public class AgreementTemplate { @GeneratedValue private UUID id; + @NotBlank(message = "Template name must be provided.") + private String templateName; + @NotNull(message = "Original author must be included for agreement template.") @ManyToOne @JoinColumn(name = "coach_profile_id") diff --git a/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java b/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java index fb9c9a7..131bb76 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java +++ b/client-service/src/main/java/com/cm/clientservice/model/contract/CoachClientAgreement.java @@ -13,9 +13,6 @@ @Getter @Setter public class CoachClientAgreement { - /** - Represents a running agreement document between - */ @Id @GeneratedValue @@ -38,5 +35,11 @@ public class CoachClientAgreement { @NotNull(message = "Coach-Client Agreement must have a start date.") private LocalDate startDate; + + @NotNull(message = "Client agreement status must be specified. ") + private Boolean clientIsInAgreement; + + @NotNull(message = "Coach agreement status must be specified. ") + private Boolean coachIsInAgreement; } diff --git a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java index 72c9e30..95de79f 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java +++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java @@ -1,4 +1,5 @@ package com.cm.clientservice.model.schedule; +import com.cm.clientservice.model.User; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -16,6 +17,9 @@ public class TrainingSchedule { @GeneratedValue private UUID id; + @OneToOne + private User user; + @OneToMany(mappedBy = "trainingSchedule", cascade = CascadeType.ALL, orphanRemoval = true) private List workouts = new ArrayList<>(); } diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index 752bd6f..02423ac 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -164,7 +164,7 @@ public TrainingScheduleDto getTrainingSchedule(UUID authId){ TrainingSchedule schedule = userRepository.findByAuthId(authId) .orElseThrow( - () -> new UserNotFoundException("User not found with authID: " + authId)) + () -> new UserNotFoundException("User not found with authId: " + authId)) .getTrainingSchedule(); return TrainingScheduleMapper.toDto(schedule); From 43f25ef1fce45d123e43a6b0050f1a53220a503e Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Wed, 3 Dec 2025 16:11:10 -0800 Subject: [PATCH 10/12] fixes with adding and removing workout from shcedule modularity --- .../controller/CoachingController.java | 9 +-- .../service/CoachClientAgreementService.java | 6 ++ .../service/TrainingScheduleService.java | 34 ++++++++++- .../cm/clientservice/service/UserService.java | 61 +++++++++---------- 4 files changed, 70 insertions(+), 40 deletions(-) diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index 2b69229..1318f4d 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -40,17 +40,18 @@ public ResponseEntity getClientSchedule(@RequestHeader("X-A @PathVariable String clientId){ TrainingScheduleDto trainingScheduleDto = - userService.getClientSchedule(UUID.fromString(clientId), UUID.fromString(authId)); + userService.getClientTrainingSchedule(UUID.fromString(clientId), UUID.fromString(authId)); return ResponseEntity.ok().body(trainingScheduleDto); } @DeleteMapping("/clients/{clientId}/schedule/workout/{id}") public ResponseEntity deleteWorkoutFromClientSchedule(@RequestHeader("X-AUTH-ID") String authId, - @PathVariable String id){ + @PathVariable String clientId, + @PathVariable String id){ TrainingScheduleDto trainingScheduleDto = - userService.removeWorkoutFromSchedule(UUID.fromString(authId), UUID.fromString(id)); + userService.removeWorkoutFromClientSchedule(UUID.fromString(authId), UUID.fromString(clientId), UUID.fromString(id)); return ResponseEntity.ok().body(trainingScheduleDto); } @@ -67,7 +68,7 @@ public ResponseEntity addWorkoutToClientSchedule(@RequestHe @PostMapping("/propose-agreement/{clientId}") - public ResponseEntity proposeClientAgreement(@RequestHeader("X-AUTH-ID") String authId, + public ResponseEntity proposeClientAgreement(@RequestHeader("X-AUTH-ID") String coachAuthId, @PathVariable String clientId, @RequestBody CoachClientAgreement coachClientAgreement){ diff --git a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java index 6a344c4..c6af3a2 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java @@ -3,6 +3,7 @@ import com.cm.clientservice.repository.CoachClientAgreementRepository; import org.springframework.stereotype.Service; +import java.time.LocalDate; import java.util.List; import java.util.UUID; @@ -25,4 +26,9 @@ public boolean isUserAClientOfCoach(UUID userId, UUID coachId){ .existsCoachClientAgreementByClient_IdAndCoach_Id(userId, coachId); } + public boolean isAgreementActive(CoachClientAgreement coachClientAgreement) { + return coachClientAgreement.getCoachIsInAgreement() && + coachClientAgreement.getClientIsInAgreement(); + } + } diff --git a/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java index 44555bb..a1d1ad4 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java @@ -1,11 +1,18 @@ package com.cm.clientservice.service; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; +import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; +import com.cm.clientservice.exception.WorkoutNotFoundException; import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; +import com.cm.clientservice.mapper.schedule.WorkoutMapper; import com.cm.clientservice.model.schedule.TrainingSchedule; +import com.cm.clientservice.model.schedule.Workout; import com.cm.clientservice.repository.TrainingScheduleRepository; import org.springframework.stereotype.Service; +import java.util.List; +import java.util.UUID; + @Service public class TrainingScheduleService { @@ -15,8 +22,29 @@ public TrainingScheduleService(TrainingScheduleRepository trainingScheduleReposi this.trainingScheduleRepository = trainingScheduleRepository; } - public TrainingScheduleDto saveSchedule(TrainingSchedule trainingSchedule){ - TrainingSchedule newSchedule = trainingScheduleRepository.save(trainingSchedule); - return TrainingScheduleMapper.toDto(newSchedule); + public TrainingScheduleDto removeWorkoutFromSchedule(TrainingSchedule schedule, UUID workoutId){ + List workouts = schedule.getWorkouts(); + + Workout workoutToRemove = + workouts.stream() + .filter(w -> w.getId().equals(workoutId)) + .findFirst() + .orElseThrow( + () -> new WorkoutNotFoundException("Workout not found with id: " + workoutId)); + + workouts.remove(workoutToRemove); + + TrainingSchedule updatedSchedule = trainingScheduleRepository.save(schedule); + return TrainingScheduleMapper.toDto(updatedSchedule); + } + + public TrainingScheduleDto addWorkoutToSchedule(WorkoutRequestDto workoutDto, TrainingSchedule trainingSchedule){ + Workout workout = WorkoutMapper.toModel(workoutDto); + workout.setTrainingSchedule(trainingSchedule); + trainingSchedule.getWorkouts().add(workout); + + TrainingSchedule updatedSchedule = trainingScheduleRepository.save(trainingSchedule); + return TrainingScheduleMapper.toDto(updatedSchedule); } } + diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index 02423ac..e45a21a 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -8,12 +8,9 @@ import com.cm.clientservice.exception.EmailAlreadyExistsException; import com.cm.clientservice.exception.UnauthorizedScheduleAccessException; import com.cm.clientservice.exception.UserNotFoundException; -import com.cm.clientservice.exception.WorkoutNotFoundException; import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; import com.cm.clientservice.mapper.UserMapper; -import com.cm.clientservice.mapper.schedule.WorkoutMapper; import com.cm.clientservice.model.schedule.TrainingSchedule; -import com.cm.clientservice.model.schedule.Workout; import com.cm.clientservice.repository.UserRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; @@ -22,10 +19,8 @@ import org.springframework.web.reactive.function.client.WebClient; import java.time.LocalDate; -import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.stream.Collectors; @Service public class UserService { @@ -127,6 +122,7 @@ public List getClientsOfCoach(UUID coachAuthId){ return coachClientAgreementService .getCoachClientAgreements(coachId) .stream() + .filter(coachClientAgreementService::isAgreementActive) .map(a -> UserMapper.toDTO(a.getClient())) .distinct() .toList(); @@ -144,7 +140,7 @@ public List getCoachesOfClient(UUID clientAuthId) { .toList(); } - public TrainingScheduleDto getClientSchedule(UUID clientId, UUID coachAuthId){ + public TrainingScheduleDto getClientTrainingSchedule(UUID clientId, UUID coachAuthId){ UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( () -> new UserNotFoundException("Coach was not found with authId: " + coachAuthId)) .getId(); @@ -170,40 +166,15 @@ public TrainingScheduleDto getTrainingSchedule(UUID authId){ return TrainingScheduleMapper.toDto(schedule); } - public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID workoutId) { - TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( - () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) - .getTrainingSchedule(); - - List workouts = trainingSchedule.getWorkouts(); - - Workout workoutToRemove = - workouts.stream() - .filter(w -> w.getId().equals(workoutId)) - .findFirst() - .orElseThrow( - () -> new WorkoutNotFoundException("Workout not found with id: " + workoutId)); - - workouts.remove(workoutToRemove); - - return trainingScheduleService.saveSchedule(trainingSchedule); - } public TrainingScheduleDto addWorkoutToSchedule(UUID clientAuthId, WorkoutRequestDto workoutDto) { TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) .getTrainingSchedule(); - return addWorkoutToScheduleHelper(workoutDto, trainingSchedule); + return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingSchedule); } - private TrainingScheduleDto addWorkoutToScheduleHelper(WorkoutRequestDto workoutDto, TrainingSchedule trainingSchedule){ - Workout workout = WorkoutMapper.toModel(workoutDto); - workout.setTrainingSchedule(trainingSchedule); - trainingSchedule.getWorkouts().add(workout); - - return trainingScheduleService.saveSchedule(trainingSchedule); - } public TrainingScheduleDto addWorkoutToClientsSchedule(UUID coachAuthId, UUID clientId, WorkoutRequestDto workoutDto) { UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( @@ -216,6 +187,30 @@ public TrainingScheduleDto addWorkoutToClientsSchedule(UUID coachAuthId, UUID cl TrainingSchedule trainingSchedule = userRepository.findById(clientId).orElseThrow( () -> new UserNotFoundException("User not found with id: " + clientId)).getTrainingSchedule(); - return addWorkoutToScheduleHelper(workoutDto, trainingSchedule); + return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingSchedule); + } + + public TrainingScheduleDto removeWorkoutFromClientSchedule(UUID coachAuthId, UUID clientId, UUID workoutId) { + UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( + () -> new UserNotFoundException("Coach not found with authId: " + coachAuthId)).getId(); + + if(!coachClientAgreementService.isUserAClientOfCoach(clientId, coachId)){ + throw new UnauthorizedScheduleAccessException("The user with id: " + coachId + " is not a coach of user with id: " + clientId); + } + + // .get should be fine here since above will throw if client user doesn't exist. + TrainingSchedule trainingSchedule = userRepository.findById(clientId).get().getTrainingSchedule(); + + return trainingScheduleService.removeWorkoutFromSchedule(trainingSchedule, workoutId); + } + + + public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID workoutId) { + TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( + () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) + .getTrainingSchedule(); + + + return trainingScheduleService.removeWorkoutFromSchedule(trainingSchedule, workoutId); } } From 96efb8140f98bebe1a1bbe4aa80148c015b80bea Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Wed, 3 Dec 2025 21:39:24 -0800 Subject: [PATCH 11/12] withdraw coach agreement acceptance and helper method to reduce duplicate orElseThrow()->UserNotFounds --- .../controller/CoachingController.java | 65 +++++++---- ...CoachClientAgreementNotFoundException.java | 7 ++ .../java/com/cm/clientservice/model/User.java | 4 +- .../service/CoachClientAgreementService.java | 20 ++++ .../cm/clientservice/service/UserService.java | 108 ++++++++++++------ 5 files changed, 145 insertions(+), 59 deletions(-) create mode 100644 client-service/src/main/java/com/cm/clientservice/exception/CoachClientAgreementNotFoundException.java diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index 1318f4d..3bf7d54 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -2,7 +2,10 @@ import com.cm.clientservice.dto.UserRequestDTO; import com.cm.clientservice.dto.UserResponseDTO; +import com.cm.clientservice.dto.contract.AgreementTemplateRequestDto; import com.cm.clientservice.dto.contract.AgreementTemplateResponseDto; +import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; +import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; import com.cm.clientservice.model.contract.AgreementTemplate; @@ -67,45 +70,59 @@ public ResponseEntity addWorkoutToClientSchedule(@RequestHe } - @PostMapping("/propose-agreement/{clientId}") - public ResponseEntity proposeClientAgreement(@RequestHeader("X-AUTH-ID") String coachAuthId, - @PathVariable String clientId, - @RequestBody CoachClientAgreement coachClientAgreement){ + @PostMapping("/agreement/{clientId}") + public ResponseEntity proposeClientAgreement(@RequestHeader("X-AUTH-ID") String coachAuthId, + @PathVariable String clientId, + @RequestBody CoachClientAgreementRequestDto coachClientAgreement){ + CoachClientAgreementResponseDto dto = + userService.proposeCoachClientAgreement(UUID.fromString(coachAuthId), + UUID.fromString(clientId), + coachClientAgreement); - // This endpoint will allow for a coach to propose a client agreement to a user. - - - return null; + return ResponseEntity.ok().body(dto); } - @PostMapping("/break-agreement") - public ResponseEntity breakClientAgreement(@RequestHeader("X-AUTH-ID") String authId, - @RequestBody UserRequestDTO userRequestDTO, - @RequestBody CoachClientAgreement coachClientAgreement){ + @PutMapping("/agreement/withdraw/{agreementId}") + public ResponseEntity withdrawCoachesAgreementAcceptance(@RequestHeader("X-AUTH-ID") String coachAuthId, + @PathVariable String agreementId){ // Alert the user they have been dropped. // Alert billing service that the contract is being terminated. - return null; + + CoachClientAgreementResponseDto dto = + userService.withdrawCoachesAgreementAcceptance(UUID.fromString(coachAuthId), UUID.fromString(agreementId)); + + return ResponseEntity.ok().body(dto); } + @PostMapping("/templates") + public ResponseEntity createAgreementTemplate(@RequestHeader("X-AUTH-ID") String coachAuthId, + @RequestBody AgreementTemplateRequestDto templateRequestDto){ - // These should probably go in their own controller. - //TODO: This should be accessed only by accounts that have a coaching profile. - public ResponseEntity createAgreementTemplate(){ - return null; + return ResponseEntity.ok().body(dto); } // TODO: This should be accessed only by accounts that have a coaching profile public ResponseEntity deleteAgreementTemplate(){ - return null; + return ResponseEntity.ok().build(); } - // TODO: This should be accessed only by accounts that have a coach prifkle. - public ResponseEntity updateAgreementTemplate(){ - return null; + @PutMapping("/templates/template/{templateId}/update") + public ResponseEntity updateAgreementTemplate(@RequestHeader("X-AUTH-ID") String coachAuthId, + @RequestBody AgreementTemplateRequestDto templateRequestDto, + @PathVariable String templateId){ + AgreementTemplateResponseDto dto = + //TODO: Add a validation group ot the request dto to make it optional for each of the fields. + userService.updateAgreementTemplate(UUID.fromString(coachAuthId), UUID.fromString(templateId), templateRequestDto); + + return ResponseEntity.ok().body(dto); } - // TODO: This should be accessed only by accounts that have a coach profile. - public ResponseEntity> getCoachAgreementTemplates(){ - return null; + @GetMapping("/templates") + public ResponseEntity> getCoachAgreementTemplates(@RequestHeader("X-AUTH-ID") String coachAuthId){ + List dtoList = + userService.getCoachAgreementTemplates(UUID.fromString(coachAuthId)); + + + return ResponseEntity.ok().body(dtoList); } } diff --git a/client-service/src/main/java/com/cm/clientservice/exception/CoachClientAgreementNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/CoachClientAgreementNotFoundException.java new file mode 100644 index 0000000..288aabe --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/exception/CoachClientAgreementNotFoundException.java @@ -0,0 +1,7 @@ +package com.cm.clientservice.exception; + +public class CoachClientAgreementNotFoundException extends RuntimeException{ + public CoachClientAgreementNotFoundException(String message){ + super(message); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/model/User.java b/client-service/src/main/java/com/cm/clientservice/model/User.java index 0aab62e..eaf7acc 100644 --- a/client-service/src/main/java/com/cm/clientservice/model/User.java +++ b/client-service/src/main/java/com/cm/clientservice/model/User.java @@ -48,10 +48,10 @@ public class User { private String address; @OneToMany(mappedBy = "coach") - private List coachAgreements; + private List agreementsAsCoach; @OneToMany(mappedBy = "client") - private List clientAgreements; + private List agreementsAsClient; @OneToMany(mappedBy = "author") private List authoredTemplates; diff --git a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java index c6af3a2..7487abf 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java @@ -1,4 +1,8 @@ package com.cm.clientservice.service; +import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; +import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; +import com.cm.clientservice.mapper.contract.CoachClientAgreementMapper; +import com.cm.clientservice.model.User; import com.cm.clientservice.model.contract.CoachClientAgreement; import com.cm.clientservice.repository.CoachClientAgreementRepository; import org.springframework.stereotype.Service; @@ -31,4 +35,20 @@ public boolean isAgreementActive(CoachClientAgreement coachClientAgreement) { coachClientAgreement.getClientIsInAgreement(); } + public CoachClientAgreementResponseDto proposeCoachClientAgreement(User coach, User client, CoachClientAgreementRequestDto agreementDto) { + + CoachClientAgreement agreement = CoachClientAgreementMapper.toModel(agreementDto); + agreement.setCoach(coach); + agreement.setClient(client); + + coachClientAgreementRepository.save(agreement); + + return CoachClientAgreementMapper.toDto(agreement); + } + + public CoachClientAgreementResponseDto withdrawCoachesAgreementAcceptance(CoachClientAgreement agreementToChange) { + agreementToChange.setCoachIsInAgreement(Boolean.FALSE); + CoachClientAgreement updatedAgreement = coachClientAgreementRepository.save(agreementToChange); + return CoachClientAgreementMapper.toDto(updatedAgreement); + } } diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index e45a21a..344d314 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -3,13 +3,20 @@ import com.cm.clientservice.dto.OutgoingEmailUpdateDTO; import com.cm.clientservice.dto.UserRequestDTO; import com.cm.clientservice.dto.UserResponseDTO; +import com.cm.clientservice.dto.contract.AgreementTemplateRequestDto; +import com.cm.clientservice.dto.contract.AgreementTemplateResponseDto; +import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; +import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; +import com.cm.clientservice.exception.CoachClientAgreementNotFoundException; import com.cm.clientservice.exception.EmailAlreadyExistsException; import com.cm.clientservice.exception.UnauthorizedScheduleAccessException; import com.cm.clientservice.exception.UserNotFoundException; +import com.cm.clientservice.mapper.contract.CoachClientAgreementMapper; import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; import com.cm.clientservice.mapper.UserMapper; +import com.cm.clientservice.model.contract.CoachClientAgreement; import com.cm.clientservice.model.schedule.TrainingSchedule; import com.cm.clientservice.repository.UserRepository; import org.springframework.beans.factory.annotation.Value; @@ -75,8 +82,7 @@ public List getAllUsers(){ public UserResponseDTO updateUser(UUID authId, UserRequestDTO userRequestDTO, String token){ // Find the user that has the authId - User user = userRepository.findByAuthId(authId).orElseThrow( - () -> new UserNotFoundException("User not found with authId: " + authId)); + User user = findUserByAuthIdOrElseThrow(authId); boolean updatingEmail = !user.getEmail().equalsIgnoreCase(userRequestDTO.getEmail()); @@ -116,8 +122,7 @@ public UserResponseDTO updateUser(UUID authId, UserRequestDTO userRequestDTO, St } public List getClientsOfCoach(UUID coachAuthId){ - UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( - () -> new UserNotFoundException("Coach was not found with authId: " + coachAuthId)).getId(); + UUID coachId = findCoachByAuthIdOrElseThrow(coachAuthId).getId(); return coachClientAgreementService .getCoachClientAgreements(coachId) @@ -129,8 +134,8 @@ public List getClientsOfCoach(UUID coachAuthId){ } public List getCoachesOfClient(UUID clientAuthId) { - UUID clientId = userRepository.findByAuthId(clientAuthId).orElseThrow( - () -> new UserNotFoundException("Client was not found with authId: " + clientAuthId)).getId(); + UUID clientId = findUserByAuthIdOrElseThrow(clientAuthId).getId(); + return coachClientAgreementService .getCoachClientAgreements(clientId) @@ -141,76 +146,113 @@ public List getCoachesOfClient(UUID clientAuthId) { } public TrainingScheduleDto getClientTrainingSchedule(UUID clientId, UUID coachAuthId){ - UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( - () -> new UserNotFoundException("Coach was not found with authId: " + coachAuthId)) - .getId(); + UUID coachId = findCoachByAuthIdOrElseThrow(coachAuthId).getId(); if (!coachClientAgreementService.isUserAClientOfCoach(clientId, coachId)) { throw new UnauthorizedScheduleAccessException("The user with id: " + coachId + " is not a coach of user with id: " + clientId); } - TrainingSchedule schedule = userRepository.findById(clientId).orElseThrow( - () -> new UserNotFoundException("Client was not found with ID: " + clientId)).getTrainingSchedule(); + TrainingSchedule clientSchedule = + findUserByIdOrElseThrow(clientId).getTrainingSchedule(); - return TrainingScheduleMapper.toDto(schedule); + return TrainingScheduleMapper.toDto(clientSchedule); } public TrainingScheduleDto getTrainingSchedule(UUID authId){ - - TrainingSchedule schedule = - userRepository.findByAuthId(authId) - .orElseThrow( - () -> new UserNotFoundException("User not found with authId: " + authId)) - .getTrainingSchedule(); - + TrainingSchedule schedule = findUserByAuthIdOrElseThrow(authId).getTrainingSchedule(); return TrainingScheduleMapper.toDto(schedule); } public TrainingScheduleDto addWorkoutToSchedule(UUID clientAuthId, WorkoutRequestDto workoutDto) { - TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( - () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) - .getTrainingSchedule(); + TrainingSchedule trainingSchedule = + findUserByAuthIdOrElseThrow(clientAuthId).getTrainingSchedule(); return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingSchedule); } public TrainingScheduleDto addWorkoutToClientsSchedule(UUID coachAuthId, UUID clientId, WorkoutRequestDto workoutDto) { - UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( - () -> new UserNotFoundException("Coach not found with authId: " + coachAuthId)).getId(); + UUID coachId = findCoachByAuthIdOrElseThrow(coachAuthId).getId(); if(!coachClientAgreementService.isUserAClientOfCoach(clientId, coachId)){ throw new UnauthorizedScheduleAccessException("The user with id: " + coachId + " is not a coach of user with id: " + clientId); } - TrainingSchedule trainingSchedule = userRepository.findById(clientId).orElseThrow( - () -> new UserNotFoundException("User not found with id: " + clientId)).getTrainingSchedule(); + TrainingSchedule trainingSchedule = + findUserByIdOrElseThrow(clientId).getTrainingSchedule(); return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingSchedule); } public TrainingScheduleDto removeWorkoutFromClientSchedule(UUID coachAuthId, UUID clientId, UUID workoutId) { - UUID coachId = userRepository.findByAuthId(coachAuthId).orElseThrow( - () -> new UserNotFoundException("Coach not found with authId: " + coachAuthId)).getId(); + UUID coachId = findCoachByAuthIdOrElseThrow(coachAuthId).getId(); if(!coachClientAgreementService.isUserAClientOfCoach(clientId, coachId)){ throw new UnauthorizedScheduleAccessException("The user with id: " + coachId + " is not a coach of user with id: " + clientId); } - // .get should be fine here since above will throw if client user doesn't exist. - TrainingSchedule trainingSchedule = userRepository.findById(clientId).get().getTrainingSchedule(); + TrainingSchedule trainingSchedule = + findUserByIdOrElseThrow(clientId).getTrainingSchedule(); return trainingScheduleService.removeWorkoutFromSchedule(trainingSchedule, workoutId); } public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID workoutId) { - TrainingSchedule trainingSchedule = userRepository.findByAuthId(clientAuthId).orElseThrow( - () -> new UserNotFoundException("User not found with authID: " + clientAuthId)) - .getTrainingSchedule(); + TrainingSchedule trainingSchedule = + findUserByAuthIdOrElseThrow(clientAuthId).getTrainingSchedule(); return trainingScheduleService.removeWorkoutFromSchedule(trainingSchedule, workoutId); } + + + public CoachClientAgreementResponseDto proposeCoachClientAgreement(UUID coachAuthId, + UUID clientId, + CoachClientAgreementRequestDto agreementDto) { + + User coach = findCoachByAuthIdOrElseThrow(coachAuthId); + User client = findUserByIdOrElseThrow(clientId); + + return coachClientAgreementService + .proposeCoachClientAgreement(coach, client, agreementDto); + } + + public CoachClientAgreementResponseDto withdrawCoachesAgreementAcceptance(UUID coachAuthId, UUID agreementId) { + User coach = findCoachByAuthIdOrElseThrow(coachAuthId); + + CoachClientAgreement agreementToChange = + coach.getAgreementsAsCoach() + .stream() + .filter(a -> a.getId().equals(agreementId)) + .findFirst() + .orElseThrow(() -> + new CoachClientAgreementNotFoundException( + "Coach client agreement owned by coach id: " + + coach.getId() + " with agreement id: " + agreementId + " not found.")); + + return coachClientAgreementService.withdrawCoachesAgreementAcceptance(agreementToChange); + } + + private User findCoachByAuthIdOrElseThrow(UUID coachAuthId){ + return userRepository.findByAuthId(coachAuthId).orElseThrow( + () -> new UserNotFoundException("Coach user not found with authId:" + coachAuthId)); + } + + private User findUserByAuthIdOrElseThrow(UUID userAuthId){ + return userRepository.findByAuthId(userAuthId).orElseThrow( + () -> new UserNotFoundException("User not found with authId:" + userAuthId)); + } + + private User findUserByIdOrElseThrow(UUID userId){ + return userRepository.findById(userId).orElseThrow( + () -> new UserNotFoundException("User not found with authId:" + userId)); + } + + public AgreementTemplateResponseDto updateAgreementTemplate(UUID uuid, UUID uuid1, AgreementTemplateRequestDto templateRequestDto) { + } + + public List getCoachAgreementTemplates(UUID uuid) { + } } From cf43831350f2dc6549820076cc60057c5c851d11 Mon Sep 17 00:00:00 2001 From: Austin Snyder Date: Fri, 5 Dec 2025 15:25:44 -0800 Subject: [PATCH 12/12] changed docker to not run tests. And starting on actual integration testing --- .../contract/get-pending-agreements.http} | 0 ...cceptance-status-of-pending-agreement.http | 0 .../add-workout-to-schedule.http | 0 .../delete-workout-from-schedule.http | 0 .../{ => schedule}/get-training-schedule.http | 0 .../contract/propose-client-agreement.http | 0 .../template/create-agreement-template.http | 0 .../template/get-agreement-templates.http | 0 .../withdraw-coach-agreement-acceptance.http | 0 .../add-workout-to-client-schedule.http | 0 .../delete-workout-from-client-schedule.http | 0 .../coaches/schedule/get-client-schedule.http | 0 client-service/Dockerfile | 2 +- client-service/pom.xml | 34 ++- .../controller/ClientController.java | 45 ++- .../controller/CoachingController.java | 34 +-- .../CoachClientAgreementRequestDto.java | 6 +- .../CoachClientAgreementResponseDto.java | 1 + .../ContractAgreementStatusRequestDto.java | 12 + .../AgreementTemplateRequestDto.java | 2 +- .../AgreementTemplateResponseDto.java | 2 +- .../AgreementTemplateReuseRequestDto.java | 10 + .../exception/GlobalExceptionHandler.java | 2 + .../AgreementTemplateNotFoundException.java | 7 + ...CoachClientAgreementNotFoundException.java | 2 +- .../MovementNotFoundException.java | 2 +- .../TrainingScheduleNotFoundException.java | 2 +- .../UnauthorizedScheduleAccessException.java | 2 +- .../WorkoutNotFoundException.java | 2 +- .../EmailAlreadyExistsException.java | 2 +- .../{ => users}/UserNotFoundException.java | 2 +- .../contract/AgreementTemplateMapper.java | 13 +- .../contract/CoachClientAgreementMapper.java | 1 - .../mapper/schedule/MovementMapper.java | 2 - .../AgreementTemplateRepository.java | 12 + .../service/AgreementTemplateService.java | 48 +++ .../service/CoachClientAgreementService.java | 23 +- .../service/MovementService.java | 2 +- .../service/TrainingScheduleService.java | 12 +- .../cm/clientservice/service/UserService.java | 94 ++++-- .../CoachingControllerTests.java | 288 ++++++++++++++++++ .../test/java/CoachingIntegrationTests.java | 2 + ...ionTest.java => UserIntegrationTests.java} | 0 43 files changed, 559 insertions(+), 109 deletions(-) rename api-request/client-service/{coaches/get-client-schedule.http => clients/contract/get-pending-agreements.http} (100%) create mode 100644 api-request/client-service/clients/contract/set-acceptance-status-of-pending-agreement.http rename api-request/client-service/clients/{ => schedule}/add-workout-to-schedule.http (100%) rename api-request/client-service/clients/{ => schedule}/delete-workout-from-schedule.http (100%) rename api-request/client-service/clients/{ => schedule}/get-training-schedule.http (100%) create mode 100644 api-request/client-service/coaches/contract/propose-client-agreement.http create mode 100644 api-request/client-service/coaches/contract/template/create-agreement-template.http create mode 100644 api-request/client-service/coaches/contract/template/get-agreement-templates.http create mode 100644 api-request/client-service/coaches/contract/withdraw-coach-agreement-acceptance.http create mode 100644 api-request/client-service/coaches/schedule/add-workout-to-client-schedule.http create mode 100644 api-request/client-service/coaches/schedule/delete-workout-from-client-schedule.http create mode 100644 api-request/client-service/coaches/schedule/get-client-schedule.http create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/ContractAgreementStatusRequestDto.java rename client-service/src/main/java/com/cm/clientservice/dto/contract/{ => template}/AgreementTemplateRequestDto.java (92%) rename client-service/src/main/java/com/cm/clientservice/dto/contract/{ => template}/AgreementTemplateResponseDto.java (86%) create mode 100644 client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateReuseRequestDto.java create mode 100644 client-service/src/main/java/com/cm/clientservice/exception/contract/AgreementTemplateNotFoundException.java rename client-service/src/main/java/com/cm/clientservice/exception/{ => contract}/CoachClientAgreementNotFoundException.java (78%) rename client-service/src/main/java/com/cm/clientservice/exception/{ => schedule}/MovementNotFoundException.java (75%) rename client-service/src/main/java/com/cm/clientservice/exception/{ => schedule}/TrainingScheduleNotFoundException.java (77%) rename client-service/src/main/java/com/cm/clientservice/exception/{ => schedule}/UnauthorizedScheduleAccessException.java (77%) rename client-service/src/main/java/com/cm/clientservice/exception/{ => schedule}/WorkoutNotFoundException.java (75%) rename client-service/src/main/java/com/cm/clientservice/exception/{ => users}/EmailAlreadyExistsException.java (75%) rename client-service/src/main/java/com/cm/clientservice/exception/{ => users}/UserNotFoundException.java (75%) create mode 100644 client-service/src/main/java/com/cm/clientservice/repository/AgreementTemplateRepository.java create mode 100644 client-service/src/main/java/com/cm/clientservice/service/AgreementTemplateService.java create mode 100644 client-service/src/test/java/com/cm/clientservice/CoachingControllerTests.java create mode 100644 integration-testing/src/test/java/CoachingIntegrationTests.java rename integration-testing/src/test/java/{ClientIntegrationTest.java => UserIntegrationTests.java} (100%) diff --git a/api-request/client-service/coaches/get-client-schedule.http b/api-request/client-service/clients/contract/get-pending-agreements.http similarity index 100% rename from api-request/client-service/coaches/get-client-schedule.http rename to api-request/client-service/clients/contract/get-pending-agreements.http diff --git a/api-request/client-service/clients/contract/set-acceptance-status-of-pending-agreement.http b/api-request/client-service/clients/contract/set-acceptance-status-of-pending-agreement.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/clients/add-workout-to-schedule.http b/api-request/client-service/clients/schedule/add-workout-to-schedule.http similarity index 100% rename from api-request/client-service/clients/add-workout-to-schedule.http rename to api-request/client-service/clients/schedule/add-workout-to-schedule.http diff --git a/api-request/client-service/clients/delete-workout-from-schedule.http b/api-request/client-service/clients/schedule/delete-workout-from-schedule.http similarity index 100% rename from api-request/client-service/clients/delete-workout-from-schedule.http rename to api-request/client-service/clients/schedule/delete-workout-from-schedule.http diff --git a/api-request/client-service/clients/get-training-schedule.http b/api-request/client-service/clients/schedule/get-training-schedule.http similarity index 100% rename from api-request/client-service/clients/get-training-schedule.http rename to api-request/client-service/clients/schedule/get-training-schedule.http diff --git a/api-request/client-service/coaches/contract/propose-client-agreement.http b/api-request/client-service/coaches/contract/propose-client-agreement.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/coaches/contract/template/create-agreement-template.http b/api-request/client-service/coaches/contract/template/create-agreement-template.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/coaches/contract/template/get-agreement-templates.http b/api-request/client-service/coaches/contract/template/get-agreement-templates.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/coaches/contract/withdraw-coach-agreement-acceptance.http b/api-request/client-service/coaches/contract/withdraw-coach-agreement-acceptance.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/coaches/schedule/add-workout-to-client-schedule.http b/api-request/client-service/coaches/schedule/add-workout-to-client-schedule.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/coaches/schedule/delete-workout-from-client-schedule.http b/api-request/client-service/coaches/schedule/delete-workout-from-client-schedule.http new file mode 100644 index 0000000..e69de29 diff --git a/api-request/client-service/coaches/schedule/get-client-schedule.http b/api-request/client-service/coaches/schedule/get-client-schedule.http new file mode 100644 index 0000000..e69de29 diff --git a/client-service/Dockerfile b/client-service/Dockerfile index 96fe42e..6dd2232 100644 --- a/client-service/Dockerfile +++ b/client-service/Dockerfile @@ -8,7 +8,7 @@ RUN mvn dependency:go-offline -B COPY src ./src -RUN mvn clean package +RUN mvn clean package -DskipTests FROM openjdk:22-jdk AS runner diff --git a/client-service/pom.xml b/client-service/pom.xml index 4b74450..0784580 100644 --- a/client-service/pom.xml +++ b/client-service/pom.xml @@ -49,11 +49,7 @@ runtime true - - org.postgresql - postgresql - runtime - + org.springframework.boot spring-boot-starter-test @@ -84,9 +80,34 @@ jakarta.persistence-api 3.1.0 + + org.postgresql + postgresql + runtime + + + org.testcontainers + junit-jupiter + test + + + org.testcontainers + postgresql + test + - + + io.rest-assured + rest-assured + test + + + org.testcontainers + junit-jupiter + test + + @@ -97,4 +118,5 @@ + diff --git a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java index 8be10a4..4092f4d 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/ClientController.java @@ -1,30 +1,7 @@ package com.cm.clientservice.controller; - - -/** - * Spec: - * - * Coaches should be able to create a new Agreement Template for them to use - * - * - * - * Coaches should be able to propose a CoachClientAgreement to a user. - * - Require both parties to sign before continuing - * - Dependency on the BillingService to take billing info and schedule payments - * - * Coaches should be able to cancel a CoachClientAgreement - * - Notify the client of the cancelation - * - * Coaches should be able to propose edits to a CoachClientAgreement while running - * - Require both party signing to continue. - * - * Coaches should be able to - * - * - * - */ - import com.cm.clientservice.dto.UserResponseDTO; +import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; +import com.cm.clientservice.dto.contract.ContractAgreementStatusRequestDto; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; import com.cm.clientservice.service.UserService; @@ -76,4 +53,22 @@ public ResponseEntity addWorkoutToSchedule(@RequestHeader(" return ResponseEntity.ok().body(trainingScheduleDto); } + + @GetMapping("/agreements/pending") + public ResponseEntity> getPendingAgreements(@RequestHeader("X-AUTH-ID") String authId){ + List dtos = + userService.getPendingAgreements(UUID.fromString(authId)); + + return ResponseEntity.ok().body(dtos); + } + + @PutMapping("/agreements/{id}/status") + public ResponseEntity setAcceptanceStatusOfPendingAgreement(@RequestHeader("X-AUTH-ID") String authId, + @RequestBody ContractAgreementStatusRequestDto requestDto, + @PathVariable String id){ + CoachClientAgreementResponseDto responseDto = + userService.setAcceptanceStatusOfPendingAgreement(UUID.fromString(authId), UUID.fromString(id), requestDto); + + return ResponseEntity.ok().body(responseDto); + } } diff --git a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java index 3bf7d54..a2b0337 100644 --- a/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java +++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java @@ -1,15 +1,11 @@ package com.cm.clientservice.controller; - -import com.cm.clientservice.dto.UserRequestDTO; import com.cm.clientservice.dto.UserResponseDTO; -import com.cm.clientservice.dto.contract.AgreementTemplateRequestDto; -import com.cm.clientservice.dto.contract.AgreementTemplateResponseDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateRequestDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateResponseDto; import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; -import com.cm.clientservice.model.contract.AgreementTemplate; -import com.cm.clientservice.model.contract.CoachClientAgreement; import com.cm.clientservice.service.UserService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,7 +15,8 @@ import java.util.List; import java.util.UUID; -@RestController("clients/coaching") +@RestController +@RequestMapping("clients/coaching") @Tag(name = "coaching", description = "API for coaching management.") public class CoachingController { @@ -85,8 +82,8 @@ public ResponseEntity proposeClientAgreement(@R @PutMapping("/agreement/withdraw/{agreementId}") public ResponseEntity withdrawCoachesAgreementAcceptance(@RequestHeader("X-AUTH-ID") String coachAuthId, @PathVariable String agreementId){ - // Alert the user they have been dropped. - // Alert billing service that the contract is being terminated. + //TODO: Alert user of withdrawal. + //TODO: Alert billing service of end of contract. CoachClientAgreementResponseDto dto = userService.withdrawCoachesAgreementAcceptance(UUID.fromString(coachAuthId), UUID.fromString(agreementId)); @@ -97,32 +94,17 @@ public ResponseEntity withdrawCoachesAgreementA @PostMapping("/templates") public ResponseEntity createAgreementTemplate(@RequestHeader("X-AUTH-ID") String coachAuthId, @RequestBody AgreementTemplateRequestDto templateRequestDto){ - - return ResponseEntity.ok().body(dto); - } - - // TODO: This should be accessed only by accounts that have a coaching profile - public ResponseEntity deleteAgreementTemplate(){ - return ResponseEntity.ok().build(); - } - - @PutMapping("/templates/template/{templateId}/update") - public ResponseEntity updateAgreementTemplate(@RequestHeader("X-AUTH-ID") String coachAuthId, - @RequestBody AgreementTemplateRequestDto templateRequestDto, - @PathVariable String templateId){ AgreementTemplateResponseDto dto = - //TODO: Add a validation group ot the request dto to make it optional for each of the fields. - userService.updateAgreementTemplate(UUID.fromString(coachAuthId), UUID.fromString(templateId), templateRequestDto); + userService.createAgreementTemplate(UUID.fromString(coachAuthId), templateRequestDto); return ResponseEntity.ok().body(dto); } @GetMapping("/templates") - public ResponseEntity> getCoachAgreementTemplates(@RequestHeader("X-AUTH-ID") String coachAuthId){ + public ResponseEntity> getCoachesAgreementTemplates(@RequestHeader("X-AUTH-ID") String coachAuthId){ List dtoList = userService.getCoachAgreementTemplates(UUID.fromString(coachAuthId)); - return ResponseEntity.ok().body(dtoList); } } diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java index d48df35..061cc3a 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java @@ -1,5 +1,5 @@ package com.cm.clientservice.dto.contract; - +import com.cm.clientservice.dto.contract.template.AgreementTemplateReuseRequestDto; import jakarta.validation.constraints.NotNull; import lombok.Getter; import lombok.Setter; @@ -7,10 +7,8 @@ @Getter @Setter public class CoachClientAgreementRequestDto { - @NotNull - private String clientId; @NotNull private String startDate; @NotNull - private AgreementTemplateRequestDto agreementTemplateDto; + private AgreementTemplateReuseRequestDto template; } diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java index edc88d8..2eb206b 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java @@ -1,5 +1,6 @@ package com.cm.clientservice.dto.contract; +import com.cm.clientservice.dto.contract.template.AgreementTemplateResponseDto; import lombok.Getter; import lombok.Setter; diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/ContractAgreementStatusRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/ContractAgreementStatusRequestDto.java new file mode 100644 index 0000000..af1c0ec --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/ContractAgreementStatusRequestDto.java @@ -0,0 +1,12 @@ +package com.cm.clientservice.dto.contract; + +import jakarta.validation.constraints.NotBlank; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class ContractAgreementStatusRequestDto { + @NotBlank + private Boolean userIsInAgreement; +} diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateRequestDto.java similarity index 92% rename from client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateRequestDto.java rename to client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateRequestDto.java index b4e077c..e63fa14 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateRequestDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateRequestDto.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.dto.contract; +package com.cm.clientservice.dto.contract.template; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateResponseDto.java similarity index 86% rename from client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateResponseDto.java rename to client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateResponseDto.java index 8e0273b..e73c415 100644 --- a/client-service/src/main/java/com/cm/clientservice/dto/contract/AgreementTemplateResponseDto.java +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateResponseDto.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.dto.contract; +package com.cm.clientservice.dto.contract.template; import lombok.Getter; import lombok.Setter; diff --git a/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateReuseRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateReuseRequestDto.java new file mode 100644 index 0000000..2347b24 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateReuseRequestDto.java @@ -0,0 +1,10 @@ +package com.cm.clientservice.dto.contract.template; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class AgreementTemplateReuseRequestDto { + private String id; +} diff --git a/client-service/src/main/java/com/cm/clientservice/exception/GlobalExceptionHandler.java b/client-service/src/main/java/com/cm/clientservice/exception/GlobalExceptionHandler.java index 4459c3a..e8b54a6 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/GlobalExceptionHandler.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/GlobalExceptionHandler.java @@ -1,4 +1,6 @@ package com.cm.clientservice.exception; +import com.cm.clientservice.exception.users.EmailAlreadyExistsException; +import com.cm.clientservice.exception.users.UserNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; diff --git a/client-service/src/main/java/com/cm/clientservice/exception/contract/AgreementTemplateNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/contract/AgreementTemplateNotFoundException.java new file mode 100644 index 0000000..402cccb --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/exception/contract/AgreementTemplateNotFoundException.java @@ -0,0 +1,7 @@ +package com.cm.clientservice.exception.contract; + +public class AgreementTemplateNotFoundException extends RuntimeException{ + public AgreementTemplateNotFoundException(String message) { + super(message); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/exception/CoachClientAgreementNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/contract/CoachClientAgreementNotFoundException.java similarity index 78% rename from client-service/src/main/java/com/cm/clientservice/exception/CoachClientAgreementNotFoundException.java rename to client-service/src/main/java/com/cm/clientservice/exception/contract/CoachClientAgreementNotFoundException.java index 288aabe..0e3d2bf 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/CoachClientAgreementNotFoundException.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/contract/CoachClientAgreementNotFoundException.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.exception; +package com.cm.clientservice.exception.contract; public class CoachClientAgreementNotFoundException extends RuntimeException{ public CoachClientAgreementNotFoundException(String message){ diff --git a/client-service/src/main/java/com/cm/clientservice/exception/MovementNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/MovementNotFoundException.java similarity index 75% rename from client-service/src/main/java/com/cm/clientservice/exception/MovementNotFoundException.java rename to client-service/src/main/java/com/cm/clientservice/exception/schedule/MovementNotFoundException.java index 4ed2440..d0da5dd 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/MovementNotFoundException.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/MovementNotFoundException.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.exception; +package com.cm.clientservice.exception.schedule; public class MovementNotFoundException extends RuntimeException { public MovementNotFoundException(String message){ diff --git a/client-service/src/main/java/com/cm/clientservice/exception/TrainingScheduleNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/TrainingScheduleNotFoundException.java similarity index 77% rename from client-service/src/main/java/com/cm/clientservice/exception/TrainingScheduleNotFoundException.java rename to client-service/src/main/java/com/cm/clientservice/exception/schedule/TrainingScheduleNotFoundException.java index 1e416a1..b8b2520 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/TrainingScheduleNotFoundException.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/TrainingScheduleNotFoundException.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.exception; +package com.cm.clientservice.exception.schedule; public class TrainingScheduleNotFoundException extends RuntimeException{ public TrainingScheduleNotFoundException(String message){ diff --git a/client-service/src/main/java/com/cm/clientservice/exception/UnauthorizedScheduleAccessException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/UnauthorizedScheduleAccessException.java similarity index 77% rename from client-service/src/main/java/com/cm/clientservice/exception/UnauthorizedScheduleAccessException.java rename to client-service/src/main/java/com/cm/clientservice/exception/schedule/UnauthorizedScheduleAccessException.java index fe62e61..3358115 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/UnauthorizedScheduleAccessException.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/UnauthorizedScheduleAccessException.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.exception; +package com.cm.clientservice.exception.schedule; public class UnauthorizedScheduleAccessException extends RuntimeException{ public UnauthorizedScheduleAccessException(String message){ diff --git a/client-service/src/main/java/com/cm/clientservice/exception/WorkoutNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/WorkoutNotFoundException.java similarity index 75% rename from client-service/src/main/java/com/cm/clientservice/exception/WorkoutNotFoundException.java rename to client-service/src/main/java/com/cm/clientservice/exception/schedule/WorkoutNotFoundException.java index 90fd28e..be2ac6f 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/WorkoutNotFoundException.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/WorkoutNotFoundException.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.exception; +package com.cm.clientservice.exception.schedule; public class WorkoutNotFoundException extends RuntimeException{ public WorkoutNotFoundException(String message){ diff --git a/client-service/src/main/java/com/cm/clientservice/exception/EmailAlreadyExistsException.java b/client-service/src/main/java/com/cm/clientservice/exception/users/EmailAlreadyExistsException.java similarity index 75% rename from client-service/src/main/java/com/cm/clientservice/exception/EmailAlreadyExistsException.java rename to client-service/src/main/java/com/cm/clientservice/exception/users/EmailAlreadyExistsException.java index 5466152..45d0ba4 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/EmailAlreadyExistsException.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/users/EmailAlreadyExistsException.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.exception; +package com.cm.clientservice.exception.users; public class EmailAlreadyExistsException extends RuntimeException{ public EmailAlreadyExistsException(String message) {super(message);} diff --git a/client-service/src/main/java/com/cm/clientservice/exception/UserNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/users/UserNotFoundException.java similarity index 75% rename from client-service/src/main/java/com/cm/clientservice/exception/UserNotFoundException.java rename to client-service/src/main/java/com/cm/clientservice/exception/users/UserNotFoundException.java index b02db8b..af5250c 100644 --- a/client-service/src/main/java/com/cm/clientservice/exception/UserNotFoundException.java +++ b/client-service/src/main/java/com/cm/clientservice/exception/users/UserNotFoundException.java @@ -1,4 +1,4 @@ -package com.cm.clientservice.exception; +package com.cm.clientservice.exception.users; public class UserNotFoundException extends RuntimeException{ public UserNotFoundException(String message){ diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java index c3139e4..df8f206 100644 --- a/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java +++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java @@ -1,9 +1,11 @@ package com.cm.clientservice.mapper.contract; -import com.cm.clientservice.dto.contract.AgreementTemplateRequestDto; -import com.cm.clientservice.dto.contract.AgreementTemplateResponseDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateRequestDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateResponseDto; import com.cm.clientservice.model.contract.AgreementTemplate; +import java.util.List; + public class AgreementTemplateMapper { public static AgreementTemplateResponseDto toDto(AgreementTemplate agreementTemplate){ @@ -20,6 +22,13 @@ public static AgreementTemplateResponseDto toDto(AgreementTemplate agreementTemp return dto; } + public static List toDto(List agreementTemplates){ + return agreementTemplates + .stream() + .map(AgreementTemplateMapper::toDto) + .toList(); + } + public static AgreementTemplate toModel(AgreementTemplateRequestDto dto) { AgreementTemplate template = new AgreementTemplate(); diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java index a87a23e..d121607 100644 --- a/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java +++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java @@ -23,7 +23,6 @@ public static CoachClientAgreementResponseDto toDto(CoachClientAgreement agreeme public static CoachClientAgreement toModel(CoachClientAgreementRequestDto dto){ CoachClientAgreement agreement = new CoachClientAgreement(); - agreement.setAgreementTemplate(AgreementTemplateMapper.toModel(dto.getAgreementTemplateDto())); agreement.setClientIsInAgreement(Boolean.FALSE); agreement.setCoachIsInAgreement(Boolean.TRUE); agreement.setStartDate(LocalDate.parse(dto.getStartDate())); diff --git a/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java index 08c7576..0003819 100644 --- a/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java +++ b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java @@ -17,9 +17,7 @@ public static MovementResponseDto toDto(Movement movement){ public static Movement toModel(MovementReuseRequestDto movementDto) { Movement movement = new Movement(); - movement.setId(UUID.fromString(movementDto.getId())); - return movement; } } diff --git a/client-service/src/main/java/com/cm/clientservice/repository/AgreementTemplateRepository.java b/client-service/src/main/java/com/cm/clientservice/repository/AgreementTemplateRepository.java new file mode 100644 index 0000000..4189568 --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/repository/AgreementTemplateRepository.java @@ -0,0 +1,12 @@ +package com.cm.clientservice.repository; + +import com.cm.clientservice.model.contract.AgreementTemplate; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; + +import java.util.UUID; + +public interface AgreementTemplateRepository extends JpaRepository { + + List findAllByAuthor_Id(UUID authorId); +} diff --git a/client-service/src/main/java/com/cm/clientservice/service/AgreementTemplateService.java b/client-service/src/main/java/com/cm/clientservice/service/AgreementTemplateService.java new file mode 100644 index 0000000..f1efb4d --- /dev/null +++ b/client-service/src/main/java/com/cm/clientservice/service/AgreementTemplateService.java @@ -0,0 +1,48 @@ +package com.cm.clientservice.service; + +import com.cm.clientservice.dto.contract.template.AgreementTemplateRequestDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateResponseDto; +import com.cm.clientservice.exception.contract.AgreementTemplateNotFoundException; +import com.cm.clientservice.mapper.contract.AgreementTemplateMapper; +import com.cm.clientservice.model.User; +import com.cm.clientservice.model.contract.AgreementTemplate; +import com.cm.clientservice.repository.AgreementTemplateRepository; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +@Service +public class AgreementTemplateService { + + private final AgreementTemplateRepository agreementTemplateRepository; + + public AgreementTemplateService(AgreementTemplateRepository agreementTemplateRepository) { + this.agreementTemplateRepository = agreementTemplateRepository; + } + + public AgreementTemplateResponseDto createAgreementTemplate(User author, + AgreementTemplateRequestDto templateRequestDto){ + + AgreementTemplate template = + AgreementTemplateMapper.toModel(templateRequestDto); + + template.setAuthor(author); + template.setVersion(1); + + AgreementTemplate createdAgreement = + agreementTemplateRepository.save(template); + + return AgreementTemplateMapper.toDto(createdAgreement); + } + + public List findAgreementsAuthoredByCoach(User coach) { + List templates = agreementTemplateRepository.findAllByAuthor_Id(coach.getId()); + return AgreementTemplateMapper.toDto(templates); + } + + public AgreementTemplate findTemplateForContractUse(UUID id) { + return agreementTemplateRepository.findById(id).orElseThrow( + () -> new AgreementTemplateNotFoundException("Agreement template not found with id: " + id)); + } +} diff --git a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java index 7487abf..329a64b 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java @@ -1,13 +1,14 @@ package com.cm.clientservice.service; import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; +import com.cm.clientservice.dto.contract.ContractAgreementStatusRequestDto; import com.cm.clientservice.mapper.contract.CoachClientAgreementMapper; import com.cm.clientservice.model.User; +import com.cm.clientservice.model.contract.AgreementTemplate; import com.cm.clientservice.model.contract.CoachClientAgreement; import com.cm.clientservice.repository.CoachClientAgreementRepository; import org.springframework.stereotype.Service; -import java.time.LocalDate; import java.util.List; import java.util.UUID; @@ -15,9 +16,12 @@ public class CoachClientAgreementService { private final CoachClientAgreementRepository coachClientAgreementRepository; + private final AgreementTemplateService agreementTemplateService; - public CoachClientAgreementService(CoachClientAgreementRepository coachClientAgreementRepository){ + public CoachClientAgreementService(CoachClientAgreementRepository coachClientAgreementRepository, + AgreementTemplateService agreementTemplateService){ this.coachClientAgreementRepository = coachClientAgreementRepository; + this.agreementTemplateService = agreementTemplateService; } public List getCoachClientAgreements(UUID coachId){ @@ -41,14 +45,29 @@ public CoachClientAgreementResponseDto proposeCoachClientAgreement(User coach, U agreement.setCoach(coach); agreement.setClient(client); + agreement.setAgreementTemplate(agreementTemplateService.findTemplateForContractUse(UUID.fromString(agreementDto.getTemplate().getId()))); coachClientAgreementRepository.save(agreement); return CoachClientAgreementMapper.toDto(agreement); } public CoachClientAgreementResponseDto withdrawCoachesAgreementAcceptance(CoachClientAgreement agreementToChange) { + //TODO: Alter this to mirror the client one. agreementToChange.setCoachIsInAgreement(Boolean.FALSE); CoachClientAgreement updatedAgreement = coachClientAgreementRepository.save(agreementToChange); return CoachClientAgreementMapper.toDto(updatedAgreement); } + + public Boolean isAgreementPending(CoachClientAgreement agreement){ + return agreement.getClientIsInAgreement().equals(Boolean.FALSE); + } + + public CoachClientAgreementResponseDto setClientAgreementStatus(CoachClientAgreement agreementToChange, + ContractAgreementStatusRequestDto statusUpdateRequest){ + + agreementToChange.setClientIsInAgreement(statusUpdateRequest.getUserIsInAgreement()); + CoachClientAgreement updatedAgreement = coachClientAgreementRepository.save(agreementToChange); + return CoachClientAgreementMapper.toDto(updatedAgreement); + } + } diff --git a/client-service/src/main/java/com/cm/clientservice/service/MovementService.java b/client-service/src/main/java/com/cm/clientservice/service/MovementService.java index cbebda8..3779aa8 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/MovementService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/MovementService.java @@ -2,7 +2,7 @@ import com.cm.clientservice.dto.scheduling.movement.MovementCreateRequestDto; import com.cm.clientservice.dto.scheduling.movement.MovementResponseDto; -import com.cm.clientservice.exception.MovementNotFoundException; +import com.cm.clientservice.exception.schedule.MovementNotFoundException; import com.cm.clientservice.mapper.schedule.MovementMapper; import com.cm.clientservice.model.schedule.Movement; import com.cm.clientservice.repository.MovementRepository; diff --git a/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java index a1d1ad4..08cf832 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java @@ -2,12 +2,14 @@ import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; -import com.cm.clientservice.exception.WorkoutNotFoundException; +import com.cm.clientservice.exception.schedule.TrainingScheduleNotFoundException; +import com.cm.clientservice.exception.schedule.WorkoutNotFoundException; import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; import com.cm.clientservice.mapper.schedule.WorkoutMapper; import com.cm.clientservice.model.schedule.TrainingSchedule; import com.cm.clientservice.model.schedule.Workout; import com.cm.clientservice.repository.TrainingScheduleRepository; +import jakarta.transaction.Transactional; import org.springframework.stereotype.Service; import java.util.List; @@ -22,6 +24,7 @@ public TrainingScheduleService(TrainingScheduleRepository trainingScheduleReposi this.trainingScheduleRepository = trainingScheduleRepository; } + @Transactional public TrainingScheduleDto removeWorkoutFromSchedule(TrainingSchedule schedule, UUID workoutId){ List workouts = schedule.getWorkouts(); @@ -38,8 +41,13 @@ public TrainingScheduleDto removeWorkoutFromSchedule(TrainingSchedule schedule, return TrainingScheduleMapper.toDto(updatedSchedule); } - public TrainingScheduleDto addWorkoutToSchedule(WorkoutRequestDto workoutDto, TrainingSchedule trainingSchedule){ + @Transactional + public TrainingScheduleDto addWorkoutToSchedule(WorkoutRequestDto workoutDto, UUID trainingScheduleId){ Workout workout = WorkoutMapper.toModel(workoutDto); + + TrainingSchedule trainingSchedule = trainingScheduleRepository.findById(trainingScheduleId).orElseThrow( + () -> new TrainingScheduleNotFoundException("Training schedule not found with id: " + trainingScheduleId)); + workout.setTrainingSchedule(trainingSchedule); trainingSchedule.getWorkouts().add(workout); diff --git a/client-service/src/main/java/com/cm/clientservice/service/UserService.java b/client-service/src/main/java/com/cm/clientservice/service/UserService.java index 344d314..233c3f3 100644 --- a/client-service/src/main/java/com/cm/clientservice/service/UserService.java +++ b/client-service/src/main/java/com/cm/clientservice/service/UserService.java @@ -3,22 +3,22 @@ import com.cm.clientservice.dto.OutgoingEmailUpdateDTO; import com.cm.clientservice.dto.UserRequestDTO; import com.cm.clientservice.dto.UserResponseDTO; -import com.cm.clientservice.dto.contract.AgreementTemplateRequestDto; -import com.cm.clientservice.dto.contract.AgreementTemplateResponseDto; -import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; -import com.cm.clientservice.dto.contract.CoachClientAgreementResponseDto; +import com.cm.clientservice.dto.contract.*; +import com.cm.clientservice.dto.contract.template.AgreementTemplateRequestDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateResponseDto; import com.cm.clientservice.dto.scheduling.TrainingScheduleDto; import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; -import com.cm.clientservice.exception.CoachClientAgreementNotFoundException; -import com.cm.clientservice.exception.EmailAlreadyExistsException; -import com.cm.clientservice.exception.UnauthorizedScheduleAccessException; -import com.cm.clientservice.exception.UserNotFoundException; +import com.cm.clientservice.exception.contract.CoachClientAgreementNotFoundException; +import com.cm.clientservice.exception.users.EmailAlreadyExistsException; +import com.cm.clientservice.exception.schedule.UnauthorizedScheduleAccessException; +import com.cm.clientservice.exception.users.UserNotFoundException; import com.cm.clientservice.mapper.contract.CoachClientAgreementMapper; import com.cm.clientservice.mapper.schedule.TrainingScheduleMapper; import com.cm.clientservice.mapper.UserMapper; import com.cm.clientservice.model.contract.CoachClientAgreement; import com.cm.clientservice.model.schedule.TrainingSchedule; import com.cm.clientservice.repository.UserRepository; +import jakarta.transaction.Transactional; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; @@ -35,21 +35,41 @@ public class UserService { private final UserRepository userRepository; private final CoachClientAgreementService coachClientAgreementService; private final TrainingScheduleService trainingScheduleService; + private final AgreementTemplateService agreementTemplateService; private final WebClient webClient; public UserService(UserRepository userRepository, WebClient.Builder webClientBuilder, @Value("${auth.service.url}") String authServiceUrl, CoachClientAgreementService coachClientAgreementService, - TrainingScheduleService trainingScheduleService){ + TrainingScheduleService trainingScheduleService, + AgreementTemplateService agreementTemplateService){ this.userRepository = userRepository; + this.agreementTemplateService = agreementTemplateService; this.webClient = webClientBuilder.baseUrl(authServiceUrl).build(); this.coachClientAgreementService = coachClientAgreementService; this.trainingScheduleService = trainingScheduleService; } + private User findCoachByAuthIdOrElseThrow(UUID coachAuthId){ + return userRepository.findByAuthId(coachAuthId).orElseThrow( + () -> new UserNotFoundException("Coach user not found with authId:" + coachAuthId)); + } + + private User findUserByAuthIdOrElseThrow(UUID userAuthId){ + return userRepository.findByAuthId(userAuthId).orElseThrow( + () -> new UserNotFoundException("User not found with authId:" + userAuthId)); + } + + private User findUserByIdOrElseThrow(UUID userId){ + return userRepository.findById(userId).orElseThrow( + () -> new UserNotFoundException("User not found with authId:" + userId)); + } + + + public UserResponseDTO createUser(UserRequestDTO userRequestDTO, String auth_id){ // Make a call to the repository to create a user. if(userRepository.existsByEmail(userRequestDTO.getEmail())){ @@ -165,10 +185,10 @@ public TrainingScheduleDto getTrainingSchedule(UUID authId){ public TrainingScheduleDto addWorkoutToSchedule(UUID clientAuthId, WorkoutRequestDto workoutDto) { - TrainingSchedule trainingSchedule = - findUserByAuthIdOrElseThrow(clientAuthId).getTrainingSchedule(); + UUID trainingScheduleId = + findUserByAuthIdOrElseThrow(clientAuthId).getTrainingSchedule().getId(); - return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingSchedule); + return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingScheduleId); } @@ -179,12 +199,13 @@ public TrainingScheduleDto addWorkoutToClientsSchedule(UUID coachAuthId, UUID cl throw new UnauthorizedScheduleAccessException("The user with id: " + coachId + " is not a coach of user with id: " + clientId); } - TrainingSchedule trainingSchedule = - findUserByIdOrElseThrow(clientId).getTrainingSchedule(); + UUID trainingScheduleId = + findUserByIdOrElseThrow(clientId).getTrainingSchedule().getId(); - return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingSchedule); + return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingScheduleId); } + public TrainingScheduleDto removeWorkoutFromClientSchedule(UUID coachAuthId, UUID clientId, UUID workoutId) { UUID coachId = findCoachByAuthIdOrElseThrow(coachAuthId).getId(); @@ -198,7 +219,6 @@ public TrainingScheduleDto removeWorkoutFromClientSchedule(UUID coachAuthId, UUI return trainingScheduleService.removeWorkoutFromSchedule(trainingSchedule, workoutId); } - public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID workoutId) { TrainingSchedule trainingSchedule = @@ -235,24 +255,42 @@ public CoachClientAgreementResponseDto withdrawCoachesAgreementAcceptance(UUID c return coachClientAgreementService.withdrawCoachesAgreementAcceptance(agreementToChange); } - private User findCoachByAuthIdOrElseThrow(UUID coachAuthId){ - return userRepository.findByAuthId(coachAuthId).orElseThrow( - () -> new UserNotFoundException("Coach user not found with authId:" + coachAuthId)); - } + public List getCoachAgreementTemplates(UUID coachAuthId) { + User coach = findCoachByAuthIdOrElseThrow(coachAuthId); + return agreementTemplateService.findAgreementsAuthoredByCoach(coach); - private User findUserByAuthIdOrElseThrow(UUID userAuthId){ - return userRepository.findByAuthId(userAuthId).orElseThrow( - () -> new UserNotFoundException("User not found with authId:" + userAuthId)); } - private User findUserByIdOrElseThrow(UUID userId){ - return userRepository.findById(userId).orElseThrow( - () -> new UserNotFoundException("User not found with authId:" + userId)); + public AgreementTemplateResponseDto createAgreementTemplate(UUID coachAuthId, AgreementTemplateRequestDto templateRequestDto) { + User coach = findCoachByAuthIdOrElseThrow(coachAuthId); + return agreementTemplateService.createAgreementTemplate(coach, templateRequestDto); } - public AgreementTemplateResponseDto updateAgreementTemplate(UUID uuid, UUID uuid1, AgreementTemplateRequestDto templateRequestDto) { + public List getPendingAgreements(UUID authId) { + UUID userId = findUserByAuthIdOrElseThrow(authId).getId(); + + return coachClientAgreementService + .getCoachClientAgreements(userId) + .stream() + .filter(coachClientAgreementService::isAgreementPending) + .map(CoachClientAgreementMapper::toDto) + .toList(); } - public List getCoachAgreementTemplates(UUID uuid) { + @Transactional + public CoachClientAgreementResponseDto setAcceptanceStatusOfPendingAgreement(UUID clientAuthId, UUID agreementId, ContractAgreementStatusRequestDto agreementRequest) { + User client = findUserByAuthIdOrElseThrow(clientAuthId); + + CoachClientAgreement agreementToChange = + client.getAgreementsAsClient() + .stream() + .filter(a -> a.getId().equals(agreementId)) + .findFirst() + .orElseThrow(() -> + new CoachClientAgreementNotFoundException( + "Coach client agreement owned by user id: " + + client.getId() + " with agreement id: " + agreementId + " not found.")); + + return coachClientAgreementService.setClientAgreementStatus(agreementToChange, agreementRequest); } } diff --git a/client-service/src/test/java/com/cm/clientservice/CoachingControllerTests.java b/client-service/src/test/java/com/cm/clientservice/CoachingControllerTests.java new file mode 100644 index 0000000..7ee06fa --- /dev/null +++ b/client-service/src/test/java/com/cm/clientservice/CoachingControllerTests.java @@ -0,0 +1,288 @@ +package com.cm.clientservice; +import com.cm.clientservice.dto.UserRequestDTO; +import com.cm.clientservice.dto.contract.CoachClientAgreementRequestDto; +import com.cm.clientservice.dto.contract.ContractAgreementStatusRequestDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateRequestDto; +import com.cm.clientservice.dto.contract.template.AgreementTemplateReuseRequestDto; +import com.cm.clientservice.dto.scheduling.exercise.ExerciseRequestDto; +import com.cm.clientservice.dto.scheduling.movement.MovementCreateRequestDto; +import com.cm.clientservice.dto.scheduling.movement.MovementResponseDto; +import com.cm.clientservice.dto.scheduling.movement.MovementReuseRequestDto; +import com.cm.clientservice.dto.scheduling.workout.WorkoutRequestDto; +import com.cm.clientservice.model.User; +import com.cm.clientservice.repository.UserRepository; +import com.cm.clientservice.service.AgreementTemplateService; +import com.cm.clientservice.service.CoachClientAgreementService; +import com.cm.clientservice.service.MovementService; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; + +import java.util.List; +import java.util.UUID; + +import io.restassured.response.Response; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.PostgreSQLContainer; +import com.cm.clientservice.service.UserService; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Testcontainers +public class CoachingControllerTests { + + @LocalServerPort + private Integer port; + + @Autowired + private UserService userService; + + @Autowired + private UserRepository userRepository; + + @Autowired + private CoachClientAgreementService coachClientAgreementService; + + @Autowired + private AgreementTemplateService agreementTemplateService; + + @Autowired + MovementService movementService; + + @Container + static PostgreSQLContainer postgres = + new PostgreSQLContainer<>("postgres:latest") + .withDatabaseName("testdb") + .withUsername("user") + .withPassword("pass"); + + @DynamicPropertySource + static void configureProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgres::getJdbcUrl); + registry.add("spring.datasource.username", postgres::getUsername); + registry.add("spring.datasource.password", postgres::getPassword); + registry.add("spring.jpa.hibernate.ddl-auto", () -> "update"); + registry.add("spring.jpa.hibernate.ddl-auto", () -> "create-drop"); + registry.add("spring.datasource.driver-class-name", () -> "org.postgresql.Driver"); + } + + @BeforeEach + void setUp(){ + RestAssured.baseURI = "http://localhost:" + port + "/clients/coaching"; + userRepository.deleteAll(); + } + + UUID createCoachUserInDbReturnAuthId(){ + UserRequestDTO userRequest = new UserRequestDTO(); + userRequest.setAddress("225 TestCoach Lane, Testville, 45135, Testax, United States of Testing."); + userRequest.setEmail("test_coach@test.com"); + userRequest.setDateOfBirth("1970-01-01"); + userRequest.setFirstName("Test"); + userRequest.setLastName("Coach"); + userRequest.setRegisteredDate("2025-10-10"); + + UUID mockAuthId = UUID.randomUUID(); + + userService.createUser(userRequest, String.valueOf(mockAuthId)); + return mockAuthId; + } + + UUID createClientUserInDBReturnAuthId(){ + UserRequestDTO userRequest = new UserRequestDTO(); + userRequest.setAddress("45 TestClient Lane, Testville, 45135, Testax, United States of Testing."); + userRequest.setEmail("test_client@test.com"); + userRequest.setDateOfBirth("1970-01-01"); + userRequest.setFirstName("Test"); + userRequest.setLastName("Client"); + userRequest.setRegisteredDate("2025-09-09"); + + UUID mockAuthId = UUID.randomUUID(); + + userService.createUser(userRequest, String.valueOf(mockAuthId)); + return mockAuthId; + } + + UUID createMockMovementReturnId(){ + // make movement + MovementCreateRequestDto dto = new MovementCreateRequestDto(); + dto.setDescription("This is a fake movement."); + dto.setName("Test Movement"); + + // return id of created. + MovementResponseDto responseDto = movementService.createMovement(dto); + return UUID.fromString(responseDto.getId()); + } + + ExerciseRequestDto createExerciseRequestDto(UUID movementId){ + // movement + MovementReuseRequestDto movementReuse = new MovementReuseRequestDto(); + movementReuse.setId(String.valueOf(movementId)); + + // exercise + ExerciseRequestDto dto = new ExerciseRequestDto(); + dto.setMovement(movementReuse); + dto.setCoachNotes("Mock Coach Notes"); + dto.setNumReps("1"); + dto.setNumSets("2"); + return dto; + } + + UUID createWorkoutInUserScheduleAndReturnScheduleId(User client, List exerciseRequestDtos){ + WorkoutRequestDto dto = new WorkoutRequestDto(); + dto.setDate("2025-05-05"); + dto.setWorkoutNotes("Test workout notes"); + dto.setIsCompleted("TRUE"); + dto.setExercises(exerciseRequestDtos); + dto.setTrainingScheduleId(String.valueOf(client.getTrainingSchedule().getId())); + UUID scheduleId = UUID.fromString(userService.addWorkoutToSchedule(client.getAuthId(), dto).getId()); + return scheduleId; + } + + UUID createCoachClientAgreementBetweenCoachAndClientReturnId(UUID coachAuth, UUID clientAuth) { + User coach = userRepository.findByAuthId(coachAuth).get(); + User client = userRepository.findByAuthId(clientAuth).get(); + + // template + AgreementTemplateReuseRequestDto template = new AgreementTemplateReuseRequestDto(); + UUID templateId = createMockAgreementTemplateReturnId(coach); + template.setId(templateId.toString()); + + // request + CoachClientAgreementRequestDto requestDto = new CoachClientAgreementRequestDto(); + requestDto.setStartDate("2025-05-05"); + requestDto.setTemplate(template); + + // agreement + UUID agreementId = UUID.fromString(coachClientAgreementService.proposeCoachClientAgreement(coach, client, requestDto).getId()); + + // client accept + ContractAgreementStatusRequestDto status = new ContractAgreementStatusRequestDto(); + status.setUserIsInAgreement(Boolean.TRUE); + userService.setAcceptanceStatusOfPendingAgreement(clientAuth, agreementId, status); + + return agreementId; + } + + UUID createMockAgreementTemplateReturnId(User coach){ + AgreementTemplateRequestDto dto = new AgreementTemplateRequestDto(); + dto.setTemplateName("Mock Template"); + dto.setPaymentAmount("100.00"); + dto.setDaysBetweenPayments("10"); + dto.setAllowPublicTemplateReuse("TRUE"); + dto.setTermsAndConditions("Mock terms"); + + return UUID.fromString(agreementTemplateService.createAgreementTemplate(coach, dto).getId()); + } + + + + // getClients + @Test + public void getClientsWithNoClientsShouldReturnEmptyList() { + UUID mockAuthId = createCoachUserInDbReturnAuthId(); + + // Call controller endpoint + Response response = + RestAssured.given() + .header("X-AUTH-ID", mockAuthId.toString()) + .accept(ContentType.JSON) + .when() + .get("/clients") + .then() + .statusCode(200) + .extract() + .response(); + + // Verify returned JSON is an empty list. + List list = response.jsonPath().getList("$"); + assert list.isEmpty(); + } + + + + // getClientSchedule + @Test + public void getClientScheduleWithValidClientAndOneWorkoutShouldReturnOneWorkout(){ + + // Create client and coach + UUID coachAuthId = createCoachUserInDbReturnAuthId(); + UUID clientAuthId = createClientUserInDBReturnAuthId(); + + User client = userRepository.findByAuthId(clientAuthId).get(); + + // Create a workout in the clients schedule + UUID movementId = createMockMovementReturnId(); + ExerciseRequestDto exerciseRequestDto = createExerciseRequestDto(movementId); + createWorkoutInUserScheduleAndReturnScheduleId(client, List.of(exerciseRequestDto)); + + // Create an agreement between client and coach. + UUID agreementId = createCoachClientAgreementBetweenCoachAndClientReturnId(coachAuthId, clientAuthId); + + Response response = + RestAssured.given() + .header("X-AUTH-ID", coachAuthId.toString()) + .accept(ContentType.JSON) + .when() + .get("/clients/" + client.getId() + "/schedule") + .then() + .statusCode(200) + .extract() + .response(); + + // Verify returned JSON is an empty list. + List workouts = response.jsonPath().getList("workouts"); + assert workouts.size() == 1; + } + + + // deleteWorkoutFromClientSchedule + @Test + public void deleteWorkoutFromClientScheduleWithValidClientAndOneWorkout(){ + // Needs: + // Coach user + // Client user + // training schedule, with 1 workout + + + // Then -> Delete the workout by clientId and workoutId + + // Assert: getClientSchedule(clientId) has 0 workouts in it. + } + + + // addWorkoutToClientSchedule + @Test + public void addWorkoutToClientScheduleValidClientShouldAddOneWorkout(){ + // Needs: + + // User coach + // User client + // training schedule with 0 workouts. + + // CoachClientAgreement between coach and client. + // a valid AgreementTemplate + + // A workout + // A movement for the workout to use. + + + // Then -> add the workout to client schedule + + + // Assert that the workout was added correctly. 1 workout and fields were right. + } + +// proposeClientAgreement + + +// withdrawCoachesAgreementAcceptance +// createAgreementTemplate +// getCoachesAgreementTemplates +} diff --git a/integration-testing/src/test/java/CoachingIntegrationTests.java b/integration-testing/src/test/java/CoachingIntegrationTests.java new file mode 100644 index 0000000..bf22bd6 --- /dev/null +++ b/integration-testing/src/test/java/CoachingIntegrationTests.java @@ -0,0 +1,2 @@ +package PACKAGE_NAME;public class CoachingIntegrationTests { +} diff --git a/integration-testing/src/test/java/ClientIntegrationTest.java b/integration-testing/src/test/java/UserIntegrationTests.java similarity index 100% rename from integration-testing/src/test/java/ClientIntegrationTest.java rename to integration-testing/src/test/java/UserIntegrationTests.java