diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryController.java b/src/main/java/org/gridsuite/directory/server/DirectoryController.java index b8038ffd..019e3837 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryController.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryController.java @@ -202,7 +202,7 @@ public ResponseEntity getCasesCount(@PathVariable("userId") String user @Header(name = "X-Permission-Error", description = "Indicates where permission check failed: PARENT_PERMISSION_DENIED, CHILD_PERMISSION_DENIED, or TARGET_PERMISSION_DENIED") }) }) - public ResponseEntity areElementsAccessible(@RequestParam("ids") List elementUuids, + public ResponseEntity areElementsAccessible(@RequestParam("ids") List elementUuids, @RequestParam(value = "accessType") PermissionType permissionType, @RequestParam(value = "targetDirectoryUuid", required = false) UUID targetDirectoryUuid, @RequestParam(value = "recursiveCheck", required = false, defaultValue = "false") boolean recursiveCheck, @@ -210,12 +210,7 @@ public ResponseEntity areElementsAccessible(@RequestParam("ids") List @@ -19,7 +18,7 @@ public class DirectoryException extends RuntimeException { private final Type type; public DirectoryException(Type type) { - super(Objects.requireNonNull(type.name())); + super(); this.type = type; } @@ -32,10 +31,6 @@ public static DirectoryException createNotificationUnknown(@NonNull String actio return new DirectoryException(Type.UNKNOWN_NOTIFICATION, String.format("The notification type '%s' is unknown", action)); } - public static DirectoryException createElementNotFound(@NonNull String type, @NonNull UUID uuid) { - return new DirectoryException(Type.NOT_FOUND, String.format("%s '%s' not found !", type, uuid)); - } - public static DirectoryException createElementNameAlreadyExists(@NonNull String name) { return new DirectoryException(Type.NAME_ALREADY_EXISTS, String.format("Element with the same name '%s' already exists in the directory !", name)); } @@ -48,7 +43,6 @@ public enum Type { NOT_ALLOWED, NOT_FOUND, NOT_DIRECTORY, - IS_DIRECTORY, UNKNOWN_NOTIFICATION, NAME_ALREADY_EXISTS, MOVE_IN_DESCENDANT_NOT_ALLOWED, diff --git a/src/main/java/org/gridsuite/directory/server/DirectoryService.java b/src/main/java/org/gridsuite/directory/server/DirectoryService.java index ba21acea..e6003aea 100644 --- a/src/main/java/org/gridsuite/directory/server/DirectoryService.java +++ b/src/main/java/org/gridsuite/directory/server/DirectoryService.java @@ -71,6 +71,23 @@ public DirectoryService(DirectoryRepositoryService repositoryService, this.roleService = roleService; } + private DirectoryElementEntity getElementEntityOrThrow(UUID elementUuid) { + return directoryElementRepository.findById(elementUuid) + .orElseThrow(() -> new DirectoryException(NOT_FOUND, "Element %s not found".formatted(elementUuid))); + } + + private void assertExistsAndIsDirectory(UUID elementUuid) { + DirectoryElementEntity elementEntity = getElementEntityOrThrow(elementUuid); + if (!elementEntity.getType().equals(DIRECTORY)) { + throw new DirectoryException(NOT_DIRECTORY); + } + } + + public String getElementName(UUID elementUuid) { + DirectoryElementEntity element = getElementEntityOrThrow(elementUuid); + return element.getName(); + } + //TODO: this consumer is the kept here at the moment, but it will be moved to explore server later on @Transactional public void studyUpdated(UUID studyUuid, String errorMessage, String userId) { @@ -94,9 +111,9 @@ public ElementAttributes createElement(ElementAttributes elementAttributes, UUID private ElementAttributes createElementWithNotif(ElementAttributes elementAttributes, UUID parentDirectoryUuid, String userId, boolean generateNewName) { if (elementAttributes.getElementName().isBlank()) { - throw new DirectoryException(NOT_ALLOWED); + throw new DirectoryException(NOT_ALLOWED, "Empty name is not allowed for an element"); } - assertDirectoryExist(parentDirectoryUuid); + assertExistsAndIsDirectory(parentDirectoryUuid); DirectoryElementEntity elementEntity = insertElement(elementAttributes, parentDirectoryUuid, userId, generateNewName); if (DIRECTORY.equals(elementAttributes.getType())) { insertManageUserPermission(elementEntity.getId(), userId, ""); @@ -111,7 +128,7 @@ private ElementAttributes createElementWithNotif(ElementAttributes elementAttrib } public ElementAttributes duplicateElement(UUID elementId, UUID newElementId, UUID targetDirectoryId, String userId) { - DirectoryElementEntity directoryElementEntity = directoryElementRepository.findById(elementId).orElseThrow(() -> new DirectoryException(NOT_FOUND)); + DirectoryElementEntity directoryElementEntity = getElementEntityOrThrow(elementId); String elementType = directoryElementEntity.getType(); UUID parentDirectoryUuid = targetDirectoryId != null ? targetDirectoryId : directoryElementEntity.getParentId(); ElementAttributes elementAttributes = ElementAttributes.builder() @@ -122,7 +139,7 @@ public ElementAttributes duplicateElement(UUID elementId, UUID newElementId, UUI .elementName(directoryElementEntity.getName()) .build(); - assertDirectoryExist(parentDirectoryUuid); + assertExistsAndIsDirectory(parentDirectoryUuid); DirectoryElementEntity elementEntity = insertElement(elementAttributes, parentDirectoryUuid, userId, true); // Here we know that parentDirectoryUuid can't be null @@ -131,18 +148,6 @@ public ElementAttributes duplicateElement(UUID elementId, UUID newElementId, UUI return toElementAttributes(elementEntity); } - private void assertRootDirectoryNotExist(String rootName) { - if (TRUE.equals(repositoryService.isRootDirectoryExist(rootName))) { - throw new DirectoryException(NOT_ALLOWED); - } - } - - private void assertDirectoryExist(UUID dirUuid) { - if (!getElement(dirUuid).getType().equals(DIRECTORY)) { - throw new DirectoryException(NOT_DIRECTORY); - } - } - private DirectoryElementEntity insertElement(ElementAttributes elementAttributes, UUID parentDirectoryUuid) { return insertElement(elementAttributes, parentDirectoryUuid, null, false); } @@ -192,10 +197,11 @@ public ElementAttributes createRootDirectory(RootDirectoryAttributes rootDirecto private ElementAttributes createRootDirectoryWithNotif(RootDirectoryAttributes rootDirectoryAttributes, String userId) { if (rootDirectoryAttributes.getElementName().isBlank()) { - throw new DirectoryException(NOT_ALLOWED); + throw new DirectoryException(NOT_ALLOWED, "Empty name is not allowed for root directory"); + } + if (repositoryService.isRootDirectoryExist(rootDirectoryAttributes.getElementName())) { + throw new DirectoryException(NOT_ALLOWED, "Root directory %s already exists".formatted(rootDirectoryAttributes.getElementName())); } - - assertRootDirectoryNotExist(rootDirectoryAttributes.getElementName()); ElementAttributes elementAttributes = toElementAttributes(insertElement(toElementAttributes(rootDirectoryAttributes), null)); UUID elementUuid = elementAttributes.getElementUuid(); insertManageUserPermission(elementUuid, userId, ""); @@ -260,9 +266,6 @@ public List getDirectoryElements(UUID directoryUuid, List getSubDirectoriesCountsMap(List types, List elementsUuids, UUID newDirectoryUuid, String userId) { - if (elementsUuids.isEmpty()) { - throw new DirectoryException(NOT_ALLOWED); - } - - validateNewDirectory(newDirectoryUuid); - - elementsUuids.forEach(elementUuid -> moveElementDirectory(getDirectoryElementEntity(elementUuid), newDirectoryUuid, userId)); + assertExistsAndIsDirectory(newDirectoryUuid); + elementsUuids.forEach(elementUuid -> moveElementDirectory(getElementEntityOrThrow(elementUuid), newDirectoryUuid, userId)); } private void moveElementDirectory(DirectoryElementEntity element, UUID newDirectoryUuid, String userId) { @@ -384,15 +382,6 @@ private void updateElementParentDirectory(DirectoryElementEntity element, UUID n repositoryService.saveElement(element); } - private void validateNewDirectory(UUID newDirectoryUuid) { - DirectoryElementEntity newDirectory = repositoryService.getElementEntity(newDirectoryUuid) - .orElseThrow(() -> DirectoryException.createElementNotFound(DIRECTORY, newDirectoryUuid)); - - if (!newDirectory.getType().equals(DIRECTORY)) { - throw new DirectoryException(NOT_DIRECTORY); - } - } - private boolean directoryHasElementOfNameAndType(UUID directoryUUID, String elementName, String elementType) { return getOnlyElementsStream(directoryUUID, List.of(elementType)) .anyMatch( @@ -464,22 +453,13 @@ public void deleteElements(List elementsUuids, UUID parentDirectoryUuid, S public List getPath(UUID elementUuid) { List path = repositoryService.getPath(elementUuid).stream().map(ElementAttributes::toElementAttributes).toList(); if (path.isEmpty()) { - throw DirectoryException.createElementNotFound(ELEMENT, elementUuid); + throw new DirectoryException(NOT_FOUND, "Element %s not found".formatted(elementUuid)); } return path; } - public String getElementName(UUID elementUuid) { - DirectoryElementEntity element = repositoryService.getElementEntity(elementUuid).orElseThrow(() -> new DirectoryException(NOT_FOUND)); - return element.getName(); - } - public ElementAttributes getElement(UUID elementUuid) { - return toElementAttributes(getDirectoryElementEntity(elementUuid)); - } - - private DirectoryElementEntity getDirectoryElementEntity(UUID elementUuid) { - return repositoryService.getElementEntity(elementUuid).orElseThrow(() -> DirectoryException.createElementNotFound(ELEMENT, elementUuid)); + return toElementAttributes(getElementEntityOrThrow(elementUuid)); } public UUID getDirectoryUuid(String directoryName, UUID parentDirectoryUuid) { @@ -507,7 +487,7 @@ public List getElements(List ids, boolean strictMode, L } if (strictMode && elementEntities.size() != ids.stream().distinct().count()) { - throw new DirectoryException(NOT_FOUND); + throw new DirectoryException(NOT_FOUND, "Not all IDs were found in strict mode (expected %d but found %d)".formatted(ids.stream().distinct().count(), elementEntities.size())); } Map subElementsCount = getSubDirectoriesCounts(elementEntities.stream().map(DirectoryElementEntity::getId).toList(), types); @@ -544,9 +524,6 @@ private String nameCandidate(String elementName, int n) { } public String getDuplicateNameCandidate(UUID directoryUuid, String elementName, String elementType, String userId) { - if (!repositoryService.canRead(directoryUuid, userId)) { - throw new DirectoryException(NOT_ALLOWED); - } var idLikes = new HashSet<>(repositoryService.getNameByTypeAndParentIdAndNameStartWith(elementType, directoryUuid, elementName)); if (!idLikes.contains(elementName)) { return elementName; @@ -569,7 +546,7 @@ public UUID getDirectoryUuidFromPath(List directoryPath) { for (String s : directoryPath) { UUID currentDirectoryUuid = getDirectoryUuid(s, parentDirectoryUuid); if (currentDirectoryUuid == null) { - throw new DirectoryException(NOT_FOUND); + throw new DirectoryException(NOT_FOUND, "No directory at path %s".formatted(s)); } else { parentDirectoryUuid = currentDirectoryUuid; } @@ -653,7 +630,6 @@ public PermissionCheckResult checkDirectoriesPermission(String userId, List checkReadPermission(userId, elementUuids); case WRITE -> checkWritePermission(userId, elementUuids, targetDirectoryUuid, recursiveCheck); case MANAGE -> checkManagePermission(userId, elementUuids); - default -> PermissionCheckResult.PARENT_PERMISSION_DENIED; }; } @@ -771,7 +747,6 @@ private void addPermissionForAllUsers(UUID elementUuid, PermissionType permissio case READ -> PermissionEntity.read(elementUuid, ALL_USERS, ""); case WRITE -> PermissionEntity.write(elementUuid, ALL_USERS, ""); case MANAGE -> PermissionEntity.manage(elementUuid, ALL_USERS, ""); - default -> throw new IllegalArgumentException("Unknown permission type: " + permissionType); }; permissionRepository.save(permissionEntity); } @@ -781,14 +756,13 @@ private void addPermissionForGroup(UUID elementUuid, String groupId, PermissionT case READ -> PermissionEntity.read(elementUuid, "", groupId); case WRITE -> PermissionEntity.write(elementUuid, "", groupId); case MANAGE -> PermissionEntity.manage(elementUuid, "", groupId); - default -> throw new IllegalArgumentException("Unknown permission type: " + permissionType); }; permissionRepository.save(permissionEntity); } public void validatePermissionsGetAccess(UUID directoryUuid, String userId) { if (!roleService.isUserExploreAdmin() && !hasReadPermissions(userId, List.of(directoryUuid))) { - throw new DirectoryException(NOT_ALLOWED); + throw new DirectoryException(NOT_ALLOWED, "User %s is not authorized to read in directory %s".formatted(userId, directoryUuid)); } } @@ -802,7 +776,7 @@ public void validatePermissionsGetAccess(UUID directoryUuid, String userId) { * @throws DirectoryException if the user doesn't have access or the directory doesn't exist */ public List getDirectoryPermissions(UUID directoryUuid, String userId) { - assertDirectoryExist(directoryUuid); + assertExistsAndIsDirectory(directoryUuid); validatePermissionsGetAccess(directoryUuid, userId); List permissions = permissionRepository.findAllByElementId(directoryUuid); @@ -900,13 +874,13 @@ private Map extractGroupPermissionLevels(List permissions, String userId) { - assertDirectoryExist(directoryUuid); + assertExistsAndIsDirectory(directoryUuid); validatePermissionUpdateAccess(directoryUuid, userId); // Remove all permissions for this directory except for the owner diff --git a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java index f10d7329..87d82ad6 100644 --- a/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java +++ b/src/main/java/org/gridsuite/directory/server/RestResponseEntityExceptionHandler.java @@ -24,28 +24,30 @@ public class RestResponseEntityExceptionHandler { private static final Logger LOGGER = LoggerFactory.getLogger(RestResponseEntityExceptionHandler.class); @ExceptionHandler(value = {DirectoryException.class}) + protected ResponseEntity handleDirectoryException(RuntimeException exception) { + DirectoryException directoryException = (DirectoryException) exception; + String message = ((DirectoryException) exception).getType().toString(); + if (exception.getMessage() != null) { + message += ": " + exception.getMessage(); + } + if (LOGGER.isInfoEnabled()) { + LOGGER.info(message); + } + return switch (directoryException.getType()) { + case NOT_ALLOWED, + NOT_DIRECTORY, + MOVE_IN_DESCENDANT_NOT_ALLOWED -> ResponseEntity.status(HttpStatus.FORBIDDEN).body(message); + case NOT_FOUND -> ResponseEntity.status(HttpStatus.NOT_FOUND).body(message); + case UNKNOWN_NOTIFICATION -> ResponseEntity.status(HttpStatus.BAD_REQUEST).body(message); + case NAME_ALREADY_EXISTS -> ResponseEntity.status(HttpStatus.CONFLICT).body(message); + }; + } + + @ExceptionHandler(value = {Exception.class}) protected ResponseEntity handleException(RuntimeException exception) { if (LOGGER.isErrorEnabled()) { - LOGGER.error(exception.getMessage(), exception); - } - DirectoryException directoryException = (DirectoryException) exception; - switch (directoryException.getType()) { - case NOT_ALLOWED: - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(NOT_ALLOWED); - case IS_DIRECTORY: - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(IS_DIRECTORY); - case NOT_DIRECTORY: - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(NOT_DIRECTORY); - case NOT_FOUND: - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(NOT_FOUND); - case UNKNOWN_NOTIFICATION: - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(UNKNOWN_NOTIFICATION); - case NAME_ALREADY_EXISTS: - return ResponseEntity.status(HttpStatus.CONFLICT).body(directoryException.getMessage()); - case MOVE_IN_DESCENDANT_NOT_ALLOWED: - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(MOVE_IN_DESCENDANT_NOT_ALLOWED); - default: - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); + LOGGER.error("An unexpected error occurred", exception); } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(exception.getMessage()); } } diff --git a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java index cbfb71dc..fe84fd57 100644 --- a/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java +++ b/src/main/java/org/gridsuite/directory/server/services/DirectoryRepositoryService.java @@ -86,10 +86,6 @@ public void deleteElements(List elementUuids) { directoryElementInfosRepository.deleteAllById(elementUuids); } - public boolean canRead(UUID id, String userId) { - return directoryElementRepository.existsByIdAndOwnerOrId(id, userId, id); - } - public void reindexElements() { reindexElements(directoryElementRepository.findAll()); } diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java index f151d7e3..fe4c226e 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryServiceTest.java @@ -216,7 +216,7 @@ void testMoveInNotExistingDirectory() { UUID randomUuid = UUID.randomUUID(); List list = List.of(elementUuid); // Just for Sonar issue (assertThrows) DirectoryException exception3 = assertThrows(DirectoryException.class, () -> directoryService.moveElementsDirectory(list, randomUuid, "user1")); - assertEquals(DirectoryException.createElementNotFound(DIRECTORY, randomUuid).getMessage(), exception3.getMessage()); + assertEquals(new DirectoryException(DirectoryException.Type.NOT_FOUND, "blabla").getMessage(), exception3.getMessage()); } @Test diff --git a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java index e8f87130..c34e43aa 100644 --- a/src/test/java/org/gridsuite/directory/server/DirectoryTest.java +++ b/src/test/java/org/gridsuite/directory/server/DirectoryTest.java @@ -62,7 +62,6 @@ import static com.vladmihalcea.sql.SQLStatementCountValidator.*; import static org.assertj.core.api.Assertions.assertThat; -import static org.gridsuite.directory.server.DirectoryException.Type.UNKNOWN_NOTIFICATION; import static org.gridsuite.directory.server.NotificationService.HEADER_UPDATE_TYPE; import static org.gridsuite.directory.server.NotificationService.*; import static org.gridsuite.directory.server.dto.ElementAttributes.toElementAttributes; @@ -1020,7 +1019,7 @@ public void testEmitDirectoryChangedNotification() { mockMvc.perform(post(String.format("/v1/elements/%s/notification?type=bad_type", elementAttributes.getElementUuid())) .header("userId", "Doe")) .andExpect(status().isBadRequest()) - .andExpect(content().string(new IsEqual<>(objectMapper.writeValueAsString(UNKNOWN_NOTIFICATION)))); + .andExpect(content().string(new IsEqual<>(objectMapper.writeValueAsString("UNKNOWN_NOTIFICATION: The notification type 'bad_type' is unknown")))); } @SneakyThrows