From 4371189c76abc4adb8136350ed2a466012649468 Mon Sep 17 00:00:00 2001
From: SamuelNguyen2121 <102634920+SamuelNguyen2121@users.noreply.github.com>
Date: Mon, 23 Oct 2023 16:58:49 -0400
Subject: [PATCH 1/2] feat(AUTH-CPC-755): Add More Roles Front End (#573)
JIRA: link to jira ticket
https://champlainsaintlambert.atlassian.net/browse/CPC-755
## Context:
What is the ticket about and why are we doing this change.
This ticket is about adding three roles, and one of them to be assigned
to users because we want them to have a restricted access in the system.
It is also about the feature for the admin to update the users' role if
ever a user needs a different permission on the website.
## Changes
What are the various changes and what other modules do those changes
effect.
This can be bullet point or sentence format.
- A new column in the admin panel called "Role" to see the users'
current role assigned
- A new button in the admin panel called "Update Role" to navigate to
the update user role form
- A new form for updating a user's role with list of availble roles to
change
## Before and After UI (Required for UI-impacting PRs)
If this is a change to the UI, include before and after screenshots to
show the differences.
If this is a new UI feature, include screenshots to show reviewers what
it looks like.
New "Update Role" Button and New "Role" Column in Admin Panel
![image](https://github.com/cgerard321/champlain_petclinic/assets/102634920/8b06d53d-b35f-4b64-b507-2f30cb75ac41)New
Update User Role Form (After Clicking Update Role Button)
![image](https://github.com/cgerard321/champlain_petclinic/assets/102634920/8195f48b-95ec-42c1-9044-da3d3e892195)
## Dev notes (Optional)
- Specific technical changes that should be noted
## Linked pull requests (Optional)
- pull request link
---
.../src/main/resources/static/index.html | 6 ++
.../src/main/resources/static/scripts/app.js | 2 +-
.../admin-panel/admin-panel.template.html | 8 +++
.../update-role-form/role-update.component.js | 10 ++++
.../update-role-form/role-update.config.js | 16 ++++++
.../role-update.controller.js | 56 +++++++++++++++++++
.../update-role-form/role-update.service.js | 8 +++
.../role-update.template.html | 12 ++++
.../businesslayer/UserService.java | 2 +-
.../authservice/datalayer/user/UserRepo.java | 1 -
.../User/RolesChangeRequestDTO.java | 3 +-
.../User/UserControllerIntegrationTest.java | 22 ++++----
12 files changed, 131 insertions(+), 15 deletions(-)
create mode 100644 api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.component.js
create mode 100644 api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.config.js
create mode 100644 api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.controller.js
create mode 100644 api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.service.js
create mode 100644 api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.template.html
diff --git a/api-gateway/src/main/resources/static/index.html b/api-gateway/src/main/resources/static/index.html
index 311e4f68b7..684cee39f2 100755
--- a/api-gateway/src/main/resources/static/index.html
+++ b/api-gateway/src/main/resources/static/index.html
@@ -198,6 +198,12 @@
+
+
+
+
+
+
diff --git a/api-gateway/src/main/resources/static/scripts/app.js b/api-gateway/src/main/resources/static/scripts/app.js
index 5974f59b8d..daf9660120 100644
--- a/api-gateway/src/main/resources/static/scripts/app.js
+++ b/api-gateway/src/main/resources/static/scripts/app.js
@@ -12,7 +12,7 @@ const petClinicApp = angular.module('petClinicApp', [
'ui.router', 'layoutNav', 'layoutFooter', 'layoutWelcome', 'ownerList', 'ownerDetails', 'ownerForm', 'ownerRegister', 'petRegister', 'petForm'
, 'visits', 'visit', 'visitList' , 'vetList','vetForm','vetDetails', 'billForm', 'billUpdateForm', 'loginForm', 'rolesDetails', 'signupForm', 'productDetailsInfo',
'billDetails', 'billsByOwnerId', 'billHistory','billsByVetId','inventoryList', 'inventoryForm', 'productForm','inventoryProductList', 'inventoryUpdateForm', 'productUpdateForm',
- 'verification' , 'adminPanel','resetPwdForm','forgotPwdForm','petTypeList', 'petDetails','userDetails','managerForm']);
+ 'verification' , 'adminPanel','resetPwdForm','forgotPwdForm','petTypeList', 'petDetails','userDetails','managerForm','userModule']);
diff --git a/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html b/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html
index 9724f37d14..1cd6933c8d 100644
--- a/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html
+++ b/api-gateway/src/main/resources/static/scripts/auth/admin-panel/admin-panel.template.html
@@ -12,6 +12,7 @@
Users
Username
Email
+ Role
Options
@@ -23,8 +24,15 @@ Users
{{user.email}}
+
+
+
+ {{ role.name }},
+
+
+ Update Role
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.component.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.component.js
new file mode 100644
index 0000000000..c2726d3ee9
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.component.js
@@ -0,0 +1,10 @@
+'use strict';
+
+angular.module('userModule')
+ .component('updateUserRoleComponent', {
+ templateUrl: 'scripts/auth/update-role-form/role-update.template.html',
+ controller: 'UpdateUserRoleController',
+ bindings: {
+ userId: '<'
+ }
+ });
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.config.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.config.js
new file mode 100644
index 0000000000..af5abd257f
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.config.js
@@ -0,0 +1,16 @@
+'use strict';
+
+angular.module('userModule', ['ui.router'])
+ .config(['$stateProvider', function($stateProvider) {
+ $stateProvider
+ .state('updateUserRole', {
+ parent: 'app',
+ url: '/users/:userId/updateRole',
+ component: 'updateUserRoleComponent',
+ resolve: {
+ userId: ['$stateParams', function($stateParams) {
+ return $stateParams.userId;
+ }]
+ }
+ });
+ }]);
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.controller.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.controller.js
new file mode 100644
index 0000000000..753496bb79
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.controller.js
@@ -0,0 +1,56 @@
+'use strict';
+
+angular.module('userModule')
+ .controller('UpdateUserRoleController', ['$scope', '$http', 'UserService', '$state', function($scope, $http, UserService, $state) {
+ var ctrl = this; // Capture the controller instance
+
+ $scope.roles = UserService.getAvailableRoles();
+ $scope.selectedRole = {};
+
+ // Use $onInit lifecycle hook to set $scope.userId
+ ctrl.$onInit = function() {
+ $scope.userId = ctrl.userId;
+ };
+
+ $scope.selectedRoles = {};
+
+ $scope.updateRole = function() {
+ var rolesList = [];
+ for (var role in $scope.selectedRoles) {
+ if ($scope.selectedRoles[role]) {
+ rolesList.push(role);
+ }
+ }
+
+ if (rolesList.length === 0) {
+ alert('Please select at least one role.');
+ return;
+ }
+
+ if (rolesList.length > 1) {
+ alert('Please select only one role.');
+ return;
+ }
+
+ var rolesChangeRequest = {
+ roles: rolesList
+ };
+
+ // Send the PATCH request
+ $http({
+ method: 'PATCH',
+ url: 'api/gateway/users/' + $scope.userId,
+ data: rolesChangeRequest,
+ headers: {
+ 'Content-Type': 'application/json',
+ // Add token headers if needed
+ }
+ })
+ .then(function successCallback(response) {
+ alert('Roles updated successfully!');
+ $state.go('AdminPanel');
+ }, function errorCallback(response) {
+ alert('Failed to update roles. ' + response.data.message);
+ });
+ };
+ }]);
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.service.js b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.service.js
new file mode 100644
index 0000000000..fbf12f6add
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.service.js
@@ -0,0 +1,8 @@
+'use strict';
+
+angular.module('userModule').service('UserService', [function() {
+ this.getAvailableRoles = function() {
+ return ['ADMIN', 'VET', 'OWNER'];
+ };
+
+}]);
\ No newline at end of file
diff --git a/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.template.html b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.template.html
new file mode 100644
index 0000000000..be352a7b03
--- /dev/null
+++ b/api-gateway/src/main/resources/static/scripts/auth/update-role-form/role-update.template.html
@@ -0,0 +1,12 @@
+Update User Role
+
diff --git a/auth-service/src/main/java/com/petclinic/authservice/businesslayer/UserService.java b/auth-service/src/main/java/com/petclinic/authservice/businesslayer/UserService.java
index 8c391b806e..4928b32f37 100644
--- a/auth-service/src/main/java/com/petclinic/authservice/businesslayer/UserService.java
+++ b/auth-service/src/main/java/com/petclinic/authservice/businesslayer/UserService.java
@@ -63,5 +63,5 @@ public interface UserService {
void updatePassword(String newPassword, String token);
void processResetPassword(UserResetPwdWithTokenRequestModel resetRequest);
- UserPasswordLessDTO updateUserRole(String id, RolesChangeRequestDTO roles, String token);
+ UserPasswordLessDTO updateUserRole(String userId, RolesChangeRequestDTO roles, String token);
}
diff --git a/auth-service/src/main/java/com/petclinic/authservice/datalayer/user/UserRepo.java b/auth-service/src/main/java/com/petclinic/authservice/datalayer/user/UserRepo.java
index 2f86e56833..10a830a499 100644
--- a/auth-service/src/main/java/com/petclinic/authservice/datalayer/user/UserRepo.java
+++ b/auth-service/src/main/java/com/petclinic/authservice/datalayer/user/UserRepo.java
@@ -26,7 +26,6 @@
public interface UserRepo extends JpaRepository {
Optional findByEmail(String email);
- User findUserById(long id);
Optional findByUsername(String username);
diff --git a/auth-service/src/main/java/com/petclinic/authservice/presentationlayer/User/RolesChangeRequestDTO.java b/auth-service/src/main/java/com/petclinic/authservice/presentationlayer/User/RolesChangeRequestDTO.java
index afde7a6c0e..7c59f390a5 100644
--- a/auth-service/src/main/java/com/petclinic/authservice/presentationlayer/User/RolesChangeRequestDTO.java
+++ b/auth-service/src/main/java/com/petclinic/authservice/presentationlayer/User/RolesChangeRequestDTO.java
@@ -6,11 +6,12 @@
import lombok.NoArgsConstructor;
import java.util.List;
+import java.util.Set;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder(toBuilder = true)
public class RolesChangeRequestDTO {
- List roles;
+ Set roles;
}
diff --git a/auth-service/src/test/java/com/petclinic/authservice/presentationlayer/User/UserControllerIntegrationTest.java b/auth-service/src/test/java/com/petclinic/authservice/presentationlayer/User/UserControllerIntegrationTest.java
index 455d4cd37d..a4020e1b1c 100644
--- a/auth-service/src/test/java/com/petclinic/authservice/presentationlayer/User/UserControllerIntegrationTest.java
+++ b/auth-service/src/test/java/com/petclinic/authservice/presentationlayer/User/UserControllerIntegrationTest.java
@@ -26,10 +26,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.when;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
+import java.util.*;
import java.util.stream.Collectors;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@@ -648,7 +645,7 @@ void deleteUser_ShouldThrowNotFoundException(){
@Test
void updateUserRole_validUserId() {
RolesChangeRequestDTO updatedUser = RolesChangeRequestDTO.builder()
- .roles(Collections.singletonList("OWNER"))
+ .roles(Collections.singleton("OWNER"))
.build();
String token = jwtTokenUtil.generateToken(userRepo.findAll().get(0));
@@ -666,16 +663,19 @@ void updateUserRole_validUserId() {
.value(dto -> {
assertNotNull(dto);
List actualRoleNames = dto.getRoles().stream()
- .map(Role::getName) // Assuming the Role object has a getName() method
+ .map(Role::getName)
.toList();
- assertEquals(updatedUser.getRoles(), actualRoleNames);
+
+ Set actualRolesSet = new HashSet<>(actualRoleNames);
+
+ assertEquals(updatedUser.getRoles(), actualRolesSet);
});
}
@Test
void updateUserRole_InvalidUserId() {
RolesChangeRequestDTO updatedUser = RolesChangeRequestDTO.builder()
- .roles(Collections.singletonList("OWNER"))
+ .roles(Collections.singleton("OWNER"))
.build();
String token = jwtTokenUtil.generateToken(userRepo.findAll().get(0));
String invalidUserId = "invalidId";
@@ -694,7 +694,7 @@ void updateUserRole_InvalidUserId() {
@Test
void updateUserRole_NoCookie() {
RolesChangeRequestDTO updatedUser = RolesChangeRequestDTO.builder()
- .roles(Collections.singletonList("OWNER"))
+ .roles(Collections.singleton("OWNER"))
.build();
webTestClient
@@ -711,7 +711,7 @@ void updateUserRole_NoCookie() {
void updateUserRole_cannotChangeOwnRoles() {
String userId = "validUserId";
RolesChangeRequestDTO updatedUser = RolesChangeRequestDTO.builder()
- .roles(Collections.singletonList("OWNER"))
+ .roles(Collections.singleton("OWNER"))
.build();
String token = jwtTokenUtil.generateToken(userRepo.findAll().get(0));
@@ -730,7 +730,7 @@ void updateUserRole_cannotChangeOwnRoles() {
@Test
void updateUserRole_invalidRole() {
RolesChangeRequestDTO updatedUser = RolesChangeRequestDTO.builder()
- .roles(Collections.singletonList("NOT_OWNER"))
+ .roles(Collections.singleton("NOT_OWNER"))
.build();
String token = jwtTokenUtil.generateToken(userRepo.findAll().get(0));
From dbc92c9d12792553ba8efaccb322c84b063093be Mon Sep 17 00:00:00 2001
From: William Chalifoux
Date: Mon, 23 Oct 2023 17:25:39 -0400
Subject: [PATCH 2/2] feat(VIST-CPC-811): send email on visit request (#589)
JIRA: link to [jira
ticket](https://champlainsaintlambert.atlassian.net/browse/CPC-811)
## Context:
Sending an email to the pet owner when a visit is requested/scheduled.
## Changes
Added AuthServiceClient and mailerClient integration to be able to send
emails.
## Before and After UI (Required for UI-impacting PRs)
Image of an email sent when a visit is added.
![image](https://github.com/cgerard321/champlain_petclinic/assets/12865356/94d11295-9207-4f7c-9920-b37aa1f80e75)
## Dev notes (Optional)
- Changed 1 line in auth to fix a deprecated use of an api in the
AuthMailServiceTests for the Auth team.
---
api-gateway/build.gradle | 50 +++++-------
.../VisitsServiceClient.java | 8 +-
.../dtos/Visits/VisitRequestDTO.java | 6 +-
.../BFFApiGatewayController.java | 6 +-
.../VisitsServiceClientIntegrationTest.java | 14 +++-
.../businesslayer/AuthMailServiceTests.java | 3 +-
docker-compose.yml | 40 +++++-----
visits-service-new/build.gradle | 32 ++++----
.../BusinessLayer/VisitServiceImpl.java | 80 +++++++++++++++++--
.../Auth/AuthServiceClient.java | 42 ++++++++++
.../DomainClientLayer/Auth/Rethrower.java | 30 +++++++
.../DomainClientLayer/Auth/Role.java | 15 ++++
.../DomainClientLayer/Auth/UserDetails.java | 23 ++++++
.../DomainClientLayer/Mailing/Mail.java | 19 +++++
.../Mailing/MailService.java | 6 ++
.../Mailing/MailServiceCall.java | 11 +++
.../Mailing/MailServiceImpl.java | 33 ++++++++
.../DomainClientLayer/VetsClient.java | 11 +--
.../Exceptions/GenericHttpException.java | 16 ++++
.../PresentationLayer/VisitRequestDTO.java | 6 +-
.../Configuration/Mail/MailServiceConfig.java | 32 ++++++++
.../VisitsServiceNewApplication.java | 2 -
.../src/main/resources/application.yml | 17 +++-
.../BusinessLayer/MailServiceTests.java | 73 +++++++++++++++++
.../BusinessLayer/VisitServiceImplTest.java | 35 ++++----
.../DataLayer/VisitRepoTest.java | 2 +-
.../AuthServiceClientIntegrationTest.java | 64 +++++++++++++++
.../Exceptions/BadRequestExceptionTest.java | 4 +-
.../GlobalControllerExceptionHandlerTest.java | 3 +-
.../Exceptions/NotFoundExceptionTest.java | 4 +-
.../VisitControllerUnitTest.java | 14 ++--
.../VisitsControllerIntegrationTest.java | 12 +--
.../Utils/EntityDtoUtilTest.java | 1 -
33 files changed, 572 insertions(+), 142 deletions(-)
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/AuthServiceClient.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Rethrower.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Role.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/UserDetails.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/Mail.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailService.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceCall.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceImpl.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Exceptions/GenericHttpException.java
create mode 100644 visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Utils/Configuration/Mail/MailServiceConfig.java
create mode 100644 visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/MailServiceTests.java
create mode 100644 visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/AuthServiceClientIntegrationTest.java
diff --git a/api-gateway/build.gradle b/api-gateway/build.gradle
index 074e953a67..dadb140664 100755
--- a/api-gateway/build.gradle
+++ b/api-gateway/build.gradle
@@ -21,39 +21,31 @@ repositories {
dependencies {
-
-
- implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
- runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2'
- runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.2'
-
- implementation 'org.springframework.boot:spring-boot-starter-validation'
- implementation 'org.springframework.boot:spring-boot-starter-actuator'
- implementation 'org.springframework.boot:spring-boot-starter-webflux'
- implementation 'org.yaml:snakeyaml:2.2'
-
- implementation 'org.webjars:bootstrap:5.1.0' // https://mvnrepository.com/artifact/org.webjars/bootstrap
- implementation 'org.webjars:jquery:3.6.0' // https://mvnrepository.com/artifact/org.webjars/jquery
- implementation 'org.webjars:angularjs:2.0.0-alpha.22' // https://mvnrepository.com/artifact/org.webjars/angularjs
-
- implementation 'org.webjars.bower:angular-ui-router:1.0.28' // https://mvnrepository.com/artifact/org.webjars.bower/angular-ui-router
- implementation 'org.webjars:webjars-locator-core:0.47' // https://mvnrepository.com/artifact/org.webjars/webjars-locator-core
- implementation 'ro.isdc.wro4j:wro4j-core:1.10.1' // https://mvnrepository.com/artifact/ro.isdc.wro4j/wro4j-core
- implementation 'com.github.houbie:lesscss-gradle-plugin:1.0.3-less-1.7.0' // https://mvnrepository.com/artifact/com.github.houbie/lesscss-gradle-plugin
- implementation 'com.github.houbie:lesscss-gradle-plugin:1.0.3-less-1.7.0' // https://mvnrepository.com/artifact/com.github.houbie/lesscss-gradle-plugin
- implementation 'org.jolokia:jolokia-core:1.7.0' // https://mvnrepository.com/artifact/org.jolokia/jolokia-core
- implementation 'io.springfox:springfox-boot-starter:3.0.0'
- implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' //for serializing and deserializing java.time.LocalDateTime
-
+ runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.2', 'io.jsonwebtoken:jjwt-jackson:0.11.2'
+
+ implementation 'org.webjars:bootstrap:5.1.0', // https://mvnrepository.com/artifact/org.webjars/bootstrap
+ 'org.springframework.boot:spring-boot-starter-webflux',
+ 'org.springframework.boot:spring-boot-starter-actuator',
+ 'org.springframework.boot:spring-boot-starter-validation',
+ 'io.jsonwebtoken:jjwt-api:0.11.2',
+ 'org.webjars:jquery:3.7.1', // https://mvnrepository.com/artifact/org.webjars/jquery
+ 'org.webjars:angularjs:2.0.0-alpha.22', // https://mvnrepository.com/artifact/org.webjars/angularjs
+ 'org.webjars.bower:angular-ui-router:1.0.28', // https://mvnrepository.com/artifact/org.webjars.bower/angular-ui-router
+ 'org.webjars:webjars-locator-core:0.47', // https://mvnrepository.com/artifact/org.webjars/webjars-locator-core
+ 'ro.isdc.wro4j:wro4j-core:1.10.1', // https://mvnrepository.com/artifact/ro.isdc.wro4j/wro4j-core
+ 'com.github.houbie:lesscss-gradle-plugin:1.0.3-less-1.7.0', // https://mvnrepository.com/artifact/com.github.houbie/lesscss-gradle-plugin
+ 'org.jolokia:jolokia-core:1.7.0', // https://mvnrepository.com/artifact/org.jolokia/jolokia-core
+ 'io.springfox:springfox-boot-starter:3.0.0',
+ 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310', //for serializing and deserializing java.time.LocalDateTime
+ 'org.yaml:snakeyaml:2.2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
- testImplementation 'io.projectreactor:reactor-test'
- testImplementation 'com.squareup.okhttp3:okhttp:4.11.0'
- testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
-
+ testImplementation 'com.squareup.okhttp3:okhttp:4.11.0',
+ 'com.squareup.okhttp3:mockwebserver:4.11.0',
+ 'io.projectreactor:reactor-test'
}
jacoco {
@@ -89,4 +81,4 @@ test {
testLogging {
events "passed", "skipped", "failed"
}
-}
\ No newline at end of file
+}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java
index 265f5fe9b4..c894cbfb6a 100755
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClient.java
@@ -2,10 +2,11 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.petclinic.bffapigateway.dtos.Visits.*;
+import com.petclinic.bffapigateway.dtos.Visits.Status;
+import com.petclinic.bffapigateway.dtos.Visits.VisitRequestDTO;
+import com.petclinic.bffapigateway.dtos.Visits.VisitResponseDTO;
import com.petclinic.bffapigateway.exceptions.BadRequestException;
import com.petclinic.bffapigateway.exceptions.DuplicateTimeException;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
@@ -24,10 +25,8 @@
*/
@Component
-@Slf4j
public class VisitsServiceClient {
private final WebClient webClient;
-
@Autowired
public VisitsServiceClient(
@Value("${app.visits-service-new.host}") String visitsServiceHost,
@@ -125,7 +124,6 @@ else if (httpStatus == HttpStatus.CONFLICT){
else {
return Mono.error(new BadRequestException(message));
}
-
} catch (IOException e) {
// Handle parsing error
return Mono.error(new BadRequestException("Bad Request"));
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java
index 4efc69f4ae..464f807503 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/dtos/Visits/VisitRequestDTO.java
@@ -19,13 +19,17 @@ public class VisitRequestDTO {
private LocalDateTime visitDate;
private String description;
private String petId;
+ private String ownerId;
+ private String jwtToken;//used to get the userDetails from the Auth-Service when sending visit emails
private String practitionerId;
private Status status;
- public VisitRequestDTO(LocalDateTime now, String description, String petId, String practitionerId) {
+ public VisitRequestDTO(LocalDateTime now, String description, String petId, String ownerId, String jwtToken, String practitionerId) {
this.visitDate = now;
this.description = description;
this.petId = petId;
+ this.ownerId = ownerId;
+ this.jwtToken = jwtToken;
this.practitionerId = practitionerId;
this.status = Status.UPCOMING;
}
diff --git a/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java b/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java
index 3d312f97be..1c32f41149 100644
--- a/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java
+++ b/api-gateway/src/main/java/com/petclinic/bffapigateway/presentationlayer/BFFApiGatewayController.java
@@ -29,7 +29,6 @@
import reactor.core.publisher.Mono;
import java.util.Map;
-import java.util.List;
import java.util.Optional;
/**
@@ -262,8 +261,9 @@ public Mono getVisitByVisitId(@PathVariable String visitId){
return visitsServiceClient.getVisitByVisitId(visitId);
}
@PostMapping(value = "visit/owners/{ownerId}/pets/{petId}/visits", consumes = "application/json", produces = "application/json")
- Mono> addVisit(@RequestBody VisitRequestDTO visit, @PathVariable String ownerId, @PathVariable String petId) {
- // visit.setPetId(petId);
+ Mono> addVisit(@RequestBody VisitRequestDTO visit, @PathVariable String ownerId, /*@PathVariable String petId,*/ @CookieValue("Bearer") String auth) {
+ visit.setOwnerId(ownerId);
+ visit.setJwtToken(auth);
return visitsServiceClient.createVisitForPet(visit).map(ResponseEntity.status(HttpStatus.CREATED)::body)
.defaultIfEmpty(ResponseEntity.badRequest().build());
}
diff --git a/api-gateway/src/test/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClientIntegrationTest.java b/api-gateway/src/test/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClientIntegrationTest.java
index a13e0c51c0..1eab54f4da 100755
--- a/api-gateway/src/test/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClientIntegrationTest.java
+++ b/api-gateway/src/test/java/com/petclinic/bffapigateway/domainclientlayer/VisitsServiceClientIntegrationTest.java
@@ -150,6 +150,8 @@ void createVisitForPet_Valid() throws JsonProcessingException {
LocalDateTime.parse("2024-11-25 13:45", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
"Test Visit",
"1",
+ "f470653d-05c5-4c45-b7a0-7d70f003d2ac",
+ "testJwtToken",
"2"
);
@@ -178,6 +180,8 @@ void createVisitForPet_Valid() throws JsonProcessingException {
// Assert
StepVerifier.create(resultMono)
+ .expectNext()
+ .expectNext()
.expectNextMatches(visitResponse -> Objects.equals(visitResponse.getVisitId(), visitResponseDTO.getVisitId()))
.verifyComplete();
@@ -191,6 +195,8 @@ void createVisitForPet_DuplicateTime_ThrowsDuplicateTimeException() throws JsonP
LocalDateTime.parse("2024-11-25 13:45", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
"Test Visit",
"1",
+ "f470653d-05c5-4c45-b7a0-7d70f003d2ac",
+ "testJwtToken",
"2"
);
@@ -218,6 +224,8 @@ void createVisitForPet_NotFound_ThrowsNotFoundException() throws JsonProcessingE
LocalDateTime.parse("2024-11-25 13:45", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
"Test Visit",
"1",
+ "f470653d-05c5-4c45-b7a0-7d70f003d2ac",
+ "testJwtToken",
"2"
);
@@ -245,6 +253,8 @@ void createVisitForPet_BadRequest_ThrowsBadRequestException() throws JsonProcess
LocalDateTime.parse("2024-11-25 13:45", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
"Test Visit",
"1",
+ "f470653d-05c5-4c45-b7a0-7d70f003d2ac",
+ "testJwtToken",
"2"
);
@@ -272,6 +282,8 @@ void createVisitForPet_InvalidErrorResponse_ThrowsBadRequestException() throws J
LocalDateTime.parse("2024-11-25 13:45", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
"Test Visit",
"1",
+ "f470653d-05c5-4c45-b7a0-7d70f003d2ac",
+ "testJwtToken",
"2"
);
@@ -322,7 +334,7 @@ void getVisitById() throws Exception {
.visitDate(LocalDateTime.parse("2024-11-25 13:45", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")))
.description("this is a dummy description")
.petId("2")
- .petName("YourPetNameHere")
+ .petName("YourPetNameHere")
.petBirthDate(new Date())
.practitionerId("2")
.vetFirstName("VetFirstNameHere")
diff --git a/auth-service/src/test/java/com/petclinic/authservice/businesslayer/AuthMailServiceTests.java b/auth-service/src/test/java/com/petclinic/authservice/businesslayer/AuthMailServiceTests.java
index 2d46c41905..5a6aeda842 100644
--- a/auth-service/src/test/java/com/petclinic/authservice/businesslayer/AuthMailServiceTests.java
+++ b/auth-service/src/test/java/com/petclinic/authservice/businesslayer/AuthMailServiceTests.java
@@ -23,7 +23,6 @@
import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
@SpringBootTest
@@ -49,7 +48,7 @@ void setUp(){
.thenReturn(Calls.response(format("Message sent to %s", EMAIL_VALID.getTo())));
when(mockMailCall.sendMail(EMAIL_EMPTY_INVALID))
- .thenReturn(Calls.response(Response.error(400, ResponseBody.create(JSON, "Bad request"))));
+ .thenReturn(Calls.response(Response.error(400, ResponseBody.create("Bad request", JSON))));
}
@Test
diff --git a/docker-compose.yml b/docker-compose.yml
index b04dd18273..08c4acc8f7 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,16 +13,7 @@ services:
- SPRING_PROFILES_ACTIVE=docker
depends_on:
- mongo2
-
-# visits:
-# build: visits-service
-# hostname: visits
-# #mem_limit: 350m
-# environment:
-# - SPRING_PROFILES_ACTIVE=docker
-# depends_on:
-# mysql1:
-# condition: service_healthy
+ - mailer-service
inventory-service:
build: inventory-service
@@ -47,16 +38,6 @@ services:
depends_on:
- mongo-customers
-# customers:
-# build: customers-service
-# hostname: customers
-# #mem_limit: 350m
-# environment:
-# - SPRING_PROFILES_ACTIVE=docker
-# depends_on:
-# mysql3:
-# condition: service_healthy
-
api-gateway:
build: api-gateway
#mem_limit: 350m
@@ -101,6 +82,25 @@ services:
env_file:
- mailer.env
+# visits:
+# build: visits-service
+# hostname: visits
+# #mem_limit: 350m
+# environment:
+# - SPRING_PROFILES_ACTIVE=docker
+# depends_on:
+# mysql1:
+# condition: service_healthy
+
+# customers:
+# build: customers-service
+# hostname: customers
+# #mem_limit: 350m
+# environment:
+# - SPRING_PROFILES_ACTIVE=docker
+# depends_on:
+# mysql3:
+# condition: service_healthy
# mysql1:
# image: mysql:5.7
diff --git a/visits-service-new/build.gradle b/visits-service-new/build.gradle
index 812ebabd18..f7fafcaa70 100644
--- a/visits-service-new/build.gradle
+++ b/visits-service-new/build.gradle
@@ -18,25 +18,27 @@ ext {
mapstructVersion = "1.5.5.Final"
}
dependencies {
+ implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive',
+ 'org.springframework.boot:spring-boot-starter-webflux',
+ 'org.yaml:snakeyaml:2.2',
+ "org.mapstruct:mapstruct:${mapstructVersion}",
+ 'org.simplejavamail:simple-java-mail:8.3.1', 'net.markenwerk:utils-mail-dkim:2.0.1', //Simple Java Mail and DKIM a framework for DKIM signing and verification
+ 'com.squareup.retrofit2:retrofit:2.9.0', 'com.squareup.retrofit2:converter-jackson:2.9.0'
- implementation 'org.springframework.boot:spring-boot-starter-data-mongodb-reactive'
- implementation 'org.springframework.boot:spring-boot-starter-webflux'
- compileOnly 'org.projectlombok:lombok'
- annotationProcessor 'org.projectlombok:lombok'
+ compileOnly 'org.projectlombok:lombok',
+ "org.mapstruct:mapstruct-processor:${mapstructVersion}"
-
- implementation("org.mapstruct:mapstruct:${mapstructVersion}")
- compileOnly "org.mapstruct:mapstruct-processor:${mapstructVersion}"
- annotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
testAnnotationProcessor "org.mapstruct:mapstruct-processor:${mapstructVersion}"
+ annotationProcessor 'org.projectlombok:lombok',
+ "org.mapstruct:mapstruct-processor:${mapstructVersion}"
- testImplementation 'org.springframework.boot:spring-boot-starter-test'
- implementation 'org.yaml:snakeyaml:2.2'
- testImplementation 'org.yaml:snakeyaml:2.2'
- testImplementation 'de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring30x:4.9.2'
- testImplementation 'io.projectreactor:reactor-test'
- testImplementation 'com.squareup.okhttp3:okhttp:4.11.0'
- testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0'
+ testImplementation 'com.squareup.okhttp3:mockwebserver:4.11.0', 'com.squareup.okhttp3:okhttp:4.11.0',
+ 'org.simplejavamail:simple-java-mail:8.3.1', 'net.markenwerk:utils-mail-dkim:2.0.1', //Simple Java Mail and DKIM a framework for DKIM signing and verification
+ 'org.springframework.boot:spring-boot-starter-test',
+ 'org.yaml:snakeyaml:2.2',
+ 'de.flapdoodle.embed:de.flapdoodle.embed.mongo.spring30x:4.9.2',
+ 'io.projectreactor:reactor-test',
+ 'com.squareup.retrofit2:retrofit-mock:2.9.0'
}
jacoco {
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImpl.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImpl.java
index 221b84e47f..5d8c10f21b 100644
--- a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImpl.java
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImpl.java
@@ -2,6 +2,10 @@
import com.petclinic.visits.visitsservicenew.DataLayer.Status;
import com.petclinic.visits.visitsservicenew.DataLayer.VisitRepo;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth.AuthServiceClient;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth.UserDetails;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.Mail;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.MailService;
import com.petclinic.visits.visitsservicenew.DomainClientLayer.PetResponseDTO;
import com.petclinic.visits.visitsservicenew.DomainClientLayer.PetsClient;
import com.petclinic.visits.visitsservicenew.DomainClientLayer.VetDTO;
@@ -18,6 +22,8 @@
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
+import static java.lang.String.format;
+
@Service
@RequiredArgsConstructor
@@ -27,6 +33,8 @@ public class VisitServiceImpl implements VisitService {
private final PetsClient petsClient;
private final EntityDtoUtil entityDtoUtil;
+ private final AuthServiceClient authServiceClient;
+ private final MailService mailService;
@Override
public Flux getAllVisits() {
return repo.findAll().flatMap(visit -> entityDtoUtil.toVisitResponseDTO(visit));
@@ -80,11 +88,20 @@ public Mono addVisit(Mono visitRequestDTOMono
.then(validatePetId(visitRequestDTO.getPetId()))
.then(validateVetId(visitRequestDTO.getPractitionerId()))
.then(Mono.just(visitRequestDTO))
+ .doOnNext(s->{
+
+ authServiceClient.getUserById(visitRequestDTO.getJwtToken(), visitRequestDTO.getOwnerId()).subscribe(user->mailService.sendMail(generateVisitRequestEmail(user, visitRequestDTO.getPetId(), visitRequestDTO.getVisitDate())));
+
+ // Mono user = getUserById(auth, ownerId);
+ // try{
+ // simpleJavaMailClient.sendMail(emailBuilder("test@email.com"));
+ // }catch(Exception e){System.out.println("Email failed to send: "+e.getMessage());}
+ })
)
- .doOnNext(v -> System.out.println("Request Date: " + v.getVisitDate())) // Debugging
+// .doOnNext(v -> System.out.println("Request Date: " + v.getVisitDate())) // Debugging
.map(visitRequestDTO -> entityDtoUtil.toVisitEntity(visitRequestDTO))
- .doOnNext(x -> x.setVisitId(entityDtoUtil.generateVisitIdString()))
- .doOnNext(v -> System.out.println("Entity Date: " + v.getVisitDate())) // Debugging
+// .doOnNext(x -> x.setVisitId(entityDtoUtil.generateVisitIdString()))
+// .doOnNext(v -> System.out.println("Entity Date: " + v.getVisitDate())) // Debugging
.flatMap(visit ->
repo.findByVisitDateAndPractitionerId(visit.getVisitDate(), visit.getPractitionerId()) // FindVisits method in repository
.collectList()
@@ -100,10 +117,6 @@ public Mono addVisit(Mono visitRequestDTOMono
.flatMap(visit -> entityDtoUtil.toVisitResponseDTO(visit));
}
-
-
-
-
@Override
public Mono deleteVisit(String visitId) {
return repo.existsByVisitId(visitId)
@@ -217,4 +230,57 @@ else if (dto.getStatus() != Status.UPCOMING){
return Mono.just(dto);
}
}
+
+ private Mail generateVisitRequestEmail(UserDetails user, String petName, LocalDateTime visitDate) {
+ return Mail.builder()
+ .message(
+ format("""
+
+
+
+
+
+ Email Verification
+
+
+
+
+
Dear %s,
+
We have received a request to schedule a visit for your pet with id: %s on the following date and time: %s.
+ \s
+
If you do not wish to create an account, please disregard this email.
+ \s
+
Thank you for choosing Pet Clinic.
+
+
+
+ """, user.getUsername(), petName, visitDate.toString()))
+ .subject("PetClinic Visit request")
+ .to(user.getEmail())
+ .build();
+ }
}
\ No newline at end of file
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/AuthServiceClient.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/AuthServiceClient.java
new file mode 100644
index 0000000000..a9d32809eb
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/AuthServiceClient.java
@@ -0,0 +1,42 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth;
+
+import com.petclinic.visits.visitsservicenew.Exceptions.GenericHttpException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+import static org.springframework.http.HttpStatus.NOT_FOUND;
+
+@Slf4j
+@Component
+public class AuthServiceClient {
+ private final WebClient.Builder webClientBuilder;
+ private final String authServiceUrl;
+ @Autowired
+ private Rethrower rethrower;
+
+ public AuthServiceClient(
+ WebClient.Builder webClientBuilder,
+ @Value("${app.auth-service.host}") String authServiceHost,
+ @Value("${app.auth-service.port}") String authServicePort) {
+ this.webClientBuilder = webClientBuilder;
+ authServiceUrl = "http://" + authServiceHost + ":" + authServicePort;
+ }
+
+ public Mono getUserById(String jwtToken, String userId) {
+ return webClientBuilder.build()
+ .get()
+ .uri(authServiceUrl + "/users/{userId}", userId)
+ .cookie("Bearer", jwtToken)
+ .retrieve()
+ .onStatus(HttpStatusCode::is4xxClientError,
+ n -> rethrower.rethrow(n,
+ x -> new GenericHttpException(x.get("message").toString(), NOT_FOUND))
+ )
+ .bodyToMono(UserDetails.class);
+ }
+}
+
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Rethrower.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Rethrower.java
new file mode 100644
index 0000000000..1084c4d75c
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Rethrower.java
@@ -0,0 +1,30 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+import org.springframework.web.reactive.function.client.ClientResponse;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.function.Function;
+
+@RequiredArgsConstructor
+@Component
+public class Rethrower {
+ private final ObjectMapper objectMapper;
+ public Mono extends Throwable> rethrow(ClientResponse clientResponse, Function exceptionProvider) {
+ return clientResponse.createException().flatMap(n ->
+ {
+ try {
+ final Map map =
+ objectMapper.readValue(n.getResponseBodyAsString(), Map.class);
+ return Mono.error(exceptionProvider.apply(map));
+ } catch (JsonProcessingException e) {
+// e.printStackTrace();
+ return Mono.error(e);
+ }
+ });
+ }
+}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Role.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Role.java
new file mode 100644
index 0000000000..82deece9f7
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/Role.java
@@ -0,0 +1,15 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder(toBuilder = true)
+public class Role {
+ private int id;
+ private String name;
+}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/UserDetails.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/UserDetails.java
new file mode 100644
index 0000000000..4ce1a6326a
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Auth/UserDetails.java
@@ -0,0 +1,23 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Set;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder(toBuilder = true)
+public class UserDetails {
+
+ private String userId;
+ private String username;
+
+ private String email;
+
+ private Set roles;
+}
+
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/Mail.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/Mail.java
new file mode 100644
index 0000000000..0f6c91be3e
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/Mail.java
@@ -0,0 +1,19 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing;
+
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder(toBuilder = true)
+public class Mail {
+
+ private String
+ to,
+ subject,
+ message;
+}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailService.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailService.java
new file mode 100644
index 0000000000..978ecfa592
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailService.java
@@ -0,0 +1,6 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing;
+
+public interface MailService {
+
+ String sendMail(Mail mail);
+}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceCall.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceCall.java
new file mode 100644
index 0000000000..5035c7978b
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceCall.java
@@ -0,0 +1,11 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing;
+
+import retrofit2.Call;
+import retrofit2.http.Body;
+import retrofit2.http.POST;
+
+public interface MailServiceCall {
+
+ @POST("/mail")
+ Call sendMail(@Body Mail mail);
+}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceImpl.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceImpl.java
new file mode 100644
index 0000000000..34f2034dc6
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/Mailing/MailServiceImpl.java
@@ -0,0 +1,33 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpClientErrorException;
+import retrofit2.Response;
+
+import java.io.IOException;
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class MailServiceImpl implements MailService {
+
+ private final MailServiceCall mailServiceCall;
+ @Override
+ public String sendMail(Mail mail) {
+ try {
+ Response execute = mailServiceCall.sendMail(mail).execute();
+ if (execute.code() == 400) {
+ log.error(execute.message());
+ log.error(execute.errorBody().string());
+ throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, execute.errorBody().string());
+ }
+ log.info("Mail service returned {} status code", execute.code());
+ return execute.body();
+ } catch (IOException e) {
+ log.error(e.toString());
+ throw new HttpClientErrorException(HttpStatus.INTERNAL_SERVER_ERROR, "Unable to send mail");
+ }
+ }
+}
\ No newline at end of file
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/VetsClient.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/VetsClient.java
index daa42fdd16..54728d04cb 100644
--- a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/VetsClient.java
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/VetsClient.java
@@ -5,9 +5,10 @@
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
-import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
+import java.util.Objects;
+
@Service
public class VetsClient {
@@ -27,14 +28,13 @@ public VetsClient(@Value("${app.vet-service.host}") String vetServiceHost,
public Mono getVetByVetId(String vetId) {
- Mono vetDTOMono =
- webClient
+ return webClient
.get()
.uri(vetClientServiceBaseURL + "/{vetId}", vetId)
.retrieve()
.onStatus(HttpStatusCode::is4xxClientError, error -> {
HttpStatusCode statusCode = error.statusCode();
- if (statusCode.equals(HttpStatus.NOT_FOUND))
+ if (Objects.equals(statusCode, HttpStatus.NOT_FOUND))
return Mono.error(new NotFoundException("No veterinarian was found with vetId: " + vetId));
return Mono.error(new IllegalArgumentException("Something went wrong"));
})
@@ -42,8 +42,5 @@ public Mono getVetByVetId(String vetId) {
Mono.error(new IllegalArgumentException("Something went wrong"))
)
.bodyToMono(VetDTO.class);
-
- return vetDTOMono;
}
-
}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Exceptions/GenericHttpException.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Exceptions/GenericHttpException.java
new file mode 100644
index 0000000000..438c25b890
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Exceptions/GenericHttpException.java
@@ -0,0 +1,16 @@
+package com.petclinic.visits.visitsservicenew.Exceptions;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.http.HttpStatus;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class GenericHttpException extends RuntimeException {
+
+ private HttpStatus httpStatus;
+ public GenericHttpException(String message, HttpStatus httpStatus) {
+ super(message);
+ this.httpStatus = httpStatus;
+ }
+}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitRequestDTO.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitRequestDTO.java
index fcec85a820..58be07c587 100644
--- a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitRequestDTO.java
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitRequestDTO.java
@@ -14,14 +14,12 @@
@NoArgsConstructor
@Builder
public class VisitRequestDTO {
-
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime visitDate;
-/* private int year;
- private int month;
- private int day;*/
private String description;
private String petId;
+ private String ownerId;
+ private String jwtToken;//used to get the userDetails from the Auth-Service when sending visit emails
private String practitionerId;
private Status status;
}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Utils/Configuration/Mail/MailServiceConfig.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Utils/Configuration/Mail/MailServiceConfig.java
new file mode 100644
index 0000000000..20c3cc4e76
--- /dev/null
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/Utils/Configuration/Mail/MailServiceConfig.java
@@ -0,0 +1,32 @@
+package com.petclinic.visits.visitsservicenew.Utils.Configuration.Mail;
+
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.MailServiceCall;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import retrofit2.Retrofit;
+import retrofit2.converter.jackson.JacksonConverterFactory;
+
+import static java.lang.String.format;
+
+@Configuration
+public class MailServiceConfig {
+
+ private final String MAIL_BASE_URL;
+
+ public MailServiceConfig(
+ @Value("${app.mailer-service.host}") String mailURL,
+ @Value("${app.mailer-service.port}") String mailPORT
+ ) {
+ MAIL_BASE_URL = format("http://%s:%s", mailURL, mailPORT);
+ }
+
+ @Bean
+ public MailServiceCall getMailerServiceCall() {
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl(MAIL_BASE_URL)
+ .addConverterFactory(JacksonConverterFactory.create())
+ .build();
+ return retrofit.create(MailServiceCall.class);
+ }
+}
diff --git a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/VisitsServiceNewApplication.java b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/VisitsServiceNewApplication.java
index 97c894e22b..8ea54dee61 100644
--- a/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/VisitsServiceNewApplication.java
+++ b/visits-service-new/src/main/java/com/petclinic/visits/visitsservicenew/VisitsServiceNewApplication.java
@@ -2,8 +2,6 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.context.annotation.Bean;
-import org.springframework.core.io.ClassPathResource;
@SpringBootApplication
diff --git a/visits-service-new/src/main/resources/application.yml b/visits-service-new/src/main/resources/application.yml
index 68a98165df..6a3ff3720b 100644
--- a/visits-service-new/src/main/resources/application.yml
+++ b/visits-service-new/src/main/resources/application.yml
@@ -8,6 +8,12 @@ app:
customers-service-reactive:
host: localhost
port: 8090
+ auth-service:
+ host: localhost
+ port: 7005
+ mailer-service:
+ host: localhost
+ port: 8888
logging:
@@ -62,12 +68,19 @@ app:
vet-service:
host: vet-service
port: 8080
-
customers-service-reactive:
host: customers-service-reactive
port: 8080
+ auth-service:
+ host: auth
+ port: 8080
+ mailer-service:
+ host: mailer-service
+ port: 8080
logging:
level:
root: INFO
- com.petclinic: DEBUG
\ No newline at end of file
+ com.petclinic: DEBUG
+
+server.port: 8080
\ No newline at end of file
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/MailServiceTests.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/MailServiceTests.java
new file mode 100644
index 0000000000..21b97421fb
--- /dev/null
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/MailServiceTests.java
@@ -0,0 +1,73 @@
+package com.petclinic.visits.visitsservicenew.BusinessLayer;
+
+
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.Mail;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.MailService;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.MailServiceCall;
+import okhttp3.MediaType;
+import okhttp3.ResponseBody;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+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.mock.mockito.MockBean;
+import org.springframework.web.client.HttpClientErrorException;
+import retrofit2.Response;
+import retrofit2.mock.Calls;
+
+import java.io.IOException;
+
+import static java.lang.String.format;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.when;
+
+@SpringBootTest()
+public class MailServiceTests {
+ @Autowired
+ private MailService mailService;
+
+ @MockBean
+ private MailServiceCall mockMailCall;
+
+ private final Mail
+ EMAIL_VALID = new Mail("to@test.com", "test-subject", "test-message"),
+ EMAIL_EMPTY_INVALID = new Mail();
+ public final MediaType JSON
+ = MediaType.parse("application/json; charset=utf-8");
+
+ @BeforeEach
+ void setUp(){
+ when(mockMailCall.sendMail(EMAIL_VALID)).thenReturn(Calls.response(format("Message sent to %s", EMAIL_VALID.getTo())));
+ when(mockMailCall.sendMail(EMAIL_EMPTY_INVALID)).thenReturn(Calls.response(Response.error(400, ResponseBody.create("Bad request", JSON))));
+ }
+
+ @Test
+ void loads(){}
+
+ @Test
+ @DisplayName("Send valid email")
+ void send_valid_email() {
+ assertEquals("Message sent to " + EMAIL_VALID.getTo(), mailService.sendMail(EMAIL_VALID));
+ }
+
+ @Test
+ @DisplayName("Send invalid empty email")
+ void send_invalid_empty_email() {
+ HttpClientErrorException httpClientErrorException =
+ assertThrows(HttpClientErrorException.class, () -> mailService.sendMail(EMAIL_EMPTY_INVALID));
+ assertEquals("400 Bad Request", httpClientErrorException.getMessage());
+ }
+
+ @Test
+ @DisplayName("IOException graceful handling")
+ void io_exception_graceful_handling() {
+ when(mockMailCall.sendMail(EMAIL_EMPTY_INVALID)).thenReturn(Calls.failure(new IOException()));
+ HttpClientErrorException httpClientErrorException =
+ assertThrows(HttpClientErrorException.class, () -> mailService.sendMail(EMAIL_EMPTY_INVALID));
+ assertEquals("500 Unable to send mail", httpClientErrorException.getMessage());
+ }
+
+
+}
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImplTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImplTest.java
index cb5a13aa62..c743637d31 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImplTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/BusinessLayer/VisitServiceImplTest.java
@@ -3,18 +3,17 @@
import com.petclinic.visits.visitsservicenew.DataLayer.Status;
import com.petclinic.visits.visitsservicenew.DataLayer.Visit;
import com.petclinic.visits.visitsservicenew.DataLayer.VisitRepo;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.Mail;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Mailing.MailService;
import com.petclinic.visits.visitsservicenew.DomainClientLayer.*;
-import com.petclinic.visits.visitsservicenew.Exceptions.DuplicateTimeException;
import com.petclinic.visits.visitsservicenew.Exceptions.BadRequestException;
+import com.petclinic.visits.visitsservicenew.Exceptions.DuplicateTimeException;
import com.petclinic.visits.visitsservicenew.Exceptions.NotFoundException;
import com.petclinic.visits.visitsservicenew.PresentationLayer.VisitRequestDTO;
import com.petclinic.visits.visitsservicenew.PresentationLayer.VisitResponseDTO;
import com.petclinic.visits.visitsservicenew.Utils.EntityDtoUtil;
-import okhttp3.mockwebserver.MockResponse;
-import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
-import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient;
import org.springframework.boot.test.context.SpringBootTest;
@@ -23,14 +22,14 @@
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Mockito.*;
-import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
-
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.*;
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
+
@SpringBootTest(webEnvironment = RANDOM_PORT, properties = {"spring.data.mongodb.port: 0"})
@AutoConfigureWebTestClient
@@ -44,20 +43,21 @@ class VisitServiceImplTest {
@MockBean
private VetsClient vetsClient;
-
@MockBean
private PetsClient petsClient;
+ @MockBean
+ private MailService mailService;
@MockBean
private EntityDtoUtil entityDtoUtil;
- private final Long dbSize = 2L;
+// private final Long dbSize = 2L;
private final VisitResponseDTO visitResponseDTO = buildVisitResponseDTO();
private final VisitRequestDTO visitRequestDTO = buildVisitRequestDTO();
private final String PRAC_ID = visitResponseDTO.getPractitionerId();
- private final String PET_ID = visitResponseDTO.getPetId();
- private final String VISIT_ID = visitResponseDTO.getVisitId();
+// private final String PET_ID = visitResponseDTO.getPetId();
+// private final String VISIT_ID = visitResponseDTO.getVisitId();
String uuidVet = UUID.randomUUID().toString();
@@ -93,7 +93,7 @@ class VisitServiceImplTest {
Visit visit1 = buildVisit("this is a dummy description");
- Visit visit2 = buildVisit("this is a dummy description");
+// Visit visit2 = buildVisit("this is a dummy description");
@Test
@@ -638,7 +638,6 @@ void deleteAllCancelledVisits () {
Mockito.verify(visitRepo, Mockito.times(1)).deleteAll(cancelledVisits);
}
-
@Test
void deleteAllCanceledVisits_shouldThrowRuntimeException () {
// Arrange
@@ -696,10 +695,4 @@ private Mono buildRequestDtoMono () {
VisitRequestDTO requestDTO = buildVisitRequestDTO();
return Mono.just(requestDTO);
}
-
-
-}
-
-
-
-
+}
\ No newline at end of file
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DataLayer/VisitRepoTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DataLayer/VisitRepoTest.java
index 60bc07bb72..0de1fe6c6c 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DataLayer/VisitRepoTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DataLayer/VisitRepoTest.java
@@ -1,10 +1,10 @@
package com.petclinic.visits.visitsservicenew.DataLayer;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
-import org.junit.jupiter.api.Test;
import reactor.test.StepVerifier;
import java.time.LocalDateTime;
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/AuthServiceClientIntegrationTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/AuthServiceClientIntegrationTest.java
new file mode 100644
index 0000000000..0dadd4d308
--- /dev/null
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/DomainClientLayer/AuthServiceClientIntegrationTest.java
@@ -0,0 +1,64 @@
+package com.petclinic.visits.visitsservicenew.DomainClientLayer;
+
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth.AuthServiceClient;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Auth.UserDetails;
+import lombok.RequiredArgsConstructor;
+import okhttp3.mockwebserver.MockResponse;
+import okhttp3.mockwebserver.MockWebServer;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+import reactor.test.StepVerifier;
+
+import java.io.IOException;
+@RequiredArgsConstructor
+public class AuthServiceClientIntegrationTest {
+ private MockWebServer server;
+ private AuthServiceClient authServiceClient;
+ @BeforeEach
+ void setup() {
+ server = new MockWebServer();
+ authServiceClient = new AuthServiceClient(
+ WebClient.builder(),
+ server.getHostName(),
+ String.valueOf(server.getPort()));
+ }
+
+ @AfterEach
+ void shutdown() throws IOException {
+ server.shutdown();
+ }
+
+
+
+
+ @Test
+ @DisplayName("Should return user details when valid userId is provided")
+ void shouldReturnUserDetails_WhenValidUserIdIsProvided() throws IOException {
+ // Arrange
+ UserDetails expectedUser = UserDetails.builder()
+ .username("username")
+ .userId("userId")
+ .email("email")
+ .build();
+ String jwtToken = "jwtToken";
+ String userId = "userId";
+
+ server.enqueue(new MockResponse()
+ .setHeader("Content-Type", "application/json")
+ .setBody(new ObjectMapper().writeValueAsString(expectedUser)));
+
+ // Act
+ Mono result = authServiceClient.getUserById(jwtToken, userId);
+
+ // Assert
+ StepVerifier.create(result)
+ .expectNext(expectedUser)
+ .verifyComplete();
+ }
+}
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/BadRequestExceptionTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/BadRequestExceptionTest.java
index ba3106a65f..2e87c1acd6 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/BadRequestExceptionTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/BadRequestExceptionTest.java
@@ -1,11 +1,9 @@
package com.petclinic.visits.visitsservicenew.Exceptions;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.junit.jupiter.SpringExtension;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
class BadRequestExceptionTest {
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/GlobalControllerExceptionHandlerTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/GlobalControllerExceptionHandlerTest.java
index c3210a912b..9b7d216d0f 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/GlobalControllerExceptionHandlerTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/GlobalControllerExceptionHandlerTest.java
@@ -9,9 +9,8 @@
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
@SpringBootTest
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/NotFoundExceptionTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/NotFoundExceptionTest.java
index b8075439c5..0241ea2885 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/NotFoundExceptionTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Exceptions/NotFoundExceptionTest.java
@@ -2,11 +2,9 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.internal.matchers.Not;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
-
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
@ExtendWith(SpringExtension.class)
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitControllerUnitTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitControllerUnitTest.java
index f9e50d24ec..f9f2a00d62 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitControllerUnitTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitControllerUnitTest.java
@@ -3,8 +3,9 @@
import com.petclinic.visits.visitsservicenew.BusinessLayer.VisitService;
import com.petclinic.visits.visitsservicenew.DataLayer.Status;
-import com.petclinic.visits.visitsservicenew.DataLayer.Visit;
-import com.petclinic.visits.visitsservicenew.DomainClientLayer.*;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.SpecialtyDTO;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.VetDTO;
+import com.petclinic.visits.visitsservicenew.DomainClientLayer.Workday;
import com.petclinic.visits.visitsservicenew.Exceptions.NotFoundException;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
@@ -15,15 +16,14 @@
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
-import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
@WebFluxTest(VisitController.class)
class VisitControllerUnitTest {
@@ -253,7 +253,7 @@ void deleteAllCancelledVisits_shouldSucceed(){
Mockito.when(visitService.deleteAllCancelledVisits()).thenReturn(Mono.empty());
// Act & Assert
- webTestClient
+ webTestClient
.delete()
.uri("/visits/cancelled")
.exchange()
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitsControllerIntegrationTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitsControllerIntegrationTest.java
index c52b5e894b..dd5fc98686 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitsControllerIntegrationTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/PresentationLayer/VisitsControllerIntegrationTest.java
@@ -13,14 +13,8 @@
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.reactive.server.WebTestClient;
-import org.springframework.web.reactive.function.BodyInserters;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.when;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@@ -29,6 +23,12 @@
import java.util.Set;
import java.util.UUID;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+
@AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
diff --git a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Utils/EntityDtoUtilTest.java b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Utils/EntityDtoUtilTest.java
index b3bdc0ca69..73b3f36a90 100644
--- a/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Utils/EntityDtoUtilTest.java
+++ b/visits-service-new/src/test/java/com/petclinic/visits/visitsservicenew/Utils/EntityDtoUtilTest.java
@@ -6,7 +6,6 @@
import com.petclinic.visits.visitsservicenew.DomainClientLayer.VetDTO;
import com.petclinic.visits.visitsservicenew.DomainClientLayer.VetsClient;
import com.petclinic.visits.visitsservicenew.PresentationLayer.VisitRequestDTO;
-
import com.petclinic.visits.visitsservicenew.PresentationLayer.VisitResponseDTO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;