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/contract/get-pending-agreements.http b/api-request/client-service/clients/contract/get-pending-agreements.http
new file mode 100644
index 0000000..e69de29
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/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/schedule/add-workout-to-schedule.http b/api-request/client-service/clients/schedule/add-workout-to-schedule.http
new file mode 100644
index 0000000..209f3df
--- /dev/null
+++ b/api-request/client-service/clients/schedule/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/schedule/delete-workout-from-schedule.http b/api-request/client-service/clients/schedule/delete-workout-from-schedule.http
new file mode 100644
index 0000000..7bc64f3
--- /dev/null
+++ b/api-request/client-service/clients/schedule/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/schedule/get-training-schedule.http b/api-request/client-service/clients/schedule/get-training-schedule.http
new file mode 100644
index 0000000..c26dc70
--- /dev/null
+++ b/api-request/client-service/clients/schedule/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/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/get-clients.http b/api-request/client-service/coaches/get-clients.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/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/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 f7d789f..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,17 +1,20 @@
package com.cm.clientservice.controller;
-
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;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
import java.util.List;
+import java.util.UUID;
@RestController
-@RequestMapping("/clients")
+@RequestMapping("clients/client")
+@Tag(name="client", description = "API for clients to manage their experience.")
public class ClientController {
private final UserService userService;
@@ -21,9 +24,51 @@ 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);
+ }
+
+ @DeleteMapping("/schedule/workout/{workoutId}")
+ public ResponseEntity deleteWorkoutFromSchedule(@RequestHeader("X-AUTH-ID") String authId,
+ @PathVariable String workoutId){
+
+ TrainingScheduleDto trainingScheduleDto =
+ userService.removeWorkoutFromSchedule(UUID.fromString(authId), UUID.fromString(workoutId));
+
+ 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);
+ }
+
+ @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
new file mode 100644
index 0000000..a2b0337
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/controller/CoachingController.java
@@ -0,0 +1,110 @@
+package com.cm.clientservice.controller;
+import com.cm.clientservice.dto.UserResponseDTO;
+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.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
+@RequestMapping("clients/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("/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){
+
+ TrainingScheduleDto trainingScheduleDto =
+ 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 clientId,
+ @PathVariable String id){
+
+ TrainingScheduleDto trainingScheduleDto =
+ userService.removeWorkoutFromClientSchedule(UUID.fromString(authId), UUID.fromString(clientId), UUID.fromString(id));
+
+ return ResponseEntity.ok().body(trainingScheduleDto);
+ }
+
+ @PostMapping("/clients/{clientId}/schedule/workout")
+ public ResponseEntity addWorkoutToClientSchedule(@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("/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);
+
+ return ResponseEntity.ok().body(dto);
+ }
+
+ @PutMapping("/agreement/withdraw/{agreementId}")
+ public ResponseEntity withdrawCoachesAgreementAcceptance(@RequestHeader("X-AUTH-ID") String coachAuthId,
+ @PathVariable String agreementId){
+ //TODO: Alert user of withdrawal.
+ //TODO: Alert billing service of end of contract.
+
+ 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){
+ AgreementTemplateResponseDto dto =
+ userService.createAgreementTemplate(UUID.fromString(coachAuthId), templateRequestDto);
+
+ return ResponseEntity.ok().body(dto);
+ }
+
+ @GetMapping("/templates")
+ 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/controller/MovementController.java b/client-service/src/main/java/com/cm/clientservice/controller/MovementController.java
new file mode 100644
index 0000000..13cec7f
--- /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("/{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/controller/UserController.java b/client-service/src/main/java/com/cm/clientservice/controller/UserController.java
index 60fb3d2..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
@@ -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("clients/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,
@@ -58,17 +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());
- }
-
-
- @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()));
+ return ResponseEntity.ok().body(updatedUser);
}
@@ -78,5 +70,4 @@ public ResponseEntity deleteUser(@PathVariable UUID id){
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
-
}
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..061cc3a
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementRequestDto.java
@@ -0,0 +1,14 @@
+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;
+
+@Getter
+@Setter
+public class CoachClientAgreementRequestDto {
+ @NotNull
+ private String startDate;
+ @NotNull
+ 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
new file mode 100644
index 0000000..2eb206b
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/CoachClientAgreementResponseDto.java
@@ -0,0 +1,20 @@
+package com.cm.clientservice.dto.contract;
+
+import com.cm.clientservice.dto.contract.template.AgreementTemplateResponseDto;
+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/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/template/AgreementTemplateRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateRequestDto.java
new file mode 100644
index 0000000..e63fa14
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateRequestDto.java
@@ -0,0 +1,30 @@
+package com.cm.clientservice.dto.contract.template;
+
+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/template/AgreementTemplateResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateResponseDto.java
new file mode 100644
index 0000000..e73c415
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/contract/template/AgreementTemplateResponseDto.java
@@ -0,0 +1,16 @@
+package com.cm.clientservice.dto.contract.template;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class AgreementTemplateResponseDto {
+ private String id;
+ private String templateName;
+ 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/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/dto/scheduling/TrainingScheduleDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java
new file mode 100644
index 0000000..4fc1b33
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/TrainingScheduleDto.java
@@ -0,0 +1,15 @@
+package com.cm.clientservice.dto.scheduling;
+
+import com.cm.clientservice.dto.scheduling.workout.WorkoutResponseDto;
+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/exercise/ExerciseRequestDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java
new file mode 100644
index 0000000..3c69ff9
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/exercise/ExerciseRequestDto.java
@@ -0,0 +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/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..6fc5600
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementCreateRequestDto.java
@@ -0,0 +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/dto/scheduling/movement/MovementResponseDto.java b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementResponseDto.java
new file mode 100644
index 0000000..63cfb6f
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/dto/scheduling/movement/MovementResponseDto.java
@@ -0,0 +1,14 @@
+package com.cm.clientservice.dto.scheduling.movement;
+
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+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/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/contract/CoachClientAgreementNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/contract/CoachClientAgreementNotFoundException.java
new file mode 100644
index 0000000..0e3d2bf
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/exception/contract/CoachClientAgreementNotFoundException.java
@@ -0,0 +1,7 @@
+package com.cm.clientservice.exception.contract;
+
+public class CoachClientAgreementNotFoundException extends RuntimeException{
+ public CoachClientAgreementNotFoundException(String message){
+ super(message);
+ }
+}
diff --git a/client-service/src/main/java/com/cm/clientservice/exception/schedule/MovementNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/MovementNotFoundException.java
new file mode 100644
index 0000000..d0da5dd
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/MovementNotFoundException.java
@@ -0,0 +1,7 @@
+package com.cm.clientservice.exception.schedule;
+
+public class MovementNotFoundException extends RuntimeException {
+ public MovementNotFoundException(String message){
+ super(message);
+ }
+}
diff --git a/client-service/src/main/java/com/cm/clientservice/exception/schedule/TrainingScheduleNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/TrainingScheduleNotFoundException.java
new file mode 100644
index 0000000..b8b2520
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/TrainingScheduleNotFoundException.java
@@ -0,0 +1,7 @@
+package com.cm.clientservice.exception.schedule;
+
+public class TrainingScheduleNotFoundException extends RuntimeException{
+ public TrainingScheduleNotFoundException(String message){
+ super(message);
+ }
+}
diff --git a/client-service/src/main/java/com/cm/clientservice/exception/schedule/UnauthorizedScheduleAccessException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/UnauthorizedScheduleAccessException.java
new file mode 100644
index 0000000..3358115
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/UnauthorizedScheduleAccessException.java
@@ -0,0 +1,7 @@
+package com.cm.clientservice.exception.schedule;
+
+public class UnauthorizedScheduleAccessException extends RuntimeException{
+ public UnauthorizedScheduleAccessException(String message){
+ super(message);
+ }
+}
diff --git a/client-service/src/main/java/com/cm/clientservice/exception/schedule/WorkoutNotFoundException.java b/client-service/src/main/java/com/cm/clientservice/exception/schedule/WorkoutNotFoundException.java
new file mode 100644
index 0000000..be2ac6f
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/exception/schedule/WorkoutNotFoundException.java
@@ -0,0 +1,7 @@
+package com.cm.clientservice.exception.schedule;
+
+public class WorkoutNotFoundException extends RuntimeException{
+ public WorkoutNotFoundException(String message){
+ super(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
new file mode 100644
index 0000000..df8f206
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/AgreementTemplateMapper.java
@@ -0,0 +1,43 @@
+package com.cm.clientservice.mapper.contract;
+
+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){
+ AgreementTemplateResponseDto dto = new AgreementTemplateResponseDto();
+
+ 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());
+ dto.setTemplateName(agreementTemplate.getTemplateName());
+
+ 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();
+
+ 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
new file mode 100644
index 0000000..d121607
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/mapper/contract/CoachClientAgreementMapper.java
@@ -0,0 +1,32 @@
+package com.cm.clientservice.mapper.contract;
+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 CoachClientAgreementResponseDto toDto(CoachClientAgreement agreement) {
+ CoachClientAgreementResponseDto dto = new CoachClientAgreementResponseDto();
+
+ 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.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/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..0003819
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/MovementMapper.java
@@ -0,0 +1,23 @@
+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/schedule/TrainingScheduleMapper.java b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/TrainingScheduleMapper.java
new file mode 100644
index 0000000..ac2b3f4
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/mapper/schedule/TrainingScheduleMapper.java
@@ -0,0 +1,14 @@
+package com.cm.clientservice.mapper.schedule;
+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/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/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/User.java b/client-service/src/main/java/com/cm/clientservice/model/User.java
index 1b552df..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
@@ -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 agreementsAsCoach;
- @OneToOne
- @JoinColumn(name = "client_profile_id")
- private ClientProfile clientProfile;
+ @OneToMany(mappedBy = "client")
+ private List agreementsAsClient;
+
+ @OneToMany(mappedBy = "author")
+ private List authoredTemplates;
+
+ @OneToOne(cascade = CascadeType.ALL)
+ @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..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
@@ -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;
@@ -19,10 +19,13 @@ 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")
- 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..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
@@ -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;
@@ -14,23 +13,20 @@
@Getter
@Setter
public class CoachClientAgreement {
- /**
- Represents a running agreement document between
- */
@Id
@GeneratedValue
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")
@@ -39,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/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
new file mode 100644
index 0000000..95de79f
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/model/schedule/TrainingSchedule.java
@@ -0,0 +1,25 @@
+package com.cm.clientservice.model.schedule;
+import com.cm.clientservice.model.User;
+import jakarta.persistence.*;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@Entity
+@Getter
+@Setter
+public class TrainingSchedule {
+
+ @Id
+ @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/model/schedule/Workout.java b/client-service/src/main/java/com/cm/clientservice/model/schedule/Workout.java
index e437f1e..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
@@ -1,11 +1,12 @@
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;
import java.time.LocalDate;
+import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -17,13 +18,8 @@ public class Workout {
@GeneratedValue
private UUID id;
- @ManyToMany
- @JoinTable(
- name = "workout_exercise",
- joinColumns = @JoinColumn(name = "workout_id"),
- inverseJoinColumns = @JoinColumn(name = "exercise_id")
- )
- private List exercises;
+ @OneToMany(mappedBy = "workout", cascade = CascadeType.ALL, orphanRemoval = true)
+ private List exercises = new ArrayList<>();
@NotNull
private LocalDate date;
@@ -32,5 +28,9 @@ public class Workout {
private String workoutNotes;
@NotNull
- private boolean isCompleted;
+ private Boolean isCompleted;
+
+ @ManyToOne
+ @JoinColumn(name = "training_schedule_id")
+ private TrainingSchedule trainingSchedule;
}
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/WorkoutSchedule.java
deleted file mode 100644
index 3718998..0000000
--- a/client-service/src/main/java/com/cm/clientservice/model/schedule/WorkoutSchedule.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.cm.clientservice.model.schedule;
-import jakarta.persistence.*;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.util.List;
-import java.util.UUID;
-
-@Entity
-@Getter
-@Setter
-public class WorkoutSchedule {
-
- @Id
- @GeneratedValue
- private UUID id;
-
- @ManyToMany
- @JoinTable(name = "trainingschedule_workout",
- joinColumns = @JoinColumn(name = "trainingschedule_id"),
- inverseJoinColumns = @JoinColumn(name = "workout_id"))
- private List workouts;
-}
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/repository/CoachClientAgreementRepository.java b/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java
new file mode 100644
index 0000000..a8d1c80
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/repository/CoachClientAgreementRepository.java
@@ -0,0 +1,12 @@
+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/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/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/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/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
new file mode 100644
index 0000000..329a64b
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/service/CoachClientAgreementService.java
@@ -0,0 +1,73 @@
+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.util.List;
+import java.util.UUID;
+
+@Service
+public class CoachClientAgreementService {
+
+ private final CoachClientAgreementRepository coachClientAgreementRepository;
+ private final AgreementTemplateService agreementTemplateService;
+
+ public CoachClientAgreementService(CoachClientAgreementRepository coachClientAgreementRepository,
+ AgreementTemplateService agreementTemplateService){
+ this.coachClientAgreementRepository = coachClientAgreementRepository;
+ this.agreementTemplateService = agreementTemplateService;
+ }
+
+ public List getCoachClientAgreements(UUID coachId){
+
+ return coachClientAgreementRepository.findAllByCoach_Id(coachId);
+ }
+
+ public boolean isUserAClientOfCoach(UUID userId, UUID coachId){
+ return coachClientAgreementRepository
+ .existsCoachClientAgreementByClient_IdAndCoach_Id(userId, coachId);
+ }
+
+ public boolean isAgreementActive(CoachClientAgreement coachClientAgreement) {
+ return coachClientAgreement.getCoachIsInAgreement() &&
+ coachClientAgreement.getClientIsInAgreement();
+ }
+
+ public CoachClientAgreementResponseDto proposeCoachClientAgreement(User coach, User client, CoachClientAgreementRequestDto agreementDto) {
+
+ CoachClientAgreement agreement = CoachClientAgreementMapper.toModel(agreementDto);
+ 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
new file mode 100644
index 0000000..3779aa8
--- /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.schedule.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);
+ }
+}
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..08cf832
--- /dev/null
+++ b/client-service/src/main/java/com/cm/clientservice/service/TrainingScheduleService.java
@@ -0,0 +1,58 @@
+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.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;
+import java.util.UUID;
+
+@Service
+public class TrainingScheduleService {
+
+ private final TrainingScheduleRepository trainingScheduleRepository;
+
+ public TrainingScheduleService(TrainingScheduleRepository trainingScheduleRepository){
+ this.trainingScheduleRepository = trainingScheduleRepository;
+ }
+
+ @Transactional
+ 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);
+ }
+
+ @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);
+
+ 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 d9ee028..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,10 +3,22 @@
import com.cm.clientservice.dto.OutgoingEmailUpdateDTO;
import com.cm.clientservice.dto.UserRequestDTO;
import com.cm.clientservice.dto.UserResponseDTO;
-import com.cm.clientservice.exception.EmailAlreadyExistsException;
-import com.cm.clientservice.exception.UserNotFoundException;
+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.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;
@@ -21,17 +33,43 @@
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){
+ @Value("${auth.service.url}") String authServiceUrl,
+ CoachClientAgreementService coachClientAgreementService,
+ 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())){
@@ -41,6 +79,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);
@@ -58,18 +100,9 @@ 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
- 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());
@@ -88,8 +121,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 +141,156 @@ public UserResponseDTO updateUser(UUID authId, UserRequestDTO userRequestDTO, St
return UserMapper.toDTO(updatedUser);
}
+ public List getClientsOfCoach(UUID coachAuthId){
+ UUID coachId = findCoachByAuthIdOrElseThrow(coachAuthId).getId();
+
+ return coachClientAgreementService
+ .getCoachClientAgreements(coachId)
+ .stream()
+ .filter(coachClientAgreementService::isAgreementActive)
+ .map(a -> UserMapper.toDTO(a.getClient()))
+ .distinct()
+ .toList();
+ }
+
+ public List getCoachesOfClient(UUID clientAuthId) {
+ UUID clientId = findUserByAuthIdOrElseThrow(clientAuthId).getId();
+
+
+ return coachClientAgreementService
+ .getCoachClientAgreements(clientId)
+ .stream()
+ .map(a -> UserMapper.toDTO(a.getCoach()))
+ .distinct()
+ .toList();
+ }
+
+ public TrainingScheduleDto getClientTrainingSchedule(UUID clientId, UUID coachAuthId){
+ 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 clientSchedule =
+ findUserByIdOrElseThrow(clientId).getTrainingSchedule();
+
+ return TrainingScheduleMapper.toDto(clientSchedule);
+ }
+
+ public TrainingScheduleDto getTrainingSchedule(UUID authId){
+ TrainingSchedule schedule = findUserByAuthIdOrElseThrow(authId).getTrainingSchedule();
+ return TrainingScheduleMapper.toDto(schedule);
+ }
+
+
+ public TrainingScheduleDto addWorkoutToSchedule(UUID clientAuthId, WorkoutRequestDto workoutDto) {
+ UUID trainingScheduleId =
+ findUserByAuthIdOrElseThrow(clientAuthId).getTrainingSchedule().getId();
+
+ return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingScheduleId);
+ }
+
+
+ public TrainingScheduleDto addWorkoutToClientsSchedule(UUID coachAuthId, UUID clientId, WorkoutRequestDto workoutDto) {
+ 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);
+ }
+
+ UUID trainingScheduleId =
+ findUserByIdOrElseThrow(clientId).getTrainingSchedule().getId();
+
+ return trainingScheduleService.addWorkoutToSchedule(workoutDto, trainingScheduleId);
+ }
+
+
+ public TrainingScheduleDto removeWorkoutFromClientSchedule(UUID coachAuthId, UUID clientId, UUID workoutId) {
+ 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 =
+ findUserByIdOrElseThrow(clientId).getTrainingSchedule();
+
+ return trainingScheduleService.removeWorkoutFromSchedule(trainingSchedule, workoutId);
+ }
+
+ public TrainingScheduleDto removeWorkoutFromSchedule(UUID clientAuthId, UUID workoutId) {
+
+ 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);
+ }
+
+ public List getCoachAgreementTemplates(UUID coachAuthId) {
+ User coach = findCoachByAuthIdOrElseThrow(coachAuthId);
+ return agreementTemplateService.findAgreementsAuthoredByCoach(coach);
+
+ }
+
+ public AgreementTemplateResponseDto createAgreementTemplate(UUID coachAuthId, AgreementTemplateRequestDto templateRequestDto) {
+ User coach = findCoachByAuthIdOrElseThrow(coachAuthId);
+ return agreementTemplateService.createAgreementTemplate(coach, templateRequestDto);
+ }
+
+ public List getPendingAgreements(UUID authId) {
+ UUID userId = findUserByAuthIdOrElseThrow(authId).getId();
+
+ return coachClientAgreementService
+ .getCoachClientAgreements(userId)
+ .stream()
+ .filter(coachClientAgreementService::isAgreementPending)
+ .map(CoachClientAgreementMapper::toDto)
+ .toList();
+ }
+
+ @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/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');
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