diff --git a/pom.xml b/pom.xml index 9aba7d2..16e63df 100644 --- a/pom.xml +++ b/pom.xml @@ -141,7 +141,7 @@ com.ecmsp protos - 1.0.0-20251105.185705-41 + 1.0.0-20251109.095920-47 diff --git a/src/main/java/com/ecmsp/userservice/api/grpc/RoleGrpcMapper.java b/src/main/java/com/ecmsp/userservice/api/grpc/RoleGrpcMapper.java new file mode 100644 index 0000000..a096dbf --- /dev/null +++ b/src/main/java/com/ecmsp/userservice/api/grpc/RoleGrpcMapper.java @@ -0,0 +1,39 @@ +package com.ecmsp.userservice.api.grpc; + +import com.ecmsp.userservice.user.domain.Permission; +import com.ecmsp.userservice.user.domain.RoleToCreate; +import org.springframework.stereotype.Component; + +import java.util.Set; +import java.util.stream.Collectors; + +@Component +public class RoleGrpcMapper { + + private final UserGrpcMapper userGrpcMapper; + + public RoleGrpcMapper(UserGrpcMapper userGrpcMapper) { + this.userGrpcMapper = userGrpcMapper; + } + + public Permission toDomainPermission(String permissionName) { + return Permission.valueOf(permissionName); + } + + public RoleToCreate toDomainRoleToCreate(com.ecmsp.user.v1.Role protoRole) { + Set permissions = protoRole.getPermissionsList().stream() + .map(this::toDomainPermission) + .collect(Collectors.toSet()); + + return new RoleToCreate(protoRole.getName(), permissions); + } + + // Delegate to UserGrpcMapper for proto conversions (reuse existing methods) + public com.ecmsp.user.v1.Role toProtoRole(com.ecmsp.userservice.user.domain.Role domainRole) { + return userGrpcMapper.toProtoRole(domainRole); + } + + public String toProtoPermission(Permission permission) { + return userGrpcMapper.toProtoPermission(permission); + } +} diff --git a/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcMapper.java b/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcMapper.java index 202d055..1231171 100644 --- a/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcMapper.java +++ b/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcMapper.java @@ -1,6 +1,5 @@ package com.ecmsp.userservice.api.grpc; -import com.ecmsp.user.v1.RoleId; import com.ecmsp.user.v1.UserId; import com.ecmsp.userservice.user.domain.Permission; import com.ecmsp.userservice.user.domain.Role; @@ -31,7 +30,6 @@ public UserId toProtoUserId(com.ecmsp.userservice.user.domain.UserId domainUserI public com.ecmsp.user.v1.Role toProtoRole(Role domainRole) { return com.ecmsp.user.v1.Role.newBuilder() - .setId(toProtoRoleId(domainRole.id())) .setName(domainRole.name()) .addAllPermissions(domainRole.permissions().stream() .map(this::toProtoPermission) @@ -39,12 +37,6 @@ public com.ecmsp.user.v1.Role toProtoRole(Role domainRole) { .build(); } - public RoleId toProtoRoleId(com.ecmsp.userservice.user.domain.RoleId domainRoleId) { - return RoleId.newBuilder() - .setValue(domainRoleId.value().toString()) - .build(); - } - public String toProtoPermission(Permission permission) { return permission.name(); } diff --git a/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcService.java b/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcService.java index a0dc821..3eb8431 100644 --- a/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcService.java +++ b/src/main/java/com/ecmsp/userservice/api/grpc/UserGrpcService.java @@ -1,26 +1,37 @@ package com.ecmsp.userservice.api.grpc; import com.ecmsp.user.v1.*; -import com.ecmsp.userservice.user.domain.User; +import com.ecmsp.userservice.user.domain.Permission; +import com.ecmsp.userservice.user.domain.RoleFacade; +import com.ecmsp.userservice.user.domain.RoleToCreate; import com.ecmsp.userservice.user.domain.UserFacade; -import com.ecmsp.userservice.user.domain.UserId; import com.ecmsp.userservice.user.domain.UserView; import io.grpc.Status; import io.grpc.stub.StreamObserver; import net.devh.boot.grpc.server.service.GrpcService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; @GrpcService public class UserGrpcService extends UserServiceGrpc.UserServiceImplBase { + private static final Logger log = LoggerFactory.getLogger(UserGrpcService.class); + private final UserFacade userFacade; + private final RoleFacade roleFacade; private final UserGrpcMapper mapper; + private final RoleGrpcMapper roleMapper; - public UserGrpcService(UserFacade userFacade, UserGrpcMapper mapper) { + public UserGrpcService(UserFacade userFacade, RoleFacade roleFacade, UserGrpcMapper mapper, RoleGrpcMapper roleMapper) { this.userFacade = userFacade; + this.roleFacade = roleFacade; this.mapper = mapper; + this.roleMapper = roleMapper; } @Override @@ -29,11 +40,11 @@ public void getUser(GetUserRequest request, StreamObserver resp com.ecmsp.user.v1.UserId protoUserId = com.ecmsp.user.v1.UserId.newBuilder() .setValue(request.getUserId()) .build(); - UserId userId = mapper.toDomainUserId(protoUserId); - Optional userOptional = userFacade.findUserById(userId); + com.ecmsp.userservice.user.domain.UserId userId = mapper.toDomainUserId(protoUserId); + Optional userOptional = userFacade.findUserById(userId); if (userOptional.isPresent()) { - User user = userOptional.get(); + com.ecmsp.userservice.user.domain.User user = userOptional.get(); UserView userView = new UserView(user.id(), user.login(), user.roles()); com.ecmsp.user.v1.User protoUser = mapper.toProtoUser(userView); @@ -80,7 +91,7 @@ public void createUser(CreateUserRequest request, StreamObserver responseObserver) { try { - UserId userId = mapper.toDomainUserId(request.getUser().getId()); + com.ecmsp.userservice.user.domain.UserId userId = mapper.toDomainUserId(request.getUser().getId()); String newLogin = request.getUser().getLogin(); if (newLogin == null || newLogin.isBlank()) { @@ -124,9 +135,9 @@ public void updateUser(UpdateUserRequest request, StreamObserver updatedUserOptional = userFacade.findUserById(userId); + Optional updatedUserOptional = userFacade.findUserById(userId); if (updatedUserOptional.isPresent()) { - User updatedUser = updatedUserOptional.get(); + com.ecmsp.userservice.user.domain.User updatedUser = updatedUserOptional.get(); UserView userView = new UserView(updatedUser.id(), updatedUser.login(), updatedUser.roles()); com.ecmsp.user.v1.User protoUser = mapper.toProtoUser(userView); @@ -158,7 +169,7 @@ public void deleteUser(DeleteUserRequest request, StreamObserver responseObserver) { - // TODO: Implement role management later - responseObserver.onError(Status.UNIMPLEMENTED - .withDescription("Role management not yet implemented") - .asRuntimeException()); + try { + log.info("Creating role: {}", request.getRole().getName()); + + RoleToCreate roleToCreate = roleMapper.toDomainRoleToCreate(request.getRole()); + com.ecmsp.userservice.user.domain.RoleId roleId = roleFacade.createRole(roleToCreate); + + com.ecmsp.userservice.user.domain.Role createdRole = roleFacade.findRoleById(roleId) + .orElseThrow(() -> new IllegalStateException("Role not found after creation")); + + CreateRoleResponse response = CreateRoleResponse.newBuilder() + .setRole(roleMapper.toProtoRole(createdRole)) + .build(); + + responseObserver.onNext(response); + responseObserver.onCompleted(); + + log.info("Role created successfully: {}", roleId.value()); + } catch (IllegalArgumentException e) { + log.error("Invalid role data: {}", e.getMessage()); + // Check if it's a duplicate role error + if (e.getMessage().contains("already exists")) { + responseObserver.onError(Status.ALREADY_EXISTS + .withDescription(e.getMessage()) + .asRuntimeException()); + } else { + responseObserver.onError(Status.INVALID_ARGUMENT + .withDescription(e.getMessage()) + .asRuntimeException()); + } + } catch (Exception e) { + log.error("Error creating role", e); + responseObserver.onError(Status.INTERNAL + .withDescription("Failed to create role: " + e.getMessage()) + .asRuntimeException()); + } } @Override public void updateRole(UpdateRoleRequest request, StreamObserver responseObserver) { - // TODO: Implement role management later - responseObserver.onError(Status.UNIMPLEMENTED - .withDescription("Role management not yet implemented") - .asRuntimeException()); + try { + String roleName = request.getRole().getName(); + log.info("Updating role: {}", roleName); + + // Get current role by name + com.ecmsp.userservice.user.domain.Role currentRole = roleFacade.findRoleByName(roleName) + .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleName)); + + // Get the role ID for subsequent operations + com.ecmsp.userservice.user.domain.RoleId roleId = currentRole.id(); + + // Determine permissions to add and remove + Set newPermissions = request.getRole().getPermissionsList().stream() + .map(roleMapper::toDomainPermission) + .collect(Collectors.toSet()); + + Set currentPermissions = currentRole.permissions(); + + // Add new permissions + newPermissions.stream() + .filter(p -> !currentPermissions.contains(p)) + .forEach(p -> roleFacade.addPermissionToRole(roleId, p)); + + // Remove old permissions + currentPermissions.stream() + .filter(p -> !newPermissions.contains(p)) + .forEach(p -> roleFacade.removePermissionFromRole(roleId, p)); + + // Get updated role + com.ecmsp.userservice.user.domain.Role updatedRole = roleFacade.findRoleById(roleId) + .orElseThrow(() -> new IllegalStateException("Role not found after update")); + + UpdateRoleResponse response = UpdateRoleResponse.newBuilder() + .setRole(roleMapper.toProtoRole(updatedRole)) + .build(); + + responseObserver.onNext(response); + responseObserver.onCompleted(); + + log.info("Role updated successfully: {}", roleName); + } catch (IllegalArgumentException e) { + log.error("Invalid role data: {}", e.getMessage()); + responseObserver.onError(Status.INVALID_ARGUMENT + .withDescription(e.getMessage()) + .asRuntimeException()); + } catch (Exception e) { + log.error("Error updating role", e); + responseObserver.onError(Status.INTERNAL + .withDescription("Failed to update role: " + e.getMessage()) + .asRuntimeException()); + } } @Override public void deleteRole(DeleteRoleRequest request, StreamObserver responseObserver) { - // TODO: Implement role management later - responseObserver.onError(Status.UNIMPLEMENTED - .withDescription("Role management not yet implemented") - .asRuntimeException()); + try { + String roleName = request.getRoleId(); + log.info("Deleting role: {}", roleName); + + roleFacade.deleteRoleByName(roleName); + + DeleteRoleResponse response = DeleteRoleResponse.newBuilder().build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + log.info("Role deleted successfully: {}", roleName); + } catch (IllegalArgumentException e) { + log.error("Invalid role name: {}", e.getMessage()); + responseObserver.onError(Status.INVALID_ARGUMENT + .withDescription(e.getMessage()) + .asRuntimeException()); + } catch (Exception e) { + log.error("Error deleting role", e); + responseObserver.onError(Status.INTERNAL + .withDescription("Failed to delete role: " + e.getMessage()) + .asRuntimeException()); + } } @Override public void listRoles(ListRolesRequest request, StreamObserver responseObserver) { - // TODO: Implement role management later - responseObserver.onError(Status.UNIMPLEMENTED - .withDescription("Role management not yet implemented") - .asRuntimeException()); + try { + log.info("Listing all roles"); + + List roles = roleFacade.getAllRoles(); + List protoRoles = roles.stream() + .map(roleMapper::toProtoRole) + .collect(Collectors.toList()); + + ListRolesResponse response = ListRolesResponse.newBuilder() + .addAllRoles(protoRoles) + .build(); + + responseObserver.onNext(response); + responseObserver.onCompleted(); + + log.info("Listed {} roles", roles.size()); + } catch (Exception e) { + log.error("Error listing roles", e); + responseObserver.onError(Status.INTERNAL + .withDescription("Failed to list roles: " + e.getMessage()) + .asRuntimeException()); + } } @Override public void assignRoleToUsers(AssignRoleToUsersRequest request, StreamObserver responseObserver) { - // TODO: Implement role management later - responseObserver.onError(Status.UNIMPLEMENTED - .withDescription("Role management not yet implemented") - .asRuntimeException()); + try { + String roleName = request.getRoleName(); + log.info("Assigning role {} to {} users", roleName, request.getUserIdsList().size()); + + // Verify role exists + roleFacade.findRoleByName(roleName) + .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleName)); + + // Assign role to each user + for (String userIdString : request.getUserIdsList()) { + com.ecmsp.userservice.user.domain.UserId userId = new com.ecmsp.userservice.user.domain.UserId( + java.util.UUID.fromString(userIdString) + ); + userFacade.assignRoleToUser(userId, roleName); + } + + AssignRoleToUsersResponse response = AssignRoleToUsersResponse.newBuilder().build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + log.info("Role assigned successfully to {} users", request.getUserIdsList().size()); + } catch (IllegalArgumentException e) { + log.error("Invalid assignment data: {}", e.getMessage()); + responseObserver.onError(Status.INVALID_ARGUMENT + .withDescription(e.getMessage()) + .asRuntimeException()); + } catch (Exception e) { + log.error("Error assigning role to users", e); + responseObserver.onError(Status.INTERNAL + .withDescription("Failed to assign role: " + e.getMessage()) + .asRuntimeException()); + } } @Override public void removeRoleFromUsers(RemoveRoleFromUsersRequest request, StreamObserver responseObserver) { - // TODO: Implement role management later - responseObserver.onError(Status.UNIMPLEMENTED - .withDescription("Role management not yet implemented") - .asRuntimeException()); + try { + String roleName = request.getRoleName(); + log.info("Removing role {} from {} users", roleName, request.getUserIdsList().size()); + + // Verify role exists + roleFacade.findRoleByName(roleName) + .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleName)); + + // Remove role from each user + for (String userIdString : request.getUserIdsList()) { + com.ecmsp.userservice.user.domain.UserId userId = new com.ecmsp.userservice.user.domain.UserId( + java.util.UUID.fromString(userIdString) + ); + userFacade.removeRoleFromUser(userId, roleName); + } + + RemoveRoleFromUsersResponse response = RemoveRoleFromUsersResponse.newBuilder().build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + + log.info("Role removed successfully from {} users", request.getUserIdsList().size()); + } catch (IllegalArgumentException e) { + log.error("Invalid removal data: {}", e.getMessage()); + responseObserver.onError(Status.INVALID_ARGUMENT + .withDescription(e.getMessage()) + .asRuntimeException()); + } catch (Exception e) { + log.error("Error removing role from users", e); + responseObserver.onError(Status.INTERNAL + .withDescription("Failed to remove role: " + e.getMessage()) + .asRuntimeException()); + } } @Override public void listAllPermissions(ListAllPermissionsRequest request, StreamObserver responseObserver) { - // TODO: Implement role management later - responseObserver.onError(Status.UNIMPLEMENTED - .withDescription("Role management not yet implemented") - .asRuntimeException()); + try { + log.info("Listing all available permissions"); + + List permissions = Arrays.stream(Permission.values()) + .map(Permission::name) + .collect(Collectors.toList()); + + ListAllPermissionsResponse response = ListAllPermissionsResponse.newBuilder() + .addAllPermissions(permissions) + .build(); + + responseObserver.onNext(response); + responseObserver.onCompleted(); + + log.info("Listed {} permissions", permissions.size()); + } catch (Exception e) { + log.error("Error listing permissions", e); + responseObserver.onError(Status.INTERNAL + .withDescription("Failed to list permissions: " + e.getMessage()) + .asRuntimeException()); + } } } diff --git a/src/main/java/com/ecmsp/userservice/api/rest/UserController.java b/src/main/java/com/ecmsp/userservice/api/rest/UserController.java index 10297d3..a14584b 100644 --- a/src/main/java/com/ecmsp/userservice/api/rest/UserController.java +++ b/src/main/java/com/ecmsp/userservice/api/rest/UserController.java @@ -4,7 +4,6 @@ import com.ecmsp.userservice.api.rest.role.AssignRoleRequest; import com.ecmsp.userservice.api.rest.role.RoleResponse; import com.ecmsp.userservice.user.domain.Role; -import com.ecmsp.userservice.user.domain.RoleId; import com.ecmsp.userservice.user.domain.UserFacade; import com.ecmsp.userservice.user.domain.UserId; import com.ecmsp.userservice.user.domain.UserToCreate; @@ -38,15 +37,15 @@ public ResponseEntity createUser(@RequestBody UserCreateRequest request) { public ResponseEntity assignRoleToUser( @PathVariable UUID userId, @RequestBody AssignRoleRequest request) { - userFacade.assignRoleToUser(new UserId(userId), new RoleId(request.roleId())); + userFacade.assignRoleToUser(new UserId(userId), request.roleName()); return ResponseEntity.ok().build(); } - @DeleteMapping("/{userId}/roles/{roleId}") + @DeleteMapping("/{userId}/roles/{roleName}") public ResponseEntity removeRoleFromUser( @PathVariable UUID userId, - @PathVariable UUID roleId) { - userFacade.removeRoleFromUser(new UserId(userId), new RoleId(roleId)); + @PathVariable String roleName) { + userFacade.removeRoleFromUser(new UserId(userId), roleName); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/ecmsp/userservice/api/rest/role/AssignRoleRequest.java b/src/main/java/com/ecmsp/userservice/api/rest/role/AssignRoleRequest.java index 066b5da..0336f90 100644 --- a/src/main/java/com/ecmsp/userservice/api/rest/role/AssignRoleRequest.java +++ b/src/main/java/com/ecmsp/userservice/api/rest/role/AssignRoleRequest.java @@ -1,6 +1,4 @@ package com.ecmsp.userservice.api.rest.role; -import java.util.UUID; - -public record AssignRoleRequest(UUID roleId) { +public record AssignRoleRequest(String roleName) { } diff --git a/src/main/java/com/ecmsp/userservice/api/rest/role/RoleController.java b/src/main/java/com/ecmsp/userservice/api/rest/role/RoleController.java index a179c24..2663f7e 100644 --- a/src/main/java/com/ecmsp/userservice/api/rest/role/RoleController.java +++ b/src/main/java/com/ecmsp/userservice/api/rest/role/RoleController.java @@ -22,6 +22,19 @@ public RoleController(RoleFacade roleFacade) { this.roleFacade = roleFacade; } + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { + if (e.getMessage().contains("already exists")) { + return ResponseEntity.status(HttpStatus.CONFLICT) + .body(new ErrorResponse(e.getMessage())); + } + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(new ErrorResponse(e.getMessage())); + } + + record ErrorResponse(String message) { + } + @PostMapping public ResponseEntity createRole(@RequestBody RoleCreateRequest request) { RoleToCreate roleToCreate = new RoleToCreate(request.name(), request.permissions()); @@ -39,9 +52,9 @@ public ResponseEntity createRole(@RequestBody RoleCreateRequest re return ResponseEntity.status(HttpStatus.CREATED).body(response); } - @GetMapping("/{roleId}") - public ResponseEntity getRoleById(@PathVariable UUID roleId) { - return roleFacade.findRoleById(new RoleId(roleId)) + @GetMapping("/{roleName}") + public ResponseEntity getRoleByName(@PathVariable String roleName) { + return roleFacade.findRoleByName(roleName) .map(role -> new RoleResponse( role.id().value(), role.name(), @@ -64,28 +77,28 @@ public ResponseEntity> getAllRoles() { return ResponseEntity.ok(roles); } - @PostMapping("/{roleId}/permissions") + @PostMapping("/{roleName}/permissions") public ResponseEntity addPermissionToRole( - @PathVariable UUID roleId, + @PathVariable String roleName, @RequestBody AddPermissionRequest request) { - roleFacade.addPermissionToRole(new RoleId(roleId), request.permission()); + roleFacade.addPermissionToRoleByName(roleName, request.permission()); return ResponseEntity.ok().build(); } - @DeleteMapping("/{roleId}/permissions/{permission}") + @DeleteMapping("/{roleName}/permissions/{permission}") public ResponseEntity removePermissionFromRole( - @PathVariable UUID roleId, + @PathVariable String roleName, @PathVariable String permission) { - roleFacade.removePermissionFromRole( - new RoleId(roleId), + roleFacade.removePermissionFromRoleByName( + roleName, com.ecmsp.userservice.user.domain.Permission.valueOf(permission) ); return ResponseEntity.ok().build(); } - @DeleteMapping("/{roleId}") - public ResponseEntity deleteRole(@PathVariable UUID roleId) { - roleFacade.deleteRole(new RoleId(roleId)); + @DeleteMapping("/{roleName}") + public ResponseEntity deleteRole(@PathVariable String roleName) { + roleFacade.deleteRoleByName(roleName); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/DbUserRepository.java b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/DbUserRepository.java index ddc439b..9dedf68 100644 --- a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/DbUserRepository.java +++ b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/DbUserRepository.java @@ -63,4 +63,9 @@ public List findByLoginContaining(String loginFilter) { public void updateLogin(UserId userId, String newLogin) { userEntityRepository.updateLogin(userId.value(), newLogin); } + + @Transactional + public void upsert(User user) { + userEntityRepository.save(userMapper.toUserEntity(user)); + } } diff --git a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntity.java b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntity.java index 6cf28ae..8c715f7 100644 --- a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntity.java +++ b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntity.java @@ -14,7 +14,7 @@ @NoArgsConstructor @Entity @Table(name = "roles") -class RoleEntity { +public class RoleEntity { @Id @Column(name = "role_id") diff --git a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntityRepository.java b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntityRepository.java index 1e8d548..623b3d1 100644 --- a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntityRepository.java +++ b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/RoleEntityRepository.java @@ -5,6 +5,6 @@ import java.util.Optional; import java.util.UUID; -interface RoleEntityRepository extends JpaRepository { +public interface RoleEntityRepository extends JpaRepository { Optional findByRoleName(String roleName); } diff --git a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntity.java b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntity.java index 9ebed41..30ceab5 100644 --- a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntity.java +++ b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntity.java @@ -14,7 +14,7 @@ @NoArgsConstructor @Entity @Table(name = "users") -class UserEntity { +public class UserEntity { @Id @Column(name = "user_id") diff --git a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntityRepository.java b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntityRepository.java index 1f0bead..e8ed28f 100644 --- a/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntityRepository.java +++ b/src/main/java/com/ecmsp/userservice/user/adapter/repository/db/UserEntityRepository.java @@ -10,7 +10,7 @@ import java.util.UUID; @Repository -interface UserEntityRepository extends JpaRepository { +public interface UserEntityRepository extends JpaRepository { @Query("SELECT u FROM UserEntity u WHERE u.login = :login") Optional findByLogin(String login); diff --git a/src/main/java/com/ecmsp/userservice/user/config/UserConfig.java b/src/main/java/com/ecmsp/userservice/user/config/UserConfig.java index 0090dd9..d704b63 100644 --- a/src/main/java/com/ecmsp/userservice/user/config/UserConfig.java +++ b/src/main/java/com/ecmsp/userservice/user/config/UserConfig.java @@ -1,5 +1,7 @@ package com.ecmsp.userservice.user.config; +import com.ecmsp.userservice.user.adapter.repository.db.RoleEntityRepository; +import com.ecmsp.userservice.user.adapter.repository.db.UserEntityRepository; import com.ecmsp.userservice.user.domain.RoleRepository; import com.ecmsp.userservice.user.domain.UserFacade; import com.ecmsp.userservice.user.domain.UserRepository; @@ -9,7 +11,7 @@ @Configuration class UserConfig { @Bean - public UserFacade userFacade(UserRepository userRepository, RoleRepository roleRepository){ - return new UserFacade(userRepository, roleRepository); + public UserFacade userFacade(UserRepository userRepository, RoleEntityRepository roleEntityRepository, UserEntityRepository userEntityRepository){ + return new UserFacade(userRepository, roleEntityRepository, userEntityRepository); } } diff --git a/src/main/java/com/ecmsp/userservice/user/domain/RoleFacade.java b/src/main/java/com/ecmsp/userservice/user/domain/RoleFacade.java index 3562ae9..4dc7d1f 100644 --- a/src/main/java/com/ecmsp/userservice/user/domain/RoleFacade.java +++ b/src/main/java/com/ecmsp/userservice/user/domain/RoleFacade.java @@ -12,6 +12,12 @@ public RoleFacade(RoleRepository roleRepository) { } public RoleId createRole(RoleToCreate roleToCreate) { + // Check if role with this name already exists + Optional existingRole = roleRepository.findByName(roleToCreate.name()); + if (existingRole.isPresent()) { + throw new IllegalArgumentException("Role with name '" + roleToCreate.name() + "' already exists"); + } + RoleId roleId = new RoleId(UUID.randomUUID()); Role role = new Role(roleId, roleToCreate.name(), roleToCreate.permissions()); roleRepository.save(role); @@ -47,4 +53,24 @@ public List getAllRoles() { public void deleteRole(RoleId roleId) { roleRepository.delete(roleId); } + + public void deleteRoleByName(String roleName) { + Role role = roleRepository.findByName(roleName) + .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleName)); + roleRepository.delete(role.id()); + } + + public void addPermissionToRoleByName(String roleName, Permission permission) { + Role role = roleRepository.findByName(roleName) + .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleName)); + role.addPermission(permission); + roleRepository.save(role); + } + + public void removePermissionFromRoleByName(String roleName, Permission permission) { + Role role = roleRepository.findByName(roleName) + .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleName)); + role.removePermission(permission); + roleRepository.save(role); + } } diff --git a/src/main/java/com/ecmsp/userservice/user/domain/UserFacade.java b/src/main/java/com/ecmsp/userservice/user/domain/UserFacade.java index bd52c57..2ac8b51 100644 --- a/src/main/java/com/ecmsp/userservice/user/domain/UserFacade.java +++ b/src/main/java/com/ecmsp/userservice/user/domain/UserFacade.java @@ -1,4 +1,8 @@ package com.ecmsp.userservice.user.domain; +import com.ecmsp.userservice.user.adapter.repository.db.RoleEntity; +import com.ecmsp.userservice.user.adapter.repository.db.RoleEntityRepository; +import com.ecmsp.userservice.user.adapter.repository.db.UserEntity; +import com.ecmsp.userservice.user.adapter.repository.db.UserEntityRepository; import java.util.HashSet; import java.util.List; @@ -8,12 +12,14 @@ public class UserFacade { private final UserRepository userRepository; - private final RoleRepository roleRepository; + private final RoleEntityRepository roleEntityRepository; + private final UserEntityRepository userEntityRepository; private final PasswordHasher passwordHasher = new PasswordHasher(); - public UserFacade(UserRepository userRepository, RoleRepository roleRepository) { + public UserFacade(UserRepository userRepository, RoleEntityRepository roleEntityRepository, UserEntityRepository userEntityRepository) { this.userRepository = userRepository; - this.roleRepository = roleRepository; + this.roleEntityRepository = roleEntityRepository; + this.userEntityRepository = userEntityRepository; } public User createUser(UserToCreate userToCreate){ @@ -51,26 +57,22 @@ public List listUsers(String filterLogin) { return userRepository.findByLoginContaining(filterLogin); } - public void assignRoleToUser(UserId userId, RoleId roleId) { - User user = userRepository.findById(userId) + public void assignRoleToUser(UserId userId, String roleName) { + UserEntity user = userEntityRepository.findById(userId.value()) .orElseThrow(() -> new IllegalArgumentException("User not found: " + userId)); - Role role = roleRepository.findById(roleId) - .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleId)); + RoleEntity role = roleEntityRepository.findByRoleName(roleName) + .orElseThrow(() -> new IllegalArgumentException("Role not found: " + roleName)); - Set updatedRoles = new HashSet<>(user.roles()); - updatedRoles.add(role); - User updatedUser = new User(user.id(), user.login(), user.passwordHash(), updatedRoles); - userRepository.save(updatedUser); + user.getRoles().add(role); + userEntityRepository.save(user); } - public void removeRoleFromUser(UserId userId, RoleId roleId) { - User user = userRepository.findById(userId) + public void removeRoleFromUser(UserId userId, String roleName) { + UserEntity user = userEntityRepository.findById(userId.value()) .orElseThrow(() -> new IllegalArgumentException("User not found: " + userId)); - Set updatedRoles = new HashSet<>(user.roles()); - updatedRoles.removeIf(role -> role.id().equals(roleId)); - User updatedUser = new User(user.id(), user.login(), user.passwordHash(), updatedRoles); - userRepository.save(updatedUser); + user.getRoles().removeIf(role -> role.getRoleName().equals(roleName)); + userEntityRepository.save(user); } public Set getUserRoles(UserId userId) { diff --git a/src/main/resources/db/migration/V3__Create_roles_and_permissions.sql b/src/main/resources/db/migration/V3__Create_roles_and_permissions.sql index 54f67a2..69d5913 100644 --- a/src/main/resources/db/migration/V3__Create_roles_and_permissions.sql +++ b/src/main/resources/db/migration/V3__Create_roles_and_permissions.sql @@ -1,23 +1,23 @@ -- Create permissions table -CREATE TABLE permissions ( +CREATE TABLE IF NOT EXISTS permissions ( permission_name VARCHAR(100) PRIMARY KEY ); -- Create roles table -CREATE TABLE roles ( +CREATE TABLE IF NOT EXISTS roles ( role_id UUID PRIMARY KEY, role_name VARCHAR(100) NOT NULL UNIQUE ); -- Create role_permissions join table -CREATE TABLE role_permissions ( +CREATE TABLE IF NOT EXISTS role_permissions ( role_id UUID REFERENCES roles(role_id) ON DELETE CASCADE, permission_name VARCHAR(100) REFERENCES permissions(permission_name) ON DELETE CASCADE, PRIMARY KEY (role_id, permission_name) ); -- Create user_roles join table -CREATE TABLE user_roles ( +CREATE TABLE IF NOT EXISTS user_roles ( user_id UUID REFERENCES users(user_id) ON DELETE CASCADE, role_id UUID REFERENCES roles(role_id) ON DELETE CASCADE, PRIMARY KEY (user_id, role_id)