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 }}, + + + 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

+
+
+ +
+ + +
+
+ + Cancel +
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));