From e6bf2105be161747a922f98c9c7652a63d581aeb Mon Sep 17 00:00:00 2001 From: qvalentin Date: Fri, 2 Apr 2021 11:30:34 +0200 Subject: [PATCH 01/20] ViewFolderContents updated to new sharing concept --- src/test/resources/ViewFolderContents.feature | 104 ++++++++++-------- 1 file changed, 58 insertions(+), 46 deletions(-) diff --git a/src/test/resources/ViewFolderContents.feature b/src/test/resources/ViewFolderContents.feature index aec46df7..d97ce605 100644 --- a/src/test/resources/ViewFolderContents.feature +++ b/src/test/resources/ViewFolderContents.feature @@ -4,73 +4,85 @@ Feature: View Folder Background: Given database is empty - And user 1234 exists - And user 420 exists + And user with userId 1234 exists and has username "Richard", password "badPassword" + And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" And accessToken with value "900000" exists for user 1234 - And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 420 has the path "/bla" and name "bla" - And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 420 and has the name "wow.txt" + And accessToken with value "222222" exists for user 420 + And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 1234 has the path "/bla" and name "bla" + # should the path contain the user id ? like: "/420/bla" Then the fe requests /Gimleux/bla and you can easily look it up in the database + # then created by user would be useless and it should be replaced with 'last modified by' (basically it is the same) + And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 1234 and has the name "wow.txt" And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 Scenario: Successful interaction - Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 - When user with token "900000" wants to see the content of folder with path "/bla" + When user with token "900000" wants to see the content of folder with path "/Richard/bla" + Then response status code is 200 + And the response contains the file with fileSystemId 72 and name "wow.txt" + + Scenario: Successful interaction shared folder + Given user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "222222" wants to see the content of folder with path "/Richard/bla" Then response status code is 200 And the response contains the file with fileSystemId 72 and name "wow.txt" Scenario: Folder does not exist - Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "900000" wants to see the content of folder with path "/bla/fasel" + When user with token "900000" wants to see the content of folder with path "/Richard/bla/fasel" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." Scenario: insufficient authorization - Given user 9877 exists - And accessToken with value "2345678" exists for user 9877 - When user with token "2345678" wants to see the content of folder with path "/bla/fasel" + When user with token "222222" wants to see the content of folder with path "/Richard/bla" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." - Scenario: shared folder (user) - Given user 4321 exists - And accessToken with value "123321123" exists for user 4321 - And user with the userId 4321 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "123321123" wants to see the content of folder with path "/bla" - Then response status code is 200 - And the response contains an empty list for files and folders - - Scenario: shared folder and file (user) - Given user 4321 exists - And accessToken with value "123321123" exists for user 4321 - And user with the userId 4321 is allowed to VIEW the fileSystemItem with the fileSystemId 72 - And user with the userId 4321 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "123321123" wants to see the content of folder with path "/bla" - Then response status code is 200 - And the response contains the file with fileSystemId 72 and name "wow.txt" - Scenario: shared folder (group) - Given user 4321 exists - And user with userId 4321 is in group with groupId 1 - And accessToken with value "123321123" exists for user 4321 - And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "123321123" wants to see the content of folder with path "/bla" - Then response status code is 200 - And the response contains an empty list for files and folders - - Scenario: shared folder and file (group) - Given user 4321 exists - And user with userId 4321 is in group with groupId 1 - And accessToken with value "123321123" exists for user 4321 - And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 72 + And user with userId 420 is in group with groupId 1 And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "123321123" wants to see the content of folder with path "/bla" + When user with token "222222" wants to see the content of folder with path "/bla" Then response status code is 200 And the response contains the file with fileSystemId 72 and name "wow.txt" Scenario: empty directory - Given fileSystemItem with the fileSystemId 44 exists, was created by user with userId 420 has the path "/empty" and name "empty" + Given fileSystemItem with the fileSystemId 44 exists, was created by user with userId 1234 has the path "/empty" and name "empty" And fileSystemItem with the fileSystemId 44 is a folder - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 44 - When user with token "900000" wants to see the content of folder with path "/empty" + When user with token "900000" wants to see the content of folder with path "/Richard/empty" Then response status code is 200 And the response contains an empty list for files and folders + + Scenario: root folder + When user with token "900000" wants to see the content of folder with path "/" + Then response status code is 200 + And the response contains the folder with name "Richard" + + Scenario: root folder shared + Given user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "222222" wants to see the content of folder with path "/" + Then response status code is 200 + And the response contains the folder with name "Richard" + And the response contains the folder with name "Nasir" + + + + Scenario: nested shared folder + Given fileSystemItem with the fileSystemId 4 exists, was created by user with userId 1234 has the path "/pläne" and name "pläne" + And fileSystemItem with the fileSystemId 5 exists, was created by user with userId 1234 has the path "/pläne/städte" and name "städte" + And fileSystemItem with the fileSystemId 12 exists, was created by user with userId 1234 has the path "/pläne/städte/jerusalem" and name "jerusalem" + And fileSystemItem with the fileSystemId 13 exists, was created by user with userId 1234 and has the name "we_will_take.mp3" + And fileSystemItem with the fileSystemId 12 is a folder and contains the fileSystemId 13 + And fileSystemItem with the fileSystemId 4 is a folder and contains the fileSystemId 5 + And fileSystemItem with the fileSystemId 5 is a folder and contains the fileSystemId 12 + And user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 12 + # Could he also only see the file? + When user with token "222222" wants to see the content of folder with path "/Richard" + Then response status code is 200 + And the response does not contains the file with fileSystemId 42 and name "bla" + And the response contains the folder with fileSystemId 4 and name "pläne" + When user with token "222222" wants to see the content of folder with path "/Richard/pläne" + Then response status code is 200 + And the response contains the folder with fileSystemId 5 and name "städte" + When user with token "222222" wants to see the content of folder with path "/Richard/pläne/städte" + Then response status code is 200 + And the response contains the folder with fileSystemId 12 and name "jerusalem" + When user with token "222222" wants to see the content of folder with path "/Richard/pläne/städte/jerusalem" + Then response status code is 200 + And the response contains the file with fileSystemId 13 and name "we_will_take.mp3" From b5fa224f10997fc70f54b6aaa85acd56a5bd10b6 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Fri, 2 Apr 2021 18:35:37 +0200 Subject: [PATCH 02/20] Implemented Refactorings from FF-296 --- .run/RestApplication-debug.run.xml | 13 + .../rest/configuration/CorsConfig.java | 4 +- .../rest/configuration/PrepareDataBase.java | 9 +- .../AuthenticationBusinessService.java | 10 +- .../authentication/AuthenticationService.java | 2 +- .../InputSanitizerService.java | 34 +- .../business/FileSystemBusinessService.java | 232 +---------- .../business/FileSystemHelperService.java | 218 ++++++++++ .../filesystem/data/InteractionType.java | 7 + .../filesystem/data/dto/FileSystemItem.java | 1 + .../data/dto/FileSystemItemUpdate.java | 4 + .../data/persistence/FileSystemEntity.java | 1 + .../rest/FileSystemRestController.java | 14 +- .../rest/FileSystemRestService.java | 10 +- .../rest/FileSystemRestServiceInterface.java | 7 +- .../filesystem/type/FileSystemType.java | 8 +- .../type/FileSystemTypeRepository.java | 35 +- .../business/SystemHealthBusinessService.java | 10 +- .../user/business/UserBusinessService.java | 2 +- .../domain/user/rest/UserRestService.java | 16 +- .../resources/application-debug.properties | 1 + .../cucumber/ViewFolderContentsSteps.java | 26 +- ...AuthenticationBusinessServiceUnitTest.java | 6 +- .../common/InputSanitizerServiceUnitTest.java | 67 +++- .../FileSystemBusinessServiceUnitTest.java | 374 ++++++------------ .../FileSystemHelperServiceUnitTest.java | 262 ++++++++++++ .../FileSystemRestControllerUnitTest.java | 15 +- .../SystemHealthBusinessServiceUnitTest.java | 4 +- 28 files changed, 840 insertions(+), 552 deletions(-) create mode 100644 .run/RestApplication-debug.run.xml rename src/main/java/de/filefighter/rest/domain/common/{exceptions => }/InputSanitizerService.java (54%) create mode 100644 src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java create mode 100644 src/main/java/de/filefighter/rest/domain/filesystem/data/InteractionType.java create mode 100644 src/main/resources/application-debug.properties create mode 100644 src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java diff --git a/.run/RestApplication-debug.run.xml b/.run/RestApplication-debug.run.xml new file mode 100644 index 00000000..3e74c1c2 --- /dev/null +++ b/.run/RestApplication-debug.run.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/src/main/java/de/filefighter/rest/configuration/CorsConfig.java b/src/main/java/de/filefighter/rest/configuration/CorsConfig.java index 1bbf1ecd..1aee717a 100644 --- a/src/main/java/de/filefighter/rest/configuration/CorsConfig.java +++ b/src/main/java/de/filefighter/rest/configuration/CorsConfig.java @@ -25,7 +25,7 @@ public CorsConfig() { } @Bean - @Profile({"dev","stage"}) + @Profile({"dev", "stage", "debug"}) public CorsFilter corsFilterDev() { final CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); ArrayList allowedOrigins = new ArrayList<>(); @@ -39,7 +39,7 @@ public CorsFilter corsFilterDev() { } @Bean - @Profile({"prod","test"}) + @Profile({"prod"}) public CorsFilter corsFilterProd() { final CorsConfiguration config = new CorsConfiguration(); config.setAllowedMethods(allowedMethods); diff --git a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java index a5879e23..0866847e 100644 --- a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java +++ b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java @@ -45,7 +45,7 @@ public class PrepareDataBase { String date; @Bean - @Profile({"dev", "prod, stage"}) + @Profile({"dev", "prod, stage", "debug"}) @Autowired CommandLineRunner veryImportantFileFighterStartScript(Environment environment) { return args -> { @@ -136,7 +136,7 @@ CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepo } @Bean - @Profile("dev") + @Profile({"dev", "debug"}) CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepository accessTokenRepository, FileSystemRepository fileSystemRepository) { return args -> { log.info("Starting with clean user collection."); @@ -243,6 +243,7 @@ CommandLineRunner initDataBaseStage(UserRepository userRepository, FileSystemRep }; } + // TODO: fix owner ids. private void addDefaultAdminAndRuntimeUser(UserRepository userRepository) { log.info("Database seems to be empty. Creating new default entities..."); log.info("Inserting system runtime user: {}", userRepository.save(UserEntity @@ -278,6 +279,8 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .size(4866) .typeId(FOLDER.getId()) .visibleForGroupIds(new long[]{FAMILY.getGroupId(), ADMIN.getGroupId()}) + .visibleForUserIds(new long[]{0}) + .editableForUserIds(new long[]{0}) .build()), fileSystemRepository.save(FileSystemEntity.builder() .createdByUserId(RUNTIME_USER_ID) @@ -289,6 +292,8 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .size(0) .typeId(FOLDER.getId()) .visibleForGroupIds(new long[]{UNDEFINED.getGroupId(), FAMILY.getGroupId(), ADMIN.getGroupId()}) + .visibleForUserIds(new long[]{1}) + .editableForUserIds(new long[]{1}) .build()), fileSystemRepository.save(FileSystemEntity.builder() .createdByUserId(1) diff --git a/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessService.java b/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessService.java index 43cc13a7..664fd5e1 100644 --- a/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessService.java @@ -1,6 +1,6 @@ package de.filefighter.rest.domain.authentication; -import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; +import de.filefighter.rest.domain.common.InputSanitizerService; import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.user.business.UserDTOService; @@ -21,10 +21,12 @@ public class AuthenticationBusinessService { private final UserRepository userRepository; private final UserDTOService userDtoService; + private final InputSanitizerService inputSanitizerService; - public AuthenticationBusinessService(UserRepository userRepository, UserDTOService userDtoService) { + public AuthenticationBusinessService(UserRepository userRepository, UserDTOService userDtoService, InputSanitizerService inputSanitizerService) { this.userRepository = userRepository; this.userDtoService = userDtoService; + this.inputSanitizerService = inputSanitizerService; } public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndPassword) { @@ -42,8 +44,8 @@ public User authenticateUserWithUsernameAndPassword(String base64encodedUserAndP if (split.length != 2) throw new RequestDidntMeetFormalRequirementsException("Credentials didnt meet formal requirements."); - String lowerCaseUsername = InputSanitizerService.sanitizeString(split[0].toLowerCase()); - String password = InputSanitizerService.sanitizeString(split[1]); + String lowerCaseUsername = inputSanitizerService.sanitizeString(split[0].toLowerCase()); + String password = inputSanitizerService.sanitizeString(split[1]); UserEntity userEntity = userRepository.findByLowercaseUsernameAndPassword(lowerCaseUsername, password); if (null == userEntity) diff --git a/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationService.java b/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationService.java index 8998f511..9a787298 100644 --- a/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationService.java +++ b/src/main/java/de/filefighter/rest/domain/authentication/AuthenticationService.java @@ -1,6 +1,6 @@ package de.filefighter.rest.domain.authentication; -import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; +import de.filefighter.rest.domain.common.InputSanitizerService; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.user.data.dto.User; diff --git a/src/main/java/de/filefighter/rest/domain/common/exceptions/InputSanitizerService.java b/src/main/java/de/filefighter/rest/domain/common/InputSanitizerService.java similarity index 54% rename from src/main/java/de/filefighter/rest/domain/common/exceptions/InputSanitizerService.java rename to src/main/java/de/filefighter/rest/domain/common/InputSanitizerService.java index 9218dcf3..c9771a0c 100644 --- a/src/main/java/de/filefighter/rest/domain/common/exceptions/InputSanitizerService.java +++ b/src/main/java/de/filefighter/rest/domain/common/InputSanitizerService.java @@ -1,7 +1,11 @@ -package de.filefighter.rest.domain.common.exceptions; +package de.filefighter.rest.domain.common; +import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException; import org.springframework.stereotype.Service; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + @Service public class InputSanitizerService { @@ -10,18 +14,25 @@ public static boolean stringIsValid(String s) { } /** - * * Sanitizes a String, so it can be used. + * * @param string String that needs to be sanitized. * @return string without whitespaces and without illegal characters. * @throws RequestDidntMeetFormalRequirementsException when string was empty. */ - public static String sanitizeString(String string) { - if(!InputSanitizerService.stringIsValid(string)) + public String sanitizeString(String string) { + if (!InputSanitizerService.stringIsValid(string)) throw new RequestDidntMeetFormalRequirementsException("String was empty."); return string.replaceAll("\\s", ""); } + public String sanitizePath(String path) { + if (!pathIsValid(path)) + throw new RequestDidntMeetFormalRequirementsException("Path was not valid."); + + return sanitizeString(path); + } + public String sanitizeRequestHeader(String header, String testString) { if (!(stringIsValid(testString) && stringIsValid(header))) throw new RequestDidntMeetFormalRequirementsException("Header does not contain a valid String."); @@ -32,7 +43,18 @@ public String sanitizeRequestHeader(String header, String testString) { return split[1]; } - public String sanitizeTokenValue(String tokenValue){ - return InputSanitizerService.sanitizeString(tokenValue); + public boolean pathIsValid(String path) { + String validString = sanitizeString(path); + + Pattern pattern = Pattern.compile("[~#@*+:!?&%<>|\"^\\\\]"); + Matcher matcher = pattern.matcher(validString); + + boolean stringContainsDoubleSlash = validString.contains("//"); + + return !(matcher.find() || stringContainsDoubleSlash); + } + + public String sanitizeTokenValue(String tokenValue) { + return this.sanitizeString(tokenValue); } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 94237a83..4bb4983b 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -1,8 +1,8 @@ package de.filefighter.rest.domain.filesystem.business; -import de.filefighter.rest.configuration.RestConfiguration; +import de.filefighter.rest.domain.common.InputSanitizerService; import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; -import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; +import de.filefighter.rest.domain.filesystem.data.InteractionType; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemEntity; import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemRepository; @@ -11,11 +11,7 @@ import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemNotFoundException; import de.filefighter.rest.domain.filesystem.type.FileSystemType; import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; -import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; -import de.filefighter.rest.domain.user.data.persistence.UserEntity; -import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; -import de.filefighter.rest.domain.user.group.Group; import lombok.extern.log4j.Log4j2; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; @@ -23,8 +19,8 @@ import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; -import java.time.Instant; -import java.util.*; +import java.util.ArrayList; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.LongStream; @@ -33,15 +29,15 @@ public class FileSystemBusinessService { private final FileSystemRepository fileSystemRepository; - private final UserBusinessService userBusinessService; + private final FileSystemHelperService fileSystemHelperService; private final FileSystemTypeRepository fileSystemTypeRepository; private final MongoTemplate mongoTemplate; private static final String DELETION_FAILED_MSG = "Failed to delete FileSystemEntity with id "; - public FileSystemBusinessService(FileSystemRepository fileSystemRepository, UserBusinessService userBusinessService, FileSystemTypeRepository fileSystemTypeRepository, MongoTemplate mongoTemplate) { + public FileSystemBusinessService(FileSystemRepository fileSystemRepository, FileSystemHelperService fileSystemHelperService, FileSystemTypeRepository fileSystemTypeRepository, MongoTemplate mongoTemplate) { this.fileSystemRepository = fileSystemRepository; - this.userBusinessService = userBusinessService; + this.fileSystemHelperService = fileSystemHelperService; this.fileSystemTypeRepository = fileSystemTypeRepository; this.mongoTemplate = mongoTemplate; } @@ -58,7 +54,7 @@ public List getFolderContentsByPath(String path, User authentica if (!path.equals("/") && !"".equals(pathWithoutSlashes[0])) throw new FileSystemContentsNotAccessibleException("Path was in wrong format. Use a leading backslash."); - String pathToFind = removeTrailingBackSlashes(path).toLowerCase(); + String pathToFind = fileSystemHelperService.removeTrailingBackSlashes(path).toLowerCase(); // find the folder with matching path. ArrayList listOfFileSystemEntities = fileSystemRepository.findByPath(pathToFind); @@ -66,7 +62,7 @@ public List getFolderContentsByPath(String path, User authentica throw new FileSystemContentsNotAccessibleException(); // remove all not accessible items. - listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || !userIsAllowedToSeeFileSystemEntity(entity, authenticatedUser)); + listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || !fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(entity, authenticatedUser, InteractionType.READ)); if (listOfFileSystemEntities.isEmpty()) throw new FileSystemContentsNotAccessibleException(); @@ -77,9 +73,9 @@ public List getFolderContentsByPath(String path, User authentica // Well this is just O(n * m) for (FileSystemEntity folder : listOfFileSystemEntities) { - ArrayList folderContents = (ArrayList) getFolderContentsOfEntityAndPermissions(folder, authenticatedUser, true, false); + ArrayList folderContents = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(folder, authenticatedUser, true, false); for (FileSystemEntity fileSystemEntityInFolder : folderContents) { - fileSystemItems.add(this.createDTO(fileSystemEntityInFolder, authenticatedUser, pathWithTrailingSlash)); + fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, pathWithTrailingSlash)); } } return fileSystemItems; @@ -90,10 +86,10 @@ public FileSystemItem getFileSystemItemInfo(long fsItemId, User authenticatedUse if (null == fileSystemEntity) throw new FileSystemItemNotFoundException(fsItemId); - if (!userIsAllowedToSeeFileSystemEntity(fileSystemEntity, authenticatedUser)) + if (!fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, authenticatedUser, InteractionType.READ)) throw new FileSystemItemNotFoundException(fsItemId); - return createDTO(fileSystemEntity, authenticatedUser, null); + return fileSystemHelperService.createDTO(fileSystemEntity, authenticatedUser, null); } public boolean deleteFileSystemItemById(long fsItemId, User authenticatedUser) { @@ -101,7 +97,7 @@ public boolean deleteFileSystemItemById(long fsItemId, User authenticatedUser) { if (null == fileSystemEntity) throw new FileSystemItemCouldNotBeDeletedException(fsItemId); - if (!(userIsAllowedToSeeFileSystemEntity(fileSystemEntity, authenticatedUser) && userIsAllowedToEditFileSystemEntity(fileSystemEntity, authenticatedUser))) + if (!(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, authenticatedUser, InteractionType.READ) && fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, authenticatedUser, InteractionType.DELETE))) throw new FileSystemItemCouldNotBeDeletedException(fsItemId); return recursivelyDeleteFileSystemEntity(fileSystemEntity, authenticatedUser); @@ -121,7 +117,7 @@ public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSyst // 1. Base of recursion // Delete File and update parentFolder. Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); - if (countDeleted != 1) + if (countDeleted != 1) // TODO: check this number again. throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); // update. @@ -131,9 +127,9 @@ public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSyst everythingWasDeleted = true; } else if (!parentFileSystemEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(parentFileSystemEntity.getTypeId()) == FileSystemType.FOLDER) { - ArrayList foundEntities = (ArrayList) getFolderContentsOfEntityAndPermissions(parentFileSystemEntity, authenticatedUser, false, false); + List foundList = fileSystemHelperService.getFolderContentsOfEntityAndPermissions(parentFileSystemEntity, authenticatedUser, false, false); - if (null == foundEntities || foundEntities.isEmpty()) { + if (null == foundList || foundList.isEmpty()) { // 2. Base of recursion Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); if (countDeleted != 1) @@ -141,13 +137,14 @@ public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSyst everythingWasDeleted = true; } else { + ArrayList foundEntities = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(parentFileSystemEntity, authenticatedUser, false, false); ArrayList invisibleEntities = new ArrayList<>(); List updatedItemIds = LongStream.of(parentFileSystemEntity.getItemIds()).boxed().collect(Collectors.toList()); int deletedEntities = 0; for (FileSystemEntity childrenEntity : foundEntities) { - if (userIsAllowedToSeeFileSystemEntity(childrenEntity, authenticatedUser)) { - if (userIsAllowedToEditFileSystemEntity(childrenEntity, authenticatedUser)) { + if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(childrenEntity, authenticatedUser, InteractionType.READ)) { + if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(childrenEntity, authenticatedUser, InteractionType.DELETE)) { // Folder. if (!childrenEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(childrenEntity.getTypeId()) == FileSystemType.FOLDER) { @@ -194,7 +191,7 @@ public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSyst // we can make sure, that the views of the other users stay the same, while the current user cannot see the folder anymore. // EdgeCase: that the user who requests the deletion is owner of the folder but cannot see cannot happen anymore, // because he the owner has all rights on all files except ones created by runtime users. - parentFileSystemEntity = sumUpAllPermissionsOfFileSystemEntities(parentFileSystemEntity, invisibleEntities); + parentFileSystemEntity = fileSystemHelperService.sumUpAllPermissionsOfFileSystemEntities(parentFileSystemEntity, invisibleEntities); newUpdate.set("visibleForUserIds", parentFileSystemEntity.getVisibleForUserIds()) .set("visibleForGroupIds", parentFileSystemEntity.getVisibleForGroupIds()) @@ -216,191 +213,4 @@ public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSyst } return everythingWasDeleted; } - - // ---------------- HELPER ------------------- - - public FileSystemEntity sumUpAllPermissionsOfFileSystemEntities(FileSystemEntity parentFileSystemEntity, List fileSystemEntities) { - HashSet visibleForUserIds = new HashSet<>(); - HashSet visibleForGroupIds = new HashSet<>(); - HashSet editableForUserIds = new HashSet<>(); - HashSet editableGroupIds = new HashSet<>(); - - for (FileSystemEntity entity : fileSystemEntities) { - addPermissionsToSets(visibleForUserIds, visibleForGroupIds, editableForUserIds, editableGroupIds, entity); - } - - parentFileSystemEntity.setVisibleForUserIds(Arrays.stream(visibleForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); - parentFileSystemEntity.setVisibleForGroupIds(Arrays.stream(visibleForGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); - parentFileSystemEntity.setEditableForUserIds(Arrays.stream(editableForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); - parentFileSystemEntity.setEditableFoGroupIds(Arrays.stream(editableGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); - return parentFileSystemEntity; - } - - public void addPermissionsToSets(Set visibleForUserIds, Set visibleForGroupIds, Set editableForUserIds, Set editableGroupIds, FileSystemEntity fileSystemEntity) { - for (long i : fileSystemEntity.getVisibleForUserIds()) { - visibleForUserIds.add(i); - } - for (long i : fileSystemEntity.getVisibleForGroupIds()) { - visibleForGroupIds.add(i); - } - for (long i : fileSystemEntity.getEditableForUserIds()) { - editableForUserIds.add(i); - } - for (long i : fileSystemEntity.getEditableFoGroupIds()) { - editableGroupIds.add(i); - } - } - - public List getFolderContentsOfEntityAndPermissions(FileSystemEntity fileSystemEntity, User authenticatedUser, boolean needsToBeVisible, boolean needsToBeEditable) { - long[] folderContentItemIds = fileSystemEntity.getItemIds(); - List fileSystemEntities = new ArrayList<>(folderContentItemIds.length); - - // check if the contents are visible / editable. - for (long fileSystemId : folderContentItemIds) { - FileSystemEntity fileSystemEntityInFolder = fileSystemRepository.findByFileSystemId(fileSystemId); - - if (null == fileSystemEntityInFolder) - throw new FileFighterDataException("FolderContents expected fileSystemItem with id " + fileSystemId + " but was empty."); - - if (needsToBeVisible && !needsToBeEditable && userIsAllowedToSeeFileSystemEntity(fileSystemEntityInFolder, authenticatedUser)) { - fileSystemEntities.add(fileSystemEntityInFolder); - } - if (needsToBeEditable && !needsToBeVisible && userIsAllowedToEditFileSystemEntity(fileSystemEntityInFolder, authenticatedUser)) { - fileSystemEntities.add(fileSystemEntityInFolder); - } - if (needsToBeVisible && needsToBeEditable && userIsAllowedToSeeFileSystemEntity(fileSystemEntityInFolder, authenticatedUser) && userIsAllowedToEditFileSystemEntity(fileSystemEntityInFolder, authenticatedUser)) { - fileSystemEntities.add(fileSystemEntityInFolder); - } - if (!needsToBeVisible && !needsToBeEditable) { - fileSystemEntities.add(fileSystemEntityInFolder); - } - } - return fileSystemEntities; - } - - public boolean userIsAllowedToSeeFileSystemEntity(FileSystemEntity fileSystemEntity, User authenticatedUser) { - // user created the item - if (fileSystemEntity.getCreatedByUserId() == authenticatedUser.getUserId()) - return true; - - // user created containing folder. - if (null != fileSystemEntity.getOwnerIds() && Arrays.stream(fileSystemEntity.getOwnerIds()).asDoubleStream().anyMatch(id -> id == authenticatedUser.getUserId())) - return true; - - // user got the item shared. - for (long userId : fileSystemEntity.getVisibleForUserIds()) { - if (userId == authenticatedUser.getUserId()) - return true; - } - - // user is in group that got the item shared. - long[] fileIsSharedToGroups = fileSystemEntity.getVisibleForGroupIds(); - for (Group group : authenticatedUser.getGroups()) { - for (long groupId : fileIsSharedToGroups) { - if (groupId == group.getGroupId()) - return true; - - } - } - return false; - } - - public boolean userIsAllowedToEditFileSystemEntity(FileSystemEntity fileSystemEntity, User authenticatedUser) { - // file was created by runtime user. - if (fileSystemEntity.getCreatedByUserId() == RestConfiguration.RUNTIME_USER_ID) - return false; - - // user created the item - if (fileSystemEntity.getCreatedByUserId() == authenticatedUser.getUserId()) - return true; - - // user created containing folder. - if (null != fileSystemEntity.getOwnerIds() && Arrays.stream(fileSystemEntity.getOwnerIds()).asDoubleStream().anyMatch(id -> id == authenticatedUser.getUserId())) - return true; - - // user got the item shared. - for (long userId : fileSystemEntity.getEditableForUserIds()) { - if (userId == authenticatedUser.getUserId()) - return true; - } - - // user is in group that got the item shared. - long[] fileIsSharedToGroups = fileSystemEntity.getEditableFoGroupIds(); - for (Group group : authenticatedUser.getGroups()) { - for (long groupId : fileIsSharedToGroups) { - if (groupId == group.getGroupId()) - return true; - - } - } - return false; - } - - public String removeTrailingBackSlashes(String pathToFind) { - char[] chars = pathToFind.toCharArray(); - // for the case of "/" - if (chars.length != 1 && chars[chars.length - 1] == '/') { - chars = Arrays.copyOf(chars, chars.length - 1); - return new String(chars); - } - return pathToFind; - } - - public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenticatedUser, String basePath) { - // for better responses and internal problem handling. - User ownerOfFileSystemItem; - try { - ownerOfFileSystemItem = userBusinessService.getUserById(fileSystemEntity.getCreatedByUserId()); - } catch (UserNotFoundException exception) { - throw new FileFighterDataException("Owner of a file could not be found."); - } - - boolean isShared = ownerOfFileSystemItem.getUserId() != authenticatedUser.getUserId(); - FileSystemType type = fileSystemTypeRepository.findFileSystemTypeById(fileSystemEntity.getTypeId()); - boolean isAFolder = type == FileSystemType.FOLDER && !fileSystemEntity.isFile(); - - return FileSystemItem.builder() - .createdByUser(ownerOfFileSystemItem) - .fileSystemId(fileSystemEntity.getFileSystemId()) - .lastUpdated(fileSystemEntity.getLastUpdated()) - .name(fileSystemEntity.getName()) - .size(fileSystemEntity.getSize()) - .type(isAFolder ? FileSystemType.FOLDER : type) - .path(null == basePath ? null : basePath + fileSystemEntity.getName()) - .isShared(isShared) - .build(); - } - - public void createBasicFilesForNewUser(UserEntity registeredUserEntity) { - fileSystemRepository.save(FileSystemEntity - .builder() - .createdByUserId(0) - .typeId(FileSystemType.FOLDER.getId()) - .isFile(false) - .name("HOME_" + registeredUserEntity.getUsername()) - .path("/") - .lastUpdated(Instant.now().getEpochSecond()) - .fileSystemId(generateNextFileSystemId()) - .build()); - } - - public double getTotalFileSize() { - ArrayList entities = fileSystemRepository.findByPath("/"); - if (null == entities) - throw new FileFighterDataException("Couldn't find any Home directories!"); - - double size = 0; - for (FileSystemEntity entity : entities) { - size += entity.getSize(); - } - return size; - } - - public long getFileSystemEntityCount() { - return fileSystemRepository.count(); - } - - public long generateNextFileSystemId() { - return getFileSystemEntityCount() + 1; - } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java new file mode 100644 index 00000000..a72aa77e --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -0,0 +1,218 @@ +package de.filefighter.rest.domain.filesystem.business; + +import de.filefighter.rest.configuration.RestConfiguration; +import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; +import de.filefighter.rest.domain.filesystem.data.InteractionType; +import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; +import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemEntity; +import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemRepository; +import de.filefighter.rest.domain.filesystem.type.FileSystemType; +import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; +import de.filefighter.rest.domain.user.business.UserBusinessService; +import de.filefighter.rest.domain.user.data.dto.User; +import de.filefighter.rest.domain.user.data.persistence.UserEntity; +import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; +import de.filefighter.rest.domain.user.group.Group; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.util.*; + +@Service +public class FileSystemHelperService { + + private final FileSystemRepository fileSystemRepository; + private final FileSystemTypeRepository fileSystemTypeRepository; + private final UserBusinessService userBusinessService; + + public FileSystemHelperService(FileSystemRepository fileSystemRepository, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService) { + this.fileSystemRepository = fileSystemRepository; + this.fileSystemTypeRepository = fileSystemTypeRepository; + this.userBusinessService = userBusinessService; + } + + public FileSystemEntity sumUpAllPermissionsOfFileSystemEntities(FileSystemEntity parentFileSystemEntity, List fileSystemEntities) { + HashSet visibleForUserIds = new HashSet<>(); + HashSet visibleForGroupIds = new HashSet<>(); + HashSet editableForUserIds = new HashSet<>(); + HashSet editableGroupIds = new HashSet<>(); + + for (FileSystemEntity entity : fileSystemEntities) { + addPermissionsToSets(visibleForUserIds, visibleForGroupIds, editableForUserIds, editableGroupIds, entity); + } + + parentFileSystemEntity.setVisibleForUserIds(Arrays.stream(visibleForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); + parentFileSystemEntity.setVisibleForGroupIds(Arrays.stream(visibleForGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); + parentFileSystemEntity.setEditableForUserIds(Arrays.stream(editableForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); + parentFileSystemEntity.setEditableFoGroupIds(Arrays.stream(editableGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray()); + return parentFileSystemEntity; + } + + public void addPermissionsToSets(Set visibleForUserIds, Set visibleForGroupIds, Set editableForUserIds, Set editableGroupIds, FileSystemEntity fileSystemEntity) { + for (long i : fileSystemEntity.getVisibleForUserIds()) { + visibleForUserIds.add(i); + } + for (long i : fileSystemEntity.getVisibleForGroupIds()) { + visibleForGroupIds.add(i); + } + for (long i : fileSystemEntity.getEditableForUserIds()) { + editableForUserIds.add(i); + } + for (long i : fileSystemEntity.getEditableFoGroupIds()) { + editableGroupIds.add(i); + } + } + + // TODO: refactor this to a list of interaction types. + public List getFolderContentsOfEntityAndPermissions(FileSystemEntity fileSystemEntity, User authenticatedUser, boolean needsToBeVisible, boolean needsToBeEditable) { + long[] folderContentItemIds = fileSystemEntity.getItemIds(); + List fileSystemEntities = new ArrayList<>(folderContentItemIds.length); + + // check if the contents are visible / editable. + for (long fileSystemId : folderContentItemIds) { + FileSystemEntity fileSystemEntityInFolder = fileSystemRepository.findByFileSystemId(fileSystemId); + + if (null == fileSystemEntityInFolder) + throw new FileFighterDataException("FolderContents expected fileSystemItem with id " + fileSystemId + " but was empty."); + + if (needsToBeVisible && !needsToBeEditable && userIsAllowedToInteractWithFileSystemEntity(fileSystemEntityInFolder, authenticatedUser, InteractionType.READ)) { + fileSystemEntities.add(fileSystemEntityInFolder); + } + if (needsToBeEditable && !needsToBeVisible && userIsAllowedToInteractWithFileSystemEntity(fileSystemEntityInFolder, authenticatedUser, InteractionType.CHANGE)) { + fileSystemEntities.add(fileSystemEntityInFolder); + } + if (needsToBeVisible && needsToBeEditable && userIsAllowedToInteractWithFileSystemEntity(fileSystemEntityInFolder, authenticatedUser, InteractionType.READ) && userIsAllowedToInteractWithFileSystemEntity(fileSystemEntityInFolder, authenticatedUser, InteractionType.CHANGE)) { + fileSystemEntities.add(fileSystemEntityInFolder); + } + if (!needsToBeVisible && !needsToBeEditable) { + fileSystemEntities.add(fileSystemEntityInFolder); + } + } + return fileSystemEntities; + } + + @SuppressWarnings("java:S3776") + public boolean userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity fileSystemEntity, User authenticatedUser, InteractionType interaction) { + // file was created by runtime user. + if ((interaction == InteractionType.DELETE) + && fileSystemEntity.getCreatedByUserId() == RestConfiguration.RUNTIME_USER_ID) + return false; + + // user created the item + if (fileSystemEntity.getCreatedByUserId() == authenticatedUser.getUserId()) + return true; + + // user created containing folder. + if (null != fileSystemEntity.getOwnerIds() && Arrays.stream(fileSystemEntity.getOwnerIds()).asDoubleStream().anyMatch(id -> id == authenticatedUser.getUserId())) + return true; + + // user got the item shared. + if (interaction == InteractionType.READ) { + for (long userId : fileSystemEntity.getVisibleForUserIds()) { + if (userId == authenticatedUser.getUserId()) + return true; + } + + // user is in group that got the item shared. + long[] fileIsSharedToGroups = fileSystemEntity.getVisibleForGroupIds(); + for (Group group : authenticatedUser.getGroups()) { + for (long groupId : fileIsSharedToGroups) { + if (groupId == group.getGroupId()) + return true; + + } + } + } + if (interaction == InteractionType.CHANGE || interaction == InteractionType.DELETE) { + for (long userId : fileSystemEntity.getEditableForUserIds()) { + if (userId == authenticatedUser.getUserId()) + return true; + } + + // user is in group that got the item shared. + long[] fileIsSharedToGroups = fileSystemEntity.getEditableFoGroupIds(); + for (Group group : authenticatedUser.getGroups()) { + for (long groupId : fileIsSharedToGroups) { + if (groupId == group.getGroupId()) + return true; + + } + } + } + return false; + } + + public String removeTrailingBackSlashes(String pathToFind) { + char[] chars = pathToFind.toCharArray(); + // for the case of "/" + if (chars.length != 1 && chars[chars.length - 1] == '/') { + chars = Arrays.copyOf(chars, chars.length - 1); + return new String(chars); + } + return pathToFind; + } + + public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenticatedUser, String basePath) { + // for better responses and internal problem handling. + User ownerOfFileSystemItem; + try { + ownerOfFileSystemItem = userBusinessService.getUserById(fileSystemEntity.getCreatedByUserId()); + } catch (UserNotFoundException exception) { + throw new FileFighterDataException("Owner of a file could not be found."); + } + + boolean isShared = ownerOfFileSystemItem.getUserId() != authenticatedUser.getUserId(); + FileSystemType type = fileSystemTypeRepository.findFileSystemTypeById(fileSystemEntity.getTypeId()); + boolean isAFolder = type == FileSystemType.FOLDER && !fileSystemEntity.isFile(); + + return FileSystemItem.builder() + .createdByUser(ownerOfFileSystemItem) + .fileSystemId(fileSystemEntity.getFileSystemId()) + .lastUpdated(fileSystemEntity.getLastUpdated()) + .name(fileSystemEntity.getName()) + .size(fileSystemEntity.getSize()) + .type(isAFolder ? FileSystemType.FOLDER : type) + .path(null == basePath ? null : basePath + fileSystemEntity.getName()) + .isShared(isShared) + .mimeType(fileSystemEntity.getMimeType()) + .build(); + } + + public void createBasicFilesForNewUser(UserEntity registeredUserEntity) { + fileSystemRepository.save(FileSystemEntity + .builder() + .createdByUserId(0) + .typeId(FileSystemType.FOLDER.getId()) + .isFile(false) + .name("HOME_" + registeredUserEntity.getUsername()) + .path("/") + .lastUpdated(Instant.now().getEpochSecond()) + .fileSystemId(generateNextFileSystemId()) + .build()); + } + + public double getTotalFileSize() { + ArrayList entities = fileSystemRepository.findByPath("/"); + if (null == entities) + throw new FileFighterDataException("Couldn't find any Home directories!"); + + double size = 0; + for (FileSystemEntity entity : entities) { + size += entity.getSize(); + } + return size; + } + + public long getFileSystemEntityCount() { + return fileSystemRepository.count(); + } + + // This will update the field. -> Everytime this function gets called a id gets taken. Which means some ids could be lost, when calling this function and not creating something. + public long generateNextFileSystemId() { + return getFileSystemEntityCount() + 1; + } + + public long getCurrentTimeStamp() { + return System.currentTimeMillis() / 1000; + } +} diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/InteractionType.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/InteractionType.java new file mode 100644 index 00000000..9ea77d94 --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/InteractionType.java @@ -0,0 +1,7 @@ +package de.filefighter.rest.domain.filesystem.data; + +public enum InteractionType { + READ, + CHANGE, + DELETE +} diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java index 1768d341..9bafb56a 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java @@ -18,5 +18,6 @@ public class FileSystemItem { private User createdByUser; //uploadedBy private long lastUpdated; private FileSystemType type; + private String mimeType; } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java index 1110d6d3..f5e425d6 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItemUpdate.java @@ -4,10 +4,14 @@ import lombok.Builder; import lombok.Data; +import java.util.List; + @Data @Builder public class FileSystemItemUpdate { private String name; private FileSystemType type; private double size; + private boolean isInRoot; + private List children; } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java index 8cc710d9..9a1d039d 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java @@ -18,6 +18,7 @@ public class FileSystemEntity { private String path; @Builder.Default private long typeId = -1; + private String mimeType; private double size; private long lastUpdated; @Builder.Default diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java index 45544f3f..6331a22a 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java @@ -44,11 +44,11 @@ public ResponseEntity getFileOrFolderInfo( return fileSystemRestService.getInfoAboutFileOrFolderByIdAndAccessToken(fsItemId, accessToken); } - @GetMapping(FS_BASE_URI+"search") + @GetMapping(FS_BASE_URI + "search") public ResponseEntity searchFileOrFolderByName( @RequestParam(name = "name", defaultValue = "name") String name, @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken - ){ + ) { log.info("Searching for file or folder with name {}", name); return fileSystemRestService.findFileOrFolderByNameAndAccessToken(name, accessToken); @@ -64,22 +64,22 @@ public ResponseEntity uploadFileOrFolder( return fileSystemRestService.uploadFileSystemItemWithAccessToken(fileSystemItemUpdate, accessToken); } - @PutMapping(FS_BASE_URI+"{fsItemId}/update") + @PutMapping(FS_BASE_URI + "{fsItemId}/update") public ResponseEntity updateExistingFileOrFolder( @PathVariable long fsItemId, @RequestBody FileSystemItemUpdate fileSystemItemUpdate, @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken - ){ + ) { log.info("Tried updating FileSystemItem {} with {}.", fsItemId, fileSystemItemUpdate); - return fileSystemRestService.updatedFileSystemItemWithIdAndAccessToken(fsItemId, fileSystemItemUpdate, accessToken); + return fileSystemRestService.updateFileSystemItemWithIdAndAccessToken(fsItemId, fileSystemItemUpdate, accessToken); } - @DeleteMapping(FS_BASE_URI+"{fsItemId}/delete") + @DeleteMapping(FS_BASE_URI + "{fsItemId}/delete") public ResponseEntity deleteFileOrFolder( @PathVariable long fsItemId, @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken - ){ + ) { log.info("Tried deleting FileSystemItem with id {}", fsItemId); return fileSystemRestService.deleteFileSystemItemWithIdAndAccessToken(fsItemId, accessToken); diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java index ed469968..d1838fd4 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java @@ -1,7 +1,7 @@ package de.filefighter.rest.domain.filesystem.rest; import de.filefighter.rest.domain.authentication.AuthenticationService; -import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; +import de.filefighter.rest.domain.common.InputSanitizerService; import de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; @@ -18,16 +18,18 @@ public class FileSystemRestService implements FileSystemRestServiceInterface { private final FileSystemBusinessService fileSystemBusinessService; private final AuthenticationService authenticationService; + private final InputSanitizerService inputSanitizerService; - public FileSystemRestService(FileSystemBusinessService fileSystemBusinessService, AuthenticationService authenticationService) { + public FileSystemRestService(FileSystemBusinessService fileSystemBusinessService, AuthenticationService authenticationService, InputSanitizerService inputSanitizerService) { this.fileSystemBusinessService = fileSystemBusinessService; this.authenticationService = authenticationService; + this.inputSanitizerService = inputSanitizerService; } @Override public ResponseEntity> getContentsOfFolderByPathAndAccessToken(String path, String accessTokenValue) { User authenticatedUser = authenticationService.bearerAuthenticationWithAccessToken(accessTokenValue); - String cleanPathString = InputSanitizerService.sanitizeString(path); + String cleanPathString = inputSanitizerService.sanitizePath(path); ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(cleanPathString, authenticatedUser); return new ResponseEntity<>(fileSystemItems, HttpStatus.OK); @@ -50,7 +52,7 @@ public ResponseEntity uploadFileSystemItemWithAccessToken(FileSy } @Override - public ResponseEntity updatedFileSystemItemWithIdAndAccessToken(long fsItemId, FileSystemItemUpdate fileSystemItemUpdate, String accessToken) { + public ResponseEntity updateFileSystemItemWithIdAndAccessToken(long fsItemId, FileSystemItemUpdate fileSystemItemUpdate, String accessToken) { return null; } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java index b868aa7e..2ba796e3 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java @@ -9,9 +9,14 @@ public interface FileSystemRestServiceInterface { ResponseEntity> getContentsOfFolderByPathAndAccessToken(String path, String accessToken); + ResponseEntity getInfoAboutFileOrFolderByIdAndAccessToken(long fsItemId, String accessToken); + ResponseEntity findFileOrFolderByNameAndAccessToken(String name, String accessToken); + ResponseEntity uploadFileSystemItemWithAccessToken(FileSystemItemUpdate fileSystemItemUpdate, String accessToken); - ResponseEntity updatedFileSystemItemWithIdAndAccessToken(long fsItemId, FileSystemItemUpdate fileSystemItemUpdate, String accessToken); + + ResponseEntity updateFileSystemItemWithIdAndAccessToken(long fsItemId, FileSystemItemUpdate fileSystemItemUpdate, String accessToken); + ResponseEntity deleteFileSystemItemWithIdAndAccessToken(long fsItemId, String accessToken); } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemType.java b/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemType.java index cff30731..fc2bd93b 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemType.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemType.java @@ -4,10 +4,10 @@ public enum FileSystemType { UNDEFINED(-1), FOLDER(0), TEXT(1), - PICTURE(2), - PDF(3), - AUDIO(4), - VIDEO(5); + IMAGE(2), + AUDIO(3), + VIDEO(4), + APPLICATION(5); private final long id; diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemTypeRepository.java b/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemTypeRepository.java index a5c037f3..a666ad73 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemTypeRepository.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/type/FileSystemTypeRepository.java @@ -1,15 +1,42 @@ package de.filefighter.rest.domain.filesystem.type; +import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; @Service +@Log4j2 public class FileSystemTypeRepository { - public FileSystemType findFileSystemTypeById(long id){ + public FileSystemType findFileSystemTypeById(long id) { FileSystemType[] values = FileSystemType.values(); - for(FileSystemType type : values){ - if(type.getId() == id) return type; + for (FileSystemType type : values) { + if (type.getId() == id) return type; } - throw new IllegalArgumentException("No FileSystemType found for id: "+ id); + throw new IllegalArgumentException("No FileSystemType found for id: " + id); + } + + // https://www.sitepoint.com/mime-types-complete-list/ + public FileSystemType parseMimeType(String mimeType) { + FileSystemType returnValue = FileSystemType.UNDEFINED; + + // java sucks. Lets do kotlin next time. + if (null == mimeType) { + log.warn("Found null in mimeType"); + return FileSystemType.UNDEFINED; + } + + if (mimeType.contains("text/")) { + returnValue = FileSystemType.TEXT; + } else if (mimeType.contains("video/")) { + returnValue = FileSystemType.VIDEO; + } else if (mimeType.contains("audio/")) { + returnValue = FileSystemType.AUDIO; + } else if (mimeType.contains("image/")) { + returnValue = FileSystemType.IMAGE; + } else if (mimeType.contains("application/")) { + returnValue = FileSystemType.APPLICATION; + } + + return returnValue; } } diff --git a/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java b/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java index 5d032d26..ce78be34 100644 --- a/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java @@ -1,6 +1,6 @@ package de.filefighter.rest.domain.health.business; -import de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService; +import de.filefighter.rest.domain.filesystem.business.FileSystemHelperService; import de.filefighter.rest.domain.health.data.SystemHealth; import de.filefighter.rest.domain.health.data.SystemHealth.DataIntegrity; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; @@ -16,7 +16,7 @@ public class SystemHealthBusinessService { private final UserBusinessService userBusinessService; private final AccessTokenBusinessService accessTokenBusinessService; - private final FileSystemBusinessService fileSystemBusinessService; + private final FileSystemHelperService fileSystemHelperService; private final Environment environment; private final long serverStartedAt; @@ -25,10 +25,10 @@ public class SystemHealthBusinessService { @Value("${filefighter.version}") String version; - public SystemHealthBusinessService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService, FileSystemBusinessService fileSystemBusinessService, Environment environment) { + public SystemHealthBusinessService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService, FileSystemHelperService fileSystemHelperService, Environment environment) { this.userBusinessService = userBusinessService; this.accessTokenBusinessService = accessTokenBusinessService; - this.fileSystemBusinessService = fileSystemBusinessService; + this.fileSystemHelperService = fileSystemHelperService; this.environment = environment; this.serverStartedAt = this.getCurrentEpochSeconds(); } @@ -38,7 +38,7 @@ public SystemHealth getCurrentSystemHealthInfo() { return SystemHealth.builder() .uptimeInSeconds(currentEpoch - serverStartedAt) .userCount(userBusinessService.getUserCount()) - .usedStorageInBytes(fileSystemBusinessService.getTotalFileSize()) + .usedStorageInBytes(fileSystemHelperService.getTotalFileSize()) .dataIntegrity(calculateDataIntegrity()) .deployment(getDeploymentStatus()) .version("v" + this.version) diff --git a/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java b/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java index c3cb4269..9bb80493 100644 --- a/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/user/business/UserBusinessService.java @@ -22,7 +22,7 @@ import java.util.Arrays; import java.util.regex.Pattern; -import static de.filefighter.rest.domain.common.exceptions.InputSanitizerService.stringIsValid; +import static de.filefighter.rest.domain.common.InputSanitizerService.stringIsValid; @Service public class UserBusinessService { diff --git a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java index 8e3056fb..f8bb80da 100644 --- a/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java +++ b/src/main/java/de/filefighter/rest/domain/user/rest/UserRestService.java @@ -1,8 +1,8 @@ package de.filefighter.rest.domain.user.rest; import de.filefighter.rest.domain.authentication.AuthenticationService; -import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; -import de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService; +import de.filefighter.rest.domain.common.InputSanitizerService; +import de.filefighter.rest.domain.filesystem.business.FileSystemHelperService; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.token.data.dto.RefreshToken; @@ -23,14 +23,16 @@ public class UserRestService implements UserRestServiceInterface { private final UserBusinessService userBusinessService; private final AccessTokenBusinessService accessTokenBusinessService; - private final FileSystemBusinessService fileSystemBusinessService; private final AuthenticationService authenticationService; + private final InputSanitizerService inputSanitizerService; + private final FileSystemHelperService fileSystemHelperService; - public UserRestService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService, FileSystemBusinessService fileSystemBusinessService, AuthenticationService authenticationService) { + public UserRestService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService, AuthenticationService authenticationService, InputSanitizerService inputSanitizerService, FileSystemHelperService fileSystemHelperService) { this.userBusinessService = userBusinessService; this.accessTokenBusinessService = accessTokenBusinessService; - this.fileSystemBusinessService = fileSystemBusinessService; this.authenticationService = authenticationService; + this.inputSanitizerService = inputSanitizerService; + this.fileSystemHelperService = fileSystemHelperService; } @Override @@ -66,13 +68,13 @@ public ResponseEntity updateUserByUserIdAuthenticateWithAccessTo public ResponseEntity registerNewUserWithAccessToken(UserRegisterForm newUser, String accessTokenHeader) { authenticationService.bearerAuthenticationWithAccessTokenAndGroup(accessTokenHeader, ADMIN); UserEntity registeredUserEntity = userBusinessService.registerNewUser(newUser); - fileSystemBusinessService.createBasicFilesForNewUser(registeredUserEntity); + fileSystemHelperService.createBasicFilesForNewUser(registeredUserEntity); return new ResponseEntity<>(new ServerResponse(HttpStatus.CREATED, "User successfully created."), HttpStatus.CREATED); } @Override public ResponseEntity findUserByUsernameAndAccessToken(String username, String accessTokenHeader) { - String sanitizedUserName = InputSanitizerService.sanitizeString(username); + String sanitizedUserName = inputSanitizerService.sanitizeString(username); authenticationService.bearerAuthenticationWithAccessToken(accessTokenHeader); User foundUser = userBusinessService.findUserByUsername(sanitizedUserName); return new ResponseEntity<>(foundUser, HttpStatus.OK); diff --git a/src/main/resources/application-debug.properties b/src/main/resources/application-debug.properties new file mode 100644 index 00000000..d897a5af --- /dev/null +++ b/src/main/resources/application-debug.properties @@ -0,0 +1 @@ +logging.level.root=DEBUG \ No newline at end of file diff --git a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java index 73bfec8e..a08c48f3 100644 --- a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java @@ -7,14 +7,13 @@ import de.filefighter.rest.RestApplicationIntegrationTest; import io.cucumber.java.en.And; import io.cucumber.java.en.When; +import org.junit.jupiter.api.Assertions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpMethod; import java.util.HashMap; import static de.filefighter.rest.configuration.RestConfiguration.*; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; public class ViewFolderContentsSteps extends RestApplicationIntegrationTest { @@ -50,7 +49,22 @@ public void theResponseContainsTheFileWithIdAndName(long fsItemId, String name) !node.get("type").asText().equals("FOLDER")) found = true; } - assertTrue(found); + Assertions.assertTrue(found); + } + + @And("the response contains the file with name {string}") + public void theResponseContainsTheFileWithName(String name) throws JsonProcessingException { + ArrayNode rootNode = (ArrayNode) objectMapper.readTree(latestResponse.getBody()); + if (!rootNode.isContainerNode() || rootNode.isEmpty()) + throw new AssertionError("Response was not an Array or empty."); + + boolean found = false; + for (JsonNode node : rootNode) { + if (node.get("name").asText().equals(name) && + !node.get("type").asText().equals("FOLDER")) + found = true; + } + Assertions.assertTrue(found); } @And("the response contains an empty list for files and folders") @@ -59,7 +73,7 @@ public void theResponseContainsAnEmptyListForFilesAndFolders() throws JsonProces if (!rootNode.isContainerNode()) throw new AssertionError("Response was not an Array or empty."); - assertTrue(rootNode.isEmpty()); + Assertions.assertTrue(rootNode.isEmpty()); } @And("the response does not contains the file with fileSystemId {long} and name {string}") @@ -77,7 +91,7 @@ public void theResponseNotContainsTheFileWithFileSystemIdAndName(long fsItemId, found = true; } } - assertFalse(found); + Assertions.assertFalse(found); } } @@ -94,6 +108,6 @@ public void theResponseContainsTheFolderWithFileSystemIdAndName(long fileSystemI node.get("type").asText().equals("FOLDER")) found = true; } - assertTrue(found); + Assertions.assertTrue(found); } } diff --git a/src/test/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessServiceUnitTest.java index efc07a95..db735566 100644 --- a/src/test/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/authentication/AuthenticationBusinessServiceUnitTest.java @@ -1,5 +1,6 @@ package de.filefighter.rest.domain.authentication; +import de.filefighter.rest.domain.common.InputSanitizerService; import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.user.business.UserDTOService; @@ -19,9 +20,10 @@ class AuthenticationBusinessServiceUnitTest { private final UserRepository userRepositoryMock = mock(UserRepository.class); private final UserDTOService userDtoServiceMock = mock(UserDTOService.class); + private final InputSanitizerService inputSanitizerServiceMock = mock(InputSanitizerService.class); private final AuthenticationBusinessService authenticationBusinessService = new AuthenticationBusinessService( userRepositoryMock, - userDtoServiceMock); + userDtoServiceMock, inputSanitizerServiceMock); @Test void authenticateUserWithUsernameAndPasswordThrows() { @@ -52,6 +54,8 @@ void authenticateUserWithUsernameAndPasswordWorksCorrectly() { when(userRepositoryMock.findByLowercaseUsernameAndPassword("user", "password")).thenReturn(dummyEntity); when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(dummyUser); + when(inputSanitizerServiceMock.sanitizeString("user")).thenReturn("user"); + when(inputSanitizerServiceMock.sanitizeString("password")).thenReturn("password"); User actual = authenticationBusinessService.authenticateUserWithUsernameAndPassword(usernameAndPassword); assertEquals(dummyUser, actual); diff --git a/src/test/java/de/filefighter/rest/domain/common/InputSanitizerServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/common/InputSanitizerServiceUnitTest.java index 4e7cb15f..9ab14537 100644 --- a/src/test/java/de/filefighter/rest/domain/common/InputSanitizerServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/common/InputSanitizerServiceUnitTest.java @@ -1,6 +1,5 @@ package de.filefighter.rest.domain.common; -import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException; import org.junit.jupiter.api.Test; @@ -25,12 +24,12 @@ void sanitizeStringThrows() { String string1 = null; RequestDidntMeetFormalRequirementsException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - InputSanitizerService.sanitizeString(string0)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); + inputSanitizerService.sanitizeString(string0)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " String was empty.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> - InputSanitizerService.sanitizeString(string1)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); + inputSanitizerService.sanitizeString(string1)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " String was empty.", ex.getMessage()); } @Test @@ -40,8 +39,8 @@ void sanitizeStringWorks() { String string0valid = "aaabbbbbbb"; String string1valid = "asd"; - assertEquals(string0valid, InputSanitizerService.sanitizeString(string0)); - assertEquals(string1valid, InputSanitizerService.sanitizeString(string1)); + assertEquals(string0valid, inputSanitizerService.sanitizeString(string0)); + assertEquals(string1valid, inputSanitizerService.sanitizeString(string1)); } @Test @@ -54,19 +53,19 @@ void sanitizeRequestHeaderThrows() { RequestDidntMeetFormalRequirementsException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeRequestHeader(header, string0)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" Header does not contain a valid String.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Header does not contain a valid String.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeRequestHeader(header, string1)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" Header does not contain a valid String.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Header does not contain a valid String.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeRequestHeader(header, string2)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" Header does not contain '" + header + "', or format is invalid.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Header does not contain '" + header + "', or format is invalid.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeRequestHeader(header, string3)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" Header does not contain '" + header + "', or format is invalid.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Header does not contain '" + header + "', or format is invalid.", ex.getMessage()); } @@ -88,11 +87,11 @@ void sanitizeTokenThrows() { RequestDidntMeetFormalRequirementsException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeTokenValue(string0)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " String was empty.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeTokenValue(string1)); - assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " String was empty.", ex.getMessage()); } @@ -107,4 +106,46 @@ void sanitizeTokenWorks() { assertEquals(string1valid, inputSanitizerService.sanitizeTokenValue(string1)); } + @Test + void sanitizePathThrows() { + String working0 = "/ foo / bar / "; + String working1 = "foo/bar/foobar"; + String working2 = "foo/bar/foo-bar.txt"; + String working3 = "foo/bar/foo_bar_BAUM_ASDASD.txt"; + String nonWorking0 = "//foo/bar"; + String nonWorking1 = "\\/foo/bar"; + String nonWorking2 = "/~foo/bar"; + String nonWorking3 = "/*()foo/bar"; + String nonWorking4 = "/?foo/bar"; + String nonWorking5 = "\\\\foo/bar"; + + assertEquals("/foo/bar/", inputSanitizerService.sanitizePath(working0)); + assertEquals("foo/bar/foobar", inputSanitizerService.sanitizePath(working1)); + assertEquals("foo/bar/foo-bar.txt", inputSanitizerService.sanitizePath(working2)); + assertEquals("foo/bar/foo_bar_BAUM_ASDASD.txt", inputSanitizerService.sanitizePath(working3)); + + RequestDidntMeetFormalRequirementsException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + inputSanitizerService.sanitizePath(nonWorking0)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); + + ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + inputSanitizerService.sanitizePath(nonWorking1)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); + + ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + inputSanitizerService.sanitizePath(nonWorking2)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); + + ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + inputSanitizerService.sanitizePath(nonWorking3)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); + + ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + inputSanitizerService.sanitizePath(nonWorking4)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); + + ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> + inputSanitizerService.sanitizePath(nonWorking5)); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); + } } \ No newline at end of file diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index b0b02559..7f598582 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -1,7 +1,7 @@ package de.filefighter.rest.domain.filesystem.business; -import de.filefighter.rest.configuration.RestConfiguration; import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; +import de.filefighter.rest.domain.filesystem.data.InteractionType; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemEntity; import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemRepository; @@ -12,16 +12,16 @@ import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; -import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; -import de.filefighter.rest.domain.user.group.Group; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import java.util.ArrayList; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; class FileSystemBusinessServiceUnitTest { @@ -30,7 +30,8 @@ class FileSystemBusinessServiceUnitTest { private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); - private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, userBusinessServiceMock, fileSystemTypeRepositoryMock, mongoTemplateMock); + private final FileSystemHelperService fileSystemHelperServiceMock = mock(FileSystemHelperService.class); + private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, mongoTemplateMock); @Test void getFolderContentsByPathThrows() { @@ -54,6 +55,7 @@ void getFolderContentsByPathThrows() { assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix() + " Path was in wrong format. Use a leading backslash.", ex.getMessage()); when(fileSystemRepositoryMock.findByPath(validPath)).thenReturn(null); + when(fileSystemHelperServiceMock.removeTrailingBackSlashes(validPath)).thenReturn(validPath); ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(validPath, dummyUser)); @@ -82,6 +84,10 @@ void getFolderContentsByPathWorks() { ArrayList entities = new ArrayList<>(); entities.add(foundFolder); + when(fileSystemHelperServiceMock.removeTrailingBackSlashes(pathToRequest)).thenReturn(path); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundFolder, user, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundFolder, user, true, false)).thenReturn(entities); + when(fileSystemHelperServiceMock.createDTO(foundFolder, user, pathToRequest)).thenReturn(FileSystemItem.builder().build()); when(fileSystemRepositoryMock.findByPath(path)).thenReturn(entities); when(fileSystemRepositoryMock.findByFileSystemId(fileIdInFolder)).thenReturn(FileSystemEntity.builder().createdByUserId(userId).build()); when(userBusinessServiceMock.getUserById(userId)).thenReturn(User.builder().build()); @@ -90,22 +96,6 @@ void getFolderContentsByPathWorks() { assertEquals(1, fileSystemItems.size()); } - @Test - void getFolderContentsOfEntityThrows() { - long fileSystemId0 = 420; - long fileSystemId1 = 1234; - - User authenticatedUser = User.builder().build(); - FileSystemEntity rootFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId0, fileSystemId1}).build(); - - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(FileSystemEntity.builder().build()); - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId1)).thenReturn(null); - - FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, true, false)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FolderContents expected fileSystemItem with id " + fileSystemId1 + " but was empty.", ex.getMessage()); - } - @Test void recursivelyDeleteFileSystemEntityThrows() { long fsItemId = 12301231; @@ -121,13 +111,19 @@ void recursivelyDeleteFileSystemEntityThrows() { FileSystemEntity rootFolder = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).build(); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); - + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, false)).thenReturn(new ArrayList<>()); ex = assertThrows(FileFighterDataException.class, () -> fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFolder, authenticatedUser)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); FileSystemEntity rootFolder1 = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).itemIds(new long[]{fileSystemId0}).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(FileSystemEntity.builder().fileSystemId(fileSystemId0).build()); + ArrayList arrayListMock = new ArrayList<>(1); + FileSystemEntity fileInRootFolder = FileSystemEntity.builder().fileSystemId(fileSystemId0).build(); + arrayListMock.add(fileInRootFolder); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(rootFolder1, authenticatedUser, false, false)).thenReturn(arrayListMock); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileInRootFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileInRootFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(fileInRootFolder); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); ex = assertThrows(FileFighterDataException.class, () -> @@ -140,63 +136,6 @@ void recursivelyDeleteFileSystemEntityThrows() { assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); } - @Test - void getFolderContentsOfEntityWorks() { - long fileSystemId0 = 420; - long fileSystemId1 = 1234; - long fileSystemId2 = 1231231234; - long userId = 123123321; - - User authenticatedUser = User.builder().userId(userId).build(); - - FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().visibleForUserIds(new long[]{userId}).build(); - FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().editableForUserIds(new long[]{userId}).build(); - FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().createdByUserId(userId).build(); - - FileSystemEntity rootFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId0, fileSystemId1, fileSystemId2}).build(); - - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(fileSystemEntity0); - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId1)).thenReturn(fileSystemEntity1); - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId2)).thenReturn(fileSystemEntity2); - - ArrayList fs0 = (ArrayList) fileSystemBusinessService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, true, false); - ArrayList fs1 = (ArrayList) fileSystemBusinessService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, true); - ArrayList fs2 = (ArrayList) fileSystemBusinessService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, true, true); - ArrayList fs3 = (ArrayList) fileSystemBusinessService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, false); - - assertEquals(2, fs0.size()); - assertEquals(fileSystemEntity0, fs0.get(0)); - assertEquals(2, fs1.size()); - assertEquals(fileSystemEntity1, fs1.get(0)); - assertEquals(1, fs2.size()); - assertEquals(3, fs3.size()); - // why can't I compare 3 objects at once :( - assertNotEquals(fs3.get(0), fs3.get(1)); - assertNotEquals(fs3.get(1), fs3.get(2)); - assertNotEquals(fs3.get(0), fs3.get(2)); - } - - @Test - void sumUpAllPermissionsOfFileSystemEntitiesWorks() { - FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().visibleForUserIds(new long[]{0, 2, 4}).visibleForGroupIds(new long[]{0, 2, 4}).editableForUserIds(new long[]{0, 2, 4}).editableFoGroupIds(new long[]{0, 2, 4}).build(); - FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().visibleForUserIds(new long[]{1, 2, 3, 4}).visibleForGroupIds(new long[]{1, 2, 3, 4}).editableForUserIds(new long[]{1, 2, 3, 4}).editableFoGroupIds(new long[]{1, 2, 3, 4}).build(); - FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().visibleForUserIds(new long[]{1, 3}).visibleForGroupIds(new long[]{1, 3}).editableForUserIds(new long[]{1, 3}).editableFoGroupIds(new long[]{1, 3}).build(); - FileSystemEntity fileSystemEntity3 = FileSystemEntity.builder().visibleForUserIds(new long[]{2, 4}).visibleForGroupIds(new long[]{2, 4}).editableForUserIds(new long[]{2, 4}).editableFoGroupIds(new long[]{2, 4}).build(); - - FileSystemEntity parentFileSystemEntity = FileSystemEntity.builder().visibleForUserIds(new long[]{-10, -99, 9}).build(); - ArrayList fileSystemEntityArrayList = new ArrayList<>(); - fileSystemEntityArrayList.add(fileSystemEntity0); - fileSystemEntityArrayList.add(fileSystemEntity1); - fileSystemEntityArrayList.add(fileSystemEntity2); - fileSystemEntityArrayList.add(fileSystemEntity3); - - FileSystemEntity actualFileSystemEntity = fileSystemBusinessService.sumUpAllPermissionsOfFileSystemEntities(parentFileSystemEntity, fileSystemEntityArrayList); - assertEquals(5, actualFileSystemEntity.getVisibleForUserIds().length); - assertEquals(5, actualFileSystemEntity.getVisibleForGroupIds().length); - assertEquals(5, actualFileSystemEntity.getEditableForUserIds().length); - assertEquals(5, actualFileSystemEntity.getEditableFoGroupIds().length); - } - @Test void deleteFileSystemItemByIdThrows() { long fsItemId = 12332123; @@ -214,6 +153,8 @@ void deleteFileSystemItemByIdThrows() { assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + fsItemId, ex.getMessage()); foundEntity = FileSystemEntity.builder().createdByUserId(userId).isFile(true).typeId(0).build(); + when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ))).thenReturn(true); + when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE))).thenReturn(true); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); FileFighterDataException ex1 = assertThrows(FileFighterDataException.class, () -> @@ -222,9 +163,14 @@ void deleteFileSystemItemByIdThrows() { long folderContentId = 13287132; FileSystemEntity folderContentEntity = FileSystemEntity.builder().createdByUserId(userId).isFile(true).typeId(0).build(); + ArrayList fileSystemEntitiesMock = new ArrayList<>(); + fileSystemEntitiesMock.add(folderContentEntity); when(fileSystemRepositoryMock.findByFileSystemId(folderContentId)).thenReturn(folderContentEntity); foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).createdByUserId(userId).itemIds(new long[]{folderContentId}).build(); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundEntity, authenticatedUser, false, false)).thenReturn(fileSystemEntitiesMock); ex1 = assertThrows(FileFighterDataException.class, () -> fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FileType was wrong. " + folderContentEntity, ex1.getMessage()); @@ -236,6 +182,8 @@ void deleteFileSystemItemByIdWorksWithFile() { long userId = 243724328; User authenticatedUser = User.builder().userId(userId).build(); FileSystemEntity foundEntity = FileSystemEntity.builder().fileSystemId(fsItemId).typeId(1).isFile(true).createdByUserId(userId).build(); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); @@ -245,21 +193,32 @@ void deleteFileSystemItemByIdWorksWithFile() { @Test void deleteFileSystemItemByIdWorksWithFolder() { - long fsItemId = 12332123; + long folderId = 12332123; + long fileId = 420; long userId = 243724328; User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity foundEntity = FileSystemEntity.builder().fileSystemId(fsItemId).typeId(0).isFile(false).createdByUserId(userId).build(); + FileSystemEntity folder = FileSystemEntity.builder().fileSystemId(folderId).typeId(0).isFile(false).createdByUserId(userId).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemRepositoryMock.findByFileSystemId(folderId)).thenReturn(folder); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); - when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); - - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - - foundEntity = FileSystemEntity.builder().typeId(0).fileSystemId(fsItemId).isFile(false).createdByUserId(userId).itemIds(new long[0]).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - verify(fileSystemRepositoryMock, times(2)).deleteByFileSystemId(fsItemId); + when(fileSystemRepositoryMock.deleteByFileSystemId(folderId)).thenReturn(1L); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + + FileSystemEntity file = FileSystemEntity.builder().typeId(2).fileSystemId(fileId).isFile(true).createdByUserId(userId).itemIds(new long[0]).build(); + ArrayList foundFiles = new ArrayList<>(); + foundFiles.add(file); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(folder, authenticatedUser, false, false)).thenReturn(foundFiles); + + when(fileSystemRepositoryMock.findByFileSystemId(fileId)).thenReturn(file); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(file, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(file, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(2)).thenReturn(FileSystemType.VIDEO); + when(fileSystemRepositoryMock.deleteByFileSystemId(fileId)).thenReturn(1L); + + fileSystemBusinessService.deleteFileSystemItemById(folderId, authenticatedUser); + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(folderId); + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(fileId); } @Test @@ -273,14 +232,28 @@ void deleteFileSystemItemByIdWorksWithFolderWhenAllItemsCanBeDeleted() { FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().isFile(false).typeId(0).createdByUserId(userId).fileSystemId(itemId0).build(); FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().fileSystemId(itemId1).typeId(1).createdByUserId(userId).isFile(true).build(); FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().fileSystemId(itemId2).typeId(1).createdByUserId(userId).isFile(true).build(); - FileSystemEntity foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).createdByUserId(userId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); + FileSystemEntity parentFolder = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).createdByUserId(userId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(parentFolder); when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(fileSystemEntity0); when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(fileSystemEntity1); when(fileSystemRepositoryMock.findByFileSystemId(itemId2)).thenReturn(fileSystemEntity2); + ArrayList contentList = new ArrayList<>(); + contentList.add(fileSystemEntity0); + contentList.add(fileSystemEntity1); + contentList.add(fileSystemEntity2); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(parentFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(parentFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity0, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity0, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity1, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity1, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity2, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity2, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(parentFolder, authenticatedUser, false, false)).thenReturn(contentList); + when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); when(fileSystemRepositoryMock.deleteByFileSystemId(itemId1)).thenReturn(1L); @@ -303,13 +276,30 @@ void deleteFileSystemItemByIdWorksWithFolderWhenSomeItemsCannotBeDeleted() { long itemId2 = 1923847; long itemId3 = 9817232; User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).createdByUserId(userId).itemIds(new long[]{itemId0, itemId1, itemId2, itemId3}).build(); + FileSystemEntity foundFolder = FileSystemEntity.builder().typeId(0).isFile(false).createdByUserId(userId).itemIds(new long[]{itemId0, itemId1, itemId2, itemId3}).build(); FileSystemEntity visibleEditableEmptyFolder = FileSystemEntity.builder().isFile(false).typeId(0).createdByUserId(userId).fileSystemId(itemId0).build(); FileSystemEntity invisibleFile = FileSystemEntity.builder().fileSystemId(itemId1).isFile(true).build(); FileSystemEntity visibleNonEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).visibleForUserIds(new long[]{userId}).isFile(true).build(); FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId3).createdByUserId(userId).isFile(true).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundFolder); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableEmptyFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableEmptyFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleNonEditableFile, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleNonEditableFile, authenticatedUser, InteractionType.DELETE)).thenReturn(false); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableFile, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableFile, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + + ArrayList foundEntities = new ArrayList<>(); + foundEntities.add(visibleEditableFile); + foundEntities.add(invisibleFile); + foundEntities.add(visibleNonEditableFile); + foundEntities.add(visibleEditableEmptyFolder); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundFolder, authenticatedUser, false, false)).thenReturn(foundEntities); + when(fileSystemHelperServiceMock.sumUpAllPermissionsOfFileSystemEntities(any(), any())).thenReturn(foundFolder); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(-1)).thenReturn(FileSystemType.UNDEFINED); when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(visibleEditableEmptyFolder); @@ -338,10 +328,19 @@ void deleteFileSystemItemByIdWorksWithFolderOnlyInvisible() { long itemId0 = 1233212; long itemId1 = 9872317; long itemId2 = 1923847; - FileSystemEntity foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).createdByUserId(userId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); // TODO: implement this edge case. (created by.) - FileSystemEntity visibleEditableEmptyFolder = FileSystemEntity.builder().isFile(false).typeId(0).createdByUserId(userId).fileSystemId(itemId0).build(); + FileSystemEntity foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); + FileSystemEntity visibleEditableEmptyFolder = FileSystemEntity.builder().isFile(false).typeId(0).fileSystemId(itemId0).build(); FileSystemEntity invisibleFile = FileSystemEntity.builder().fileSystemId(itemId1).isFile(true).visibleForUserIds(new long[]{userId - 1}).build(); - FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).createdByUserId(userId).isFile(true).build(); + FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).isFile(true).build(); + + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + + ArrayList foundEntities = new ArrayList<>(); + foundEntities.add(visibleEditableFile); + foundEntities.add(invisibleFile); + foundEntities.add(visibleEditableEmptyFolder); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundEntity, authenticatedUser, false, false)).thenReturn(foundEntities); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); @@ -352,15 +351,18 @@ void deleteFileSystemItemByIdWorksWithFolderOnlyInvisible() { when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); when(fileSystemRepositoryMock.deleteByFileSystemId(itemId2)).thenReturn(1L); + FileSystemEntity entityWithSummedUpPermissions = FileSystemEntity.builder().build(); + entityWithSummedUpPermissions.setVisibleForUserIds(invisibleFile.getVisibleForUserIds()); + when(fileSystemHelperServiceMock.sumUpAllPermissionsOfFileSystemEntities(foundEntity, foundEntities)).thenReturn(entityWithSummedUpPermissions); fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - // verify deleted entities. - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId0); - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId2); - + // nothing should be deleted, but parent folder should be changed, so the user cannot see the "deleted" folder anymore. ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); - verify(mongoTemplateMock, times(1)).findAndModify(any(), updateArgumentCaptor.capture(), any()); - assertEquals("{ \"$set\" : { \"itemIds\" : [ " + itemId1 + " ], \"visibleForUserIds\" : [ " + (userId - 1) + " ], \"visibleForGroupIds\" : [ ], \"editableForUserIds\" : [ ], \"editableForGroupIds\" : [ ] } }", updateArgumentCaptor.getValue().toString()); // no better way to assert requested changes. + ArgumentCaptor queryArgumentCaptor = ArgumentCaptor.forClass(Query.class); + + verify(mongoTemplateMock, times(1)).findAndModify(queryArgumentCaptor.capture(), updateArgumentCaptor.capture(), eq(FileSystemEntity.class)); + assertEquals("Query: { \"fileSystemId\" : " + fsItemId + "}, Fields: {}, Sort: {}", queryArgumentCaptor.getValue().toString()); + assertEquals("{ \"$set\" : { \"itemIds\" : [ " + itemId0 + ", " + itemId1 + ", " + itemId2 + " ], \"visibleForUserIds\" : [ " + (userId - 1) + " ], \"visibleForGroupIds\" : [ ], \"editableForUserIds\" : [ ], \"editableForGroupIds\" : [ ] } }", updateArgumentCaptor.getValue().toString()); // no better way to assert requested changes. } @Test @@ -386,168 +388,14 @@ void getFileSystemItemInfoWorks() { String name = "Folder"; User dummyUser = User.builder().userId(userId).build(); FileSystemEntity entity = FileSystemEntity.builder().name(name).createdByUserId(userId).build(); + FileSystemItem item = FileSystemItem.builder().build(); when(userBusinessServiceMock.getUserById(userId)).thenReturn(dummyUser); when(fileSystemRepositoryMock.findByFileSystemId(id)).thenReturn(entity); - FileSystemItem fileSystemItem = fileSystemBusinessService.getFileSystemItemInfo(id, dummyUser); - assertEquals(name, fileSystemItem.getName()); - assertEquals(userId, fileSystemItem.getCreatedByUser().getUserId()); - assertNull(fileSystemItem.getPath()); - assertFalse(fileSystemItem.isShared()); - } + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity, dummyUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.createDTO(entity, dummyUser, null)).thenReturn(item); - @Test - void removeTrailingWhiteSpaces() { - String doesNotRemove0 = "/"; - String doesNotRemove1 = "/ugabuga"; - String doesRemove = "/uga/"; - String removed = "/uga"; - - - String actual0 = fileSystemBusinessService.removeTrailingBackSlashes(doesNotRemove0); - assertEquals(doesNotRemove0, actual0); - - String actual1 = fileSystemBusinessService.removeTrailingBackSlashes(doesNotRemove1); - assertEquals(doesNotRemove1, actual1); - - String actual2 = fileSystemBusinessService.removeTrailingBackSlashes(doesRemove); - assertEquals(removed, actual2); - } - - @Test - void userIsAllowedToSeeFileSystemEntity() { - long userId = 1232783672; - User user = User.builder().userId(userId).build(); - FileSystemEntity fileSystemEntity = FileSystemEntity.builder().createdByUserId(userId).build(); - - // user created fileSystemItem - assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); - - // user created containing folder - fileSystemEntity.setCreatedByUserId(1203891230); - fileSystemEntity.setOwnerIds(new long[]{userId}); - assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); - - // user got it shared. - fileSystemEntity = FileSystemEntity.builder().visibleForUserIds(new long[]{userId}).build(); - assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); - - //user is in group - user = User.builder().userId(123897123).groups(new Group[]{Group.ADMIN}).build(); - fileSystemEntity = FileSystemEntity.builder().fileSystemId(9872347).visibleForGroupIds(new long[]{1}).build(); - assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); - - // user is not allowed. - user = User.builder().userId(123).groups(new Group[]{Group.UNDEFINED}).build(); - fileSystemEntity = FileSystemEntity.builder().createdByUserId(321).visibleForGroupIds(new long[]{1}).build(); - assertFalse(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); - } - - @Test - void userIsAllowedToEditFileSystemEntity() { - long userId = 1232783672; - User user = User.builder().userId(userId).build(); - FileSystemEntity fileSystemEntity = FileSystemEntity.builder().createdByUserId(userId).build(); - - // fileSystemEntity was created by runtime user. - assertFalse(fileSystemBusinessService.userIsAllowedToEditFileSystemEntity(FileSystemEntity.builder().createdByUserId(RestConfiguration.RUNTIME_USER_ID).build(), user)); - - // user created fileSystemItem - assertTrue(fileSystemBusinessService.userIsAllowedToEditFileSystemEntity(fileSystemEntity, user)); - - // user created containing folder - fileSystemEntity.setCreatedByUserId(1203891230); - fileSystemEntity.setOwnerIds(new long[]{userId}); - assertTrue(fileSystemBusinessService.userIsAllowedToEditFileSystemEntity(fileSystemEntity, user)); - - // user got it shared. - fileSystemEntity = FileSystemEntity.builder().editableForUserIds(new long[]{userId}).build(); - assertTrue(fileSystemBusinessService.userIsAllowedToEditFileSystemEntity(fileSystemEntity, user)); - - //user is in group - user = User.builder().userId(0).groups(new Group[]{Group.ADMIN}).build(); - fileSystemEntity = FileSystemEntity.builder().editableFoGroupIds(new long[]{1}).build(); - assertTrue(fileSystemBusinessService.userIsAllowedToEditFileSystemEntity(fileSystemEntity, user)); - - // user is not allowed. - user = User.builder().userId(123).groups(new Group[]{Group.UNDEFINED}).build(); - fileSystemEntity = FileSystemEntity.builder().createdByUserId(321).editableFoGroupIds(new long[]{1}).build(); - assertFalse(fileSystemBusinessService.userIsAllowedToEditFileSystemEntity(fileSystemEntity, user)); - } - - @Test - void createDTOThrows() { - long userId = 420; - FileSystemEntity entity = FileSystemEntity.builder().createdByUserId(userId).build(); - User user = User.builder().build(); - - when(userBusinessServiceMock.getUserById(userId)).thenThrow(UserNotFoundException.class); - - FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.createDTO(entity, user, null)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Owner of a file could not be found.", ex.getMessage()); - } - - @Test - void createDTOWorks() { - long createdByUserId = 420L; - String basePath = "/someTHING/somethingElse/"; - long[] items = new long[]{1, 2, 3}; - long fileSystemId = 123123; - boolean isFile = true; - long lastUpdated = 123123; - String name = "SomeText.txt"; - double size = 123321; - long typeId = -1; - - User authenticatedUser = User.builder().userId(createdByUserId - 1).build(); - User userThatCreatedFile = User.builder().userId(createdByUserId).build(); - FileSystemEntity fileSystemEntity = FileSystemEntity - .builder() - .createdByUserId(createdByUserId) - .itemIds(items) - .fileSystemId(fileSystemId) - .isFile(isFile) - .lastUpdated(lastUpdated) - .name(name) - .path("") // is empty because its a file. - .size(size) - .typeId(typeId) - .build(); - - when(userBusinessServiceMock.getUserById(createdByUserId)).thenReturn(userThatCreatedFile); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(typeId)).thenReturn(FileSystemType.UNDEFINED); - - FileSystemItem actual = fileSystemBusinessService.createDTO(fileSystemEntity, authenticatedUser, basePath); - - assertEquals(createdByUserId, actual.getCreatedByUser().getUserId()); - assertEquals(fileSystemId, actual.getFileSystemId()); - assertEquals(lastUpdated, actual.getLastUpdated()); - assertEquals(name, actual.getName()); - assertEquals(size, actual.getSize()); - assertEquals(FileSystemType.UNDEFINED, actual.getType()); - assertEquals(basePath + name, actual.getPath()); - assertTrue(actual.isShared()); - } - - @Test - void getTotalFileSizeThrows() { - when(fileSystemRepositoryMock.findByPath("/")).thenReturn(null); - FileFighterDataException ex = assertThrows(FileFighterDataException.class, fileSystemBusinessService::getTotalFileSize); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Couldn't find any Home directories!", ex.getMessage()); - } - - @Test - void getTotalFileSizeWorks() { - double size0 = 1.3; - double size1 = 2.4; - ArrayList entities = new ArrayList<>(); - entities.add(FileSystemEntity.builder().size(size0).build()); - entities.add(FileSystemEntity.builder().size(size1).build()); - - when(fileSystemRepositoryMock.findByPath("/")).thenReturn(entities); - - double actualSize = fileSystemBusinessService.getTotalFileSize(); - assertEquals(size0 + size1, actualSize); + FileSystemItem fileSystemItem = fileSystemBusinessService.getFileSystemItemInfo(id, dummyUser); + assertEquals(item, fileSystemItem); } } \ No newline at end of file diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java new file mode 100644 index 00000000..44eab450 --- /dev/null +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -0,0 +1,262 @@ +package de.filefighter.rest.domain.filesystem.business; + + +import de.filefighter.rest.configuration.RestConfiguration; +import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; +import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; +import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemEntity; +import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemRepository; +import de.filefighter.rest.domain.filesystem.type.FileSystemType; +import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; +import de.filefighter.rest.domain.user.business.UserBusinessService; +import de.filefighter.rest.domain.user.data.dto.User; +import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; +import de.filefighter.rest.domain.user.group.Group; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static de.filefighter.rest.domain.filesystem.data.InteractionType.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class FileSystemHelperServiceUnitTest { + + private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); + private final FileSystemRepository fileSystemRepositoryMock = mock(FileSystemRepository.class); + private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); + + private final FileSystemHelperService fileSystemHelperService = new FileSystemHelperService(fileSystemRepositoryMock, fileSystemTypeRepositoryMock, userBusinessServiceMock); + + @Test + void sumUpAllPermissionsOfFileSystemEntitiesWorks() { + FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().visibleForUserIds(new long[]{0, 2, 4}).visibleForGroupIds(new long[]{0, 2, 4}).editableForUserIds(new long[]{0, 2, 4}).editableFoGroupIds(new long[]{0, 2, 4}).build(); + FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().visibleForUserIds(new long[]{1, 2, 3, 4}).visibleForGroupIds(new long[]{1, 2, 3, 4}).editableForUserIds(new long[]{1, 2, 3, 4}).editableFoGroupIds(new long[]{1, 2, 3, 4}).build(); + FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().visibleForUserIds(new long[]{1, 3}).visibleForGroupIds(new long[]{1, 3}).editableForUserIds(new long[]{1, 3}).editableFoGroupIds(new long[]{1, 3}).build(); + FileSystemEntity fileSystemEntity3 = FileSystemEntity.builder().visibleForUserIds(new long[]{2, 4}).visibleForGroupIds(new long[]{2, 4}).editableForUserIds(new long[]{2, 4}).editableFoGroupIds(new long[]{2, 4}).build(); + + FileSystemEntity parentFileSystemEntity = FileSystemEntity.builder().visibleForUserIds(new long[]{-10, -99, 9}).build(); + ArrayList fileSystemEntityArrayList = new ArrayList<>(); + fileSystemEntityArrayList.add(fileSystemEntity0); + fileSystemEntityArrayList.add(fileSystemEntity1); + fileSystemEntityArrayList.add(fileSystemEntity2); + fileSystemEntityArrayList.add(fileSystemEntity3); + + FileSystemEntity actualFileSystemEntity = fileSystemHelperService.sumUpAllPermissionsOfFileSystemEntities(parentFileSystemEntity, fileSystemEntityArrayList); + assertEquals(5, actualFileSystemEntity.getVisibleForUserIds().length); + assertEquals(5, actualFileSystemEntity.getVisibleForGroupIds().length); + assertEquals(5, actualFileSystemEntity.getEditableForUserIds().length); + assertEquals(5, actualFileSystemEntity.getEditableFoGroupIds().length); + } + + @Test + void getFolderContentsOfEntityThrows() { + long fileSystemId0 = 420; + long fileSystemId1 = 1234; + + User authenticatedUser = User.builder().build(); + FileSystemEntity rootFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId0, fileSystemId1}).build(); + + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(FileSystemEntity.builder().build()); + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId1)).thenReturn(null); + + FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> + fileSystemHelperService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, true, false)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FolderContents expected fileSystemItem with id " + fileSystemId1 + " but was empty.", ex.getMessage()); + } + + @Test + void getFolderContentsOfEntityWorks() { + long fileSystemId0 = 420; + long fileSystemId1 = 1234; + long fileSystemId2 = 1231231234; + long userId = 123123321; + + User authenticatedUser = User.builder().userId(userId).build(); + + FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().visibleForUserIds(new long[]{userId}).build(); + FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().editableForUserIds(new long[]{userId}).build(); + FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().createdByUserId(userId).build(); + + FileSystemEntity rootFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId0, fileSystemId1, fileSystemId2}).build(); + + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(fileSystemEntity0); + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId1)).thenReturn(fileSystemEntity1); + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId2)).thenReturn(fileSystemEntity2); + + ArrayList fs0 = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, true, false); + ArrayList fs1 = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, true); + ArrayList fs2 = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, true, true); + ArrayList fs3 = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, false); + + assertEquals(2, fs0.size()); + assertEquals(fileSystemEntity0, fs0.get(0)); + assertEquals(2, fs1.size()); + assertEquals(fileSystemEntity1, fs1.get(0)); + assertEquals(1, fs2.size()); + assertEquals(3, fs3.size()); + // why can't I compare 3 objects at once :( + assertNotEquals(fs3.get(0), fs3.get(1)); + assertNotEquals(fs3.get(1), fs3.get(2)); + assertNotEquals(fs3.get(0), fs3.get(2)); + } + + @Test + void removeTrailingWhiteSpaces() { + String doesNotRemove0 = "/"; + String doesNotRemove1 = "/ugabuga"; + String doesRemove = "/uga/"; + String removed = "/uga"; + + + String actual0 = fileSystemHelperService.removeTrailingBackSlashes(doesNotRemove0); + assertEquals(doesNotRemove0, actual0); + + String actual1 = fileSystemHelperService.removeTrailingBackSlashes(doesNotRemove1); + assertEquals(doesNotRemove1, actual1); + + String actual2 = fileSystemHelperService.removeTrailingBackSlashes(doesRemove); + assertEquals(removed, actual2); + } + + @Test + void userIsAllowedToReadFileSystemEntity() { + long userId = 1232783672; + User user = User.builder().userId(userId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().createdByUserId(userId).build(); + + // user created fileSystemItem + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); + + // user created containing folder + fileSystemEntity.setCreatedByUserId(1203891230); + fileSystemEntity.setOwnerIds(new long[]{userId}); + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); + + // user got it shared. + fileSystemEntity = FileSystemEntity.builder().visibleForUserIds(new long[]{userId}).build(); + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); + + //user is in group + user = User.builder().userId(123897123).groups(new Group[]{Group.ADMIN}).build(); + fileSystemEntity = FileSystemEntity.builder().fileSystemId(9872347).visibleForGroupIds(new long[]{1}).build(); + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); + + // user is not allowed. + user = User.builder().userId(123).groups(new Group[]{Group.UNDEFINED}).build(); + fileSystemEntity = FileSystemEntity.builder().createdByUserId(321).visibleForGroupIds(new long[]{1}).build(); + assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); + } + + @Test + void userIsAllowedToEditFileSystemEntity() { + long userId = 1232783672; + User user = User.builder().userId(userId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().createdByUserId(userId).build(); + + // fileSystemEntity was created by runtime user. + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity.builder().createdByUserId(RestConfiguration.RUNTIME_USER_ID).editableForUserIds(new long[]{userId}).build(), user, CHANGE)); + + assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity.builder().createdByUserId(RestConfiguration.RUNTIME_USER_ID).editableForUserIds(new long[]{userId}).build(), user, DELETE)); + + // user created fileSystemItem + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); + + // user created containing folder + fileSystemEntity.setCreatedByUserId(1203891230); + fileSystemEntity.setOwnerIds(new long[]{userId}); + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); + + // user got it shared. + fileSystemEntity = FileSystemEntity.builder().editableForUserIds(new long[]{userId}).build(); + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); + + //user is in group + user = User.builder().userId(0).groups(new Group[]{Group.ADMIN}).build(); + fileSystemEntity = FileSystemEntity.builder().editableFoGroupIds(new long[]{1}).build(); + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); + + // user is not allowed. + user = User.builder().userId(123).groups(new Group[]{Group.UNDEFINED}).build(); + fileSystemEntity = FileSystemEntity.builder().createdByUserId(321).editableFoGroupIds(new long[]{1}).build(); + assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); + } + + @Test + void createDTOThrows() { + long userId = 420; + FileSystemEntity entity = FileSystemEntity.builder().createdByUserId(userId).build(); + User user = User.builder().build(); + + when(userBusinessServiceMock.getUserById(userId)).thenThrow(UserNotFoundException.class); + + FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> + fileSystemHelperService.createDTO(entity, user, null)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Owner of a file could not be found.", ex.getMessage()); + } + + @Test + void createDTOWorks() { + long createdByUserId = 420L; + String basePath = "/someTHING/somethingElse/"; + long[] items = new long[]{1, 2, 3}; + long fileSystemId = 123123; + boolean isFile = true; + long lastUpdated = 123123; + String name = "SomeText.txt"; + double size = 123321; + long typeId = -1; + + User authenticatedUser = User.builder().userId(createdByUserId - 1).build(); + User userThatCreatedFile = User.builder().userId(createdByUserId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity + .builder() + .createdByUserId(createdByUserId) + .itemIds(items) + .fileSystemId(fileSystemId) + .isFile(isFile) + .lastUpdated(lastUpdated) + .name(name) + .path("") // is empty because its a file. + .size(size) + .typeId(typeId) + .build(); + + when(userBusinessServiceMock.getUserById(createdByUserId)).thenReturn(userThatCreatedFile); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(typeId)).thenReturn(FileSystemType.UNDEFINED); + + FileSystemItem actual = fileSystemHelperService.createDTO(fileSystemEntity, authenticatedUser, basePath); + + assertEquals(createdByUserId, actual.getCreatedByUser().getUserId()); + assertEquals(fileSystemId, actual.getFileSystemId()); + assertEquals(lastUpdated, actual.getLastUpdated()); + assertEquals(name, actual.getName()); + assertEquals(size, actual.getSize()); + assertEquals(FileSystemType.UNDEFINED, actual.getType()); + assertEquals(basePath + name, actual.getPath()); + assertTrue(actual.isShared()); + } + + @Test + void getTotalFileSizeThrows() { + when(fileSystemRepositoryMock.findByPath("/")).thenReturn(null); + FileFighterDataException ex = assertThrows(FileFighterDataException.class, fileSystemHelperService::getTotalFileSize); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Couldn't find any Home directories!", ex.getMessage()); + } + + @Test + void getTotalFileSizeWorks() { + double size0 = 1.3; + double size1 = 2.4; + ArrayList entities = new ArrayList<>(); + entities.add(FileSystemEntity.builder().size(size0).build()); + entities.add(FileSystemEntity.builder().size(size1).build()); + + when(fileSystemRepositoryMock.findByPath("/")).thenReturn(entities); + + double actualSize = fileSystemHelperService.getTotalFileSize(); + assertEquals(size0 + size1, actualSize); + } +} + diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java index b6ac4584..238d07a9 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java @@ -72,15 +72,14 @@ void searchFileOrFolderByName() { @Test void uploadFileOrFolder() { FileSystemItem file = FileSystemItem.builder().build(); - ResponseEntity expectedModel = new ResponseEntity<>(file, OK); + FileSystemItemUpdate upload = FileSystemItemUpdate.builder().build(); + String token = "sometoken"; + ResponseEntity responseEntity = new ResponseEntity<>(file, OK); - FileSystemItemUpdate fileSystemItemUpdate = FileSystemItemUpdate.builder().name("ugabuga").build(); - String token = "token"; + when(fileSystemRestServiceMock.uploadFileSystemItemWithAccessToken(upload, token)).thenReturn(responseEntity); - when(fileSystemRestServiceMock.uploadFileSystemItemWithAccessToken(fileSystemItemUpdate, token)).thenReturn(expectedModel); - - ResponseEntity actualModel = fileSystemRestController.uploadFileOrFolder(fileSystemItemUpdate, token); - assertEquals(expectedModel, actualModel); + ResponseEntity actualModel = fileSystemRestController.uploadFileOrFolder(upload, token); + assertEquals(responseEntity, actualModel); } @Test @@ -92,7 +91,7 @@ void updateExistingFileOrFolder() { FileSystemItemUpdate fileSystemItemUpdate = FileSystemItemUpdate.builder().name("ugabuga").build(); String token = "token"; - when(fileSystemRestServiceMock.updatedFileSystemItemWithIdAndAccessToken(id, fileSystemItemUpdate, token)).thenReturn(expectedModel); + when(fileSystemRestServiceMock.updateFileSystemItemWithIdAndAccessToken(id, fileSystemItemUpdate, token)).thenReturn(expectedModel); ResponseEntity actualModel = fileSystemRestController.updateExistingFileOrFolder(id, fileSystemItemUpdate, token); assertEquals(expectedModel, actualModel); diff --git a/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java index 245fe093..a09e272f 100644 --- a/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java @@ -1,6 +1,6 @@ package de.filefighter.rest.domain.health.business; -import de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService; +import de.filefighter.rest.domain.filesystem.business.FileSystemHelperService; import de.filefighter.rest.domain.health.data.SystemHealth; import de.filefighter.rest.domain.health.data.SystemHealth.DataIntegrity; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; @@ -20,7 +20,7 @@ class SystemHealthBusinessServiceUnitTest { private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); private final AccessTokenBusinessService accessTokenBusinessServiceMock = mock(AccessTokenBusinessService.class); - private final FileSystemBusinessService fileSystemBusinessServiceMock = mock(FileSystemBusinessService.class); + private final FileSystemHelperService fileSystemBusinessServiceMock = mock(FileSystemHelperService.class); private final Environment environmentMock = mock(Environment.class); private SystemHealthBusinessService systemHealthBusinessService; From b992c1425e0e597a2cd51b0432601914ba662fde Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sat, 3 Apr 2021 09:55:50 +0200 Subject: [PATCH 03/20] start with delete FeatureFile --- .../resources/deleteFileSystemItems.feature | 90 ++++--------------- 1 file changed, 19 insertions(+), 71 deletions(-) diff --git a/src/test/resources/deleteFileSystemItems.feature b/src/test/resources/deleteFileSystemItems.feature index 99225531..f3d0fb51 100644 --- a/src/test/resources/deleteFileSystemItems.feature +++ b/src/test/resources/deleteFileSystemItems.feature @@ -3,68 +3,34 @@ Feature: FileSystem Delete Background: Given database is empty - And user 1234 exists - And user 420 exists + And user with userId 1234 exists and has username "Richard", password "badPassword" + And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" And accessToken with value "900000" exists for user 1234 - And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 420 has the path "/bla" and name "bla" + And accessToken with value "222222" exists for user 420 + And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 1234 has the path "/bla" and name "bla" + # todo add owner? (1234 in this case) + And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 1234 and has the name "wow.txt" And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 - And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 420 and has the name "wow.txt" Scenario: File Deletion - Given user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 72 - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "900000" wants to see the content of folder with path "/bla" + When user with token "900000" wants to see the content of folder with path "/Richard/bla" Then response status code is 200 And the response contains the file with fileSystemId 72 and name "wow.txt" When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 72 Then response status code is 200 - And response contains key "message" and value "Successfully deleted all requested FileSystemItems." - When user with token "900000" wants to see the content of folder with path "/bla" - And the response contains an empty list for files and folders + #And response contains key "message" and value "Successfully deleted all requested FileSystemItems." + When user with token "900000" wants to see the content of folder with path "/Richard/bla" + Then the response contains an empty list for files and folders And response status code is 200 Scenario: Folder and content Deletion - Given user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 42 - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - And user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 72 - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 Then response status code is 200 - When user with token "900000" wants to see the content of folder with path "/bla" + When user with token "900000" wants to see the content of folder with path "/Richard/bla" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." - Scenario: Folder and content Deletion with remaining content - Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - And user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 42 - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 - And user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 72 - And fileSystemItem with the fileSystemId 1080 exists, was created by user with userId 420 and has the name "IwillStay.txt" - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 1080 - And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 1080 - When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 - Then response status code is 200 - And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." - When user with token "900000" wants to see the content of folder with path "/bla" - And the response does not contains the file with fileSystemId 72 and name "wow.txt" - And the response contains the file with fileSystemId 1080 and name "IwillStay.txt" - - Scenario: Folder and content Deletion with remaining content (invisible) - And accessToken with value "2000000" exists for user 420 - Given user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 42 - Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 - Then response status code is 200 - # This sucks, because for the user everything got deleted. But the message doesnt say that because "NOT EVERYTHING GOT DELETED". - And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." - When user with token "900000" wants to see the content of folder with path "/bla" - Then response status code is 400 - And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." - When user with token "2000000" wants to see the content of folder with path "/bla" - Then response status code is 200 - And the response contains the file with fileSystemId 72 and name "wow.txt" - + # todo add owners Scenario: recursion Given fileSystemItem with the fileSystemId 0 exists, was created by user with userId 1234 has the path "/foo" and name "foo" And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 @@ -73,37 +39,17 @@ Feature: FileSystem Delete And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 1234 and has the name "git.exe" When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 0 Then response status code is 200 - And response contains key "message" and value "Successfully deleted all requested FileSystemItems." - When user with token "900000" wants to see the content of folder with path "/foo/bar" + When user with token "900000" wants to see the content of folder with path "/Richard/foo/bar" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." - When user with token "900000" wants to see the content of folder with path "/foo" + When user with token "900000" wants to see the content of folder with path "/Richard/foo" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." - Scenario: recursion with remaining file - Given fileSystemItem with the fileSystemId 0 exists, was created by user with userId 1234 has the path "/foo" and name "foo" - And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 - And fileSystemItem with the fileSystemId 1 exists, was created by user with userId 1234 has the path "/foo/bar" and name "bar" - And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 - And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 3 - And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 1234 and has the name "git.exe" - And fileSystemItem with the fileSystemId 3 exists, was created by user with userId 420 and has the name "subversion.exe" - And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 3 - When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 0 - Then response status code is 200 - And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." - When user with token "900000" wants to see the content of folder with path "/foo/bar" - Then response status code is 200 - And the response contains the file with fileSystemId 3 and name "subversion.exe" - When user with token "900000" wants to see the content of folder with path "/foo" - Then response status code is 200 - And the response contains the folder with fileSystemId 1 and name "bar" - And the response does not contains the file with fileSystemId 2 and name "git.exe" Scenario: insufficient authorization - Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 + Given user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "222222" wants to delete the fileSystemItem with the fileSystemId 42 Then response status code is 400 And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 42" @@ -119,6 +65,7 @@ Feature: FileSystem Delete Then response status code is 400 And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 42432567" + # todo Scenario: Folder was created by runtime user. Given database is empty # If this fails check the runtime user id. @@ -131,6 +78,7 @@ Feature: FileSystem Delete Then response status code is 400 And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 0" + # todo Scenario: File was created by runtime user. Given database is empty And user with userId 123123123 exists and has username "kevin", password "securePassword123" @@ -144,4 +92,4 @@ Feature: FileSystem Delete And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 0 and has the name "veryImportantDocumentDon'tDeleteMePls.exe" When user with token "token" wants to delete the fileSystemItem with the fileSystemId 0 Then response status code is 200 - And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." \ No newline at end of file + And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." From 6cad8c1ba351e3845e51f1e6f620e9ffc6ac7dfb Mon Sep 17 00:00:00 2001 From: open-schnick Date: Sat, 3 Apr 2021 10:54:21 +0200 Subject: [PATCH 04/20] Rewrote part of the logic, Implemented Ownerids, renamed to lastupdated. --- .../rest/configuration/PrepareDataBase.java | 60 +++++++------- .../business/FileSystemBusinessService.java | 81 ++++++++++++++----- .../business/FileSystemHelperService.java | 38 +++++---- .../filesystem/data/dto/FileSystemItem.java | 3 +- .../data/persistence/FileSystemEntity.java | 6 +- .../rest/cucumber/CommonCucumberSteps.java | 6 +- .../FileSystemBusinessServiceUnitTest.java | 38 ++++----- .../FileSystemHelperServiceUnitTest.java | 26 +++--- 8 files changed, 156 insertions(+), 102 deletions(-) diff --git a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java index 0866847e..dd193ec6 100644 --- a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java +++ b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java @@ -70,12 +70,6 @@ CommandLineRunner veryImportantFileFighterStartScript(Environment environment) { System.out.println(); System.out.println("-------------------------------< REST API >-------------------------------"); System.out.println(); - - /* - System.out.println("╭---╮") - System.out.println("| |") - System.out.println("╰---╯") - */ }; } @@ -91,26 +85,28 @@ CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepo addDefaultAdminAndRuntimeUser(userRepository); log.info("Inserting Home directories and default structure: {} {}.", fileSystemRepository.save(FileSystemEntity .builder() - .createdByUserId(RUNTIME_USER_ID) + .lastUpdatedBy(RUNTIME_USER_ID) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1) .fileSystemId(0) .isFile(false) .path("/") .itemIds(new long[0]) - .lastUpdated(Instant.now().getEpochSecond()) - .name("HOME_Admin") + .name("HOME_1") .size(420) .typeId(FOLDER.getId()) .visibleForGroupIds(new long[]{UNDEFINED.getGroupId(), FAMILY.getGroupId(), ADMIN.getGroupId()}) .itemIds(new long[]{1}) .build()), fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(1) - .fileSystemId(1) - .isFile(true) + .lastUpdatedBy(RUNTIME_USER_ID) .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1).fileSystemId(1) + .isFile(true) .name("dummyFile.txt") .size(420) .typeId(TEXT.getId()) + .mimeType("text/plain") .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) .build())); @@ -243,7 +239,6 @@ CommandLineRunner initDataBaseStage(UserRepository userRepository, FileSystemRep }; } - // TODO: fix owner ids. private void addDefaultAdminAndRuntimeUser(UserRepository userRepository) { log.info("Database seems to be empty. Creating new default entities..."); log.info("Inserting system runtime user: {}", userRepository.save(UserEntity @@ -269,26 +264,28 @@ private void addDefaultAdminAndRuntimeUser(UserRepository userRepository) { private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository) { log.info("Inserting default fsItems:\n {}\n {}\n {}\n {}\n {}\n {}.", fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(RUNTIME_USER_ID) + .lastUpdatedBy(RUNTIME_USER_ID) + .ownerId(1) + .lastUpdated(Instant.now().getEpochSecond()) .fileSystemId(0) .isFile(false) .path("/") - .itemIds(new long[]{2, 3}) - .lastUpdated(Instant.now().getEpochSecond()) - .name("HOME_User") + .name("HOME_1") .size(4866) .typeId(FOLDER.getId()) + .itemIds(new long[]{2, 3}) .visibleForGroupIds(new long[]{FAMILY.getGroupId(), ADMIN.getGroupId()}) .visibleForUserIds(new long[]{0}) .editableForUserIds(new long[]{0}) .build()), fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(RUNTIME_USER_ID) + .lastUpdatedBy(RUNTIME_USER_ID) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(2) .fileSystemId(1) .isFile(false) .path("/") - .lastUpdated(Instant.now().getEpochSecond()) - .name("HOME_User1") + .name("HOME_2") .size(0) .typeId(FOLDER.getId()) .visibleForGroupIds(new long[]{UNDEFINED.getGroupId(), FAMILY.getGroupId(), ADMIN.getGroupId()}) @@ -296,23 +293,26 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .editableForUserIds(new long[]{1}) .build()), fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(1) + .lastUpdatedBy(1) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1) .fileSystemId(2) .isFile(true) - .lastUpdated(Instant.now().getEpochSecond()) .name("dummyFile.txt") .size(420) .typeId(TEXT.getId()) + .mimeType("text/plain") .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) .build()), fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(1) + .lastUpdatedBy(1) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1) .fileSystemId(3) .isFile(false) .path("/somefolder") .name("SomeFolder") - .lastUpdated(Instant.now().getEpochSecond()) .size(4446) .typeId(FOLDER.getId()) .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) @@ -320,24 +320,28 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .itemIds(new long[]{4, 5}) .build()), fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(1) + .lastUpdatedBy(1) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1) .fileSystemId(4) .isFile(true) - .lastUpdated(Instant.now().getEpochSecond()) .name("secretFileInSomeFolder.txt") .size(3214) .typeId(TEXT.getId()) + .mimeType("text/plain") .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) .build()), fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(1) + .lastUpdatedBy(1) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1) .fileSystemId(5) .isFile(true) - .lastUpdated(Instant.now().getEpochSecond()) .name("definitelyNotPorn.mp4") .size(1232) .typeId(VIDEO.getId()) + .mimeType("video/mp4") .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) .build()) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 4bb4983b..8b9193cc 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -1,6 +1,5 @@ package de.filefighter.rest.domain.filesystem.business; -import de.filefighter.rest.domain.common.InputSanitizerService; import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; import de.filefighter.rest.domain.filesystem.data.InteractionType; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; @@ -11,7 +10,9 @@ import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemNotFoundException; import de.filefighter.rest.domain.filesystem.type.FileSystemType; import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; +import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; +import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import lombok.extern.log4j.Log4j2; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; @@ -31,30 +32,52 @@ public class FileSystemBusinessService { private final FileSystemRepository fileSystemRepository; private final FileSystemHelperService fileSystemHelperService; private final FileSystemTypeRepository fileSystemTypeRepository; + private final UserBusinessService userBusinessService; private final MongoTemplate mongoTemplate; private static final String DELETION_FAILED_MSG = "Failed to delete FileSystemEntity with id "; - public FileSystemBusinessService(FileSystemRepository fileSystemRepository, FileSystemHelperService fileSystemHelperService, FileSystemTypeRepository fileSystemTypeRepository, MongoTemplate mongoTemplate) { + public FileSystemBusinessService(FileSystemRepository fileSystemRepository, FileSystemHelperService fileSystemHelperService, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService, MongoTemplate mongoTemplate) { this.fileSystemRepository = fileSystemRepository; this.fileSystemHelperService = fileSystemHelperService; this.fileSystemTypeRepository = fileSystemTypeRepository; + this.userBusinessService = userBusinessService; this.mongoTemplate = mongoTemplate; } public List getFolderContentsByPath(String path, User authenticatedUser) { - if (!InputSanitizerService.stringIsValid(path)) - throw new FileSystemContentsNotAccessibleException("Path was not valid."); - String[] pathWithoutSlashes = path.split("/"); - if (!path.equals("/") && pathWithoutSlashes.length < 2) - throw new FileSystemContentsNotAccessibleException("Path was in wrong format."); + String pathToFind; + User ownerOfRequestedFolder = null; + + if (path.equals("/")) { + pathToFind = "/"; + } else { + if (pathWithoutSlashes.length < 2) + throw new FileSystemContentsNotAccessibleException("Path was in wrong format."); + + if (!"".equals(pathWithoutSlashes[0])) + throw new FileSystemContentsNotAccessibleException("Path was in wrong format. Use a leading backslash."); - if (!path.equals("/") && !"".equals(pathWithoutSlashes[0])) - throw new FileSystemContentsNotAccessibleException("Path was in wrong format. Use a leading backslash."); + // the first path must be the the username. + try { + ownerOfRequestedFolder = userBusinessService.findUserByUsername(pathWithoutSlashes[1]); + String[] fileSystemPath = path.split(ownerOfRequestedFolder.getUsername()); + if (fileSystemPath.length == 1) { + if (!fileSystemPath[0].equals("/")) + throw new FileSystemContentsNotAccessibleException(); - String pathToFind = fileSystemHelperService.removeTrailingBackSlashes(path).toLowerCase(); + pathToFind = "/"; + } else { + pathToFind = fileSystemPath[1]; + } + } catch (UserNotFoundException exception) { + throw new FileSystemContentsNotAccessibleException(); + } + } + + pathToFind = fileSystemHelperService.removeTrailingBackSlashes(pathToFind).toLowerCase(); // find the folder with matching path. ArrayList listOfFileSystemEntities = fileSystemRepository.findByPath(pathToFind); @@ -62,23 +85,39 @@ public List getFolderContentsByPath(String path, User authentica throw new FileSystemContentsNotAccessibleException(); // remove all not accessible items. - listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || !fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(entity, authenticatedUser, InteractionType.READ)); + // this is only the case if the real / was requested. -> filter by visibility + if (null == ownerOfRequestedFolder) { + listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || !fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(entity, authenticatedUser, InteractionType.READ)); + // do not get the actual contents here but display the folder names as a fake directory. + + ArrayList fileSystemItems = new ArrayList<>(); + for (FileSystemEntity folder : listOfFileSystemEntities) { + // change names here accordingly. + fileSystemItems.add(fileSystemHelperService.createDTO(folder, authenticatedUser, "/")); + } - if (listOfFileSystemEntities.isEmpty()) - throw new FileSystemContentsNotAccessibleException(); + return fileSystemItems; + } else { + User finalOwnerOfRequestedFolder = ownerOfRequestedFolder; + listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || entity.getOwnerId() != finalOwnerOfRequestedFolder.getUserId()); - // now only own or shared folders are left. - ArrayList fileSystemItems = new ArrayList<>(); - String pathWithTrailingSlash = pathToFind.equals("/") ? pathToFind : (pathToFind + "/"); //NOSONAR + if (listOfFileSystemEntities.isEmpty()) + throw new FileSystemContentsNotAccessibleException(); + + // now one Folder should remain + if (listOfFileSystemEntities.size() != 1) + throw new FileFighterDataException("Found more than one folder with the path " + pathToFind); + + ArrayList fileSystemItems = new ArrayList<>(); + ArrayList folderContents = + (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfFileSystemEntities.get(0), authenticatedUser, false, false); - // Well this is just O(n * m) - for (FileSystemEntity folder : listOfFileSystemEntities) { - ArrayList folderContents = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(folder, authenticatedUser, true, false); for (FileSystemEntity fileSystemEntityInFolder : folderContents) { - fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, pathWithTrailingSlash)); + fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, "/" + ownerOfRequestedFolder.getUsername() + pathToFind)); } + + return fileSystemItems; } - return fileSystemItems; } public FileSystemItem getFileSystemItemInfo(long fsItemId, User authenticatedUser) { diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java index a72aa77e..84978e11 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -95,15 +95,11 @@ public List getFolderContentsOfEntityAndPermissions(FileSystem public boolean userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity fileSystemEntity, User authenticatedUser, InteractionType interaction) { // file was created by runtime user. if ((interaction == InteractionType.DELETE) - && fileSystemEntity.getCreatedByUserId() == RestConfiguration.RUNTIME_USER_ID) + && fileSystemEntity.getLastUpdatedBy() == RestConfiguration.RUNTIME_USER_ID) return false; // user created the item - if (fileSystemEntity.getCreatedByUserId() == authenticatedUser.getUserId()) - return true; - - // user created containing folder. - if (null != fileSystemEntity.getOwnerIds() && Arrays.stream(fileSystemEntity.getOwnerIds()).asDoubleStream().anyMatch(id -> id == authenticatedUser.getUserId())) + if (fileSystemEntity.getLastUpdatedBy() == authenticatedUser.getUserId()) return true; // user got the item shared. @@ -152,27 +148,41 @@ public String removeTrailingBackSlashes(String pathToFind) { return pathToFind; } - public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenticatedUser, String basePath) { + public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenticatedUser, String absolutePathWithUsername) { // for better responses and internal problem handling. User ownerOfFileSystemItem; + User lastUpdatedByUser; try { - ownerOfFileSystemItem = userBusinessService.getUserById(fileSystemEntity.getCreatedByUserId()); + ownerOfFileSystemItem = userBusinessService.getUserById(fileSystemEntity.getOwnerId()); + lastUpdatedByUser = userBusinessService.getUserById(fileSystemEntity.getLastUpdatedBy()); } catch (UserNotFoundException exception) { - throw new FileFighterDataException("Owner of a file could not be found."); + throw new FileFighterDataException("Owner or auther of last change could not be found. Entity: " + fileSystemEntity); } - boolean isShared = ownerOfFileSystemItem.getUserId() != authenticatedUser.getUserId(); + boolean isShared = ownerOfFileSystemItem.getUserId() != RestConfiguration.RUNTIME_USER_ID + && ownerOfFileSystemItem.getUserId() != authenticatedUser.getUserId(); FileSystemType type = fileSystemTypeRepository.findFileSystemTypeById(fileSystemEntity.getTypeId()); boolean isAFolder = type == FileSystemType.FOLDER && !fileSystemEntity.isFile(); + String entityName = fileSystemEntity.getName(); + + if (absolutePathWithUsername != null) { + if (absolutePathWithUsername.equals("/")) { + absolutePathWithUsername = absolutePathWithUsername + ownerOfFileSystemItem.getUsername(); // this is only for the case of the path = "/" + entityName = ownerOfFileSystemItem.getUsername(); + } else { + absolutePathWithUsername = this.removeTrailingBackSlashes(absolutePathWithUsername) + "/" + fileSystemEntity.getName(); + } + } return FileSystemItem.builder() - .createdByUser(ownerOfFileSystemItem) + .lastUpdatedBy(lastUpdatedByUser) .fileSystemId(fileSystemEntity.getFileSystemId()) + .owner(ownerOfFileSystemItem) .lastUpdated(fileSystemEntity.getLastUpdated()) - .name(fileSystemEntity.getName()) + .name(entityName) .size(fileSystemEntity.getSize()) .type(isAFolder ? FileSystemType.FOLDER : type) - .path(null == basePath ? null : basePath + fileSystemEntity.getName()) + .path(absolutePathWithUsername) .isShared(isShared) .mimeType(fileSystemEntity.getMimeType()) .build(); @@ -181,7 +191,7 @@ public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenti public void createBasicFilesForNewUser(UserEntity registeredUserEntity) { fileSystemRepository.save(FileSystemEntity .builder() - .createdByUserId(0) + .lastUpdatedBy(0) .typeId(FileSystemType.FOLDER.getId()) .isFile(false) .name("HOME_" + registeredUserEntity.getUsername()) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java index 9bafb56a..df151489 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FileSystemItem.java @@ -15,7 +15,8 @@ public class FileSystemItem { private String name; private boolean isShared; private double size; - private User createdByUser; //uploadedBy + private User owner; + private User lastUpdatedBy; private long lastUpdated; private FileSystemType type; private String mimeType; diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java index 9a1d039d..ca143f6f 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemEntity.java @@ -22,11 +22,11 @@ public class FileSystemEntity { private double size; private long lastUpdated; @Builder.Default - private boolean isFile = true; + private long lastUpdatedBy = -1; @Builder.Default - private long createdByUserId = -1; + private boolean isFile = true; @Builder.Default - private long[] ownerIds = new long[0]; + private long ownerId = -1; @Builder.Default private long[] visibleForGroupIds = new long[0]; @Builder.Default diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index d0dca520..66141866 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -93,7 +93,7 @@ public void userWithIdIsInGroupWithId(long userId, long groupId) { public void fileSystemItemWithTheFileSystemIdExistsAndHasThePath(long fileSystemId, long userId, String path, String name) { fileSystemRepository.save(FileSystemEntity.builder() .path(path) - .createdByUserId(userId) + .lastUpdatedBy(userId) .fileSystemId(fileSystemId) .name(name) .build()); @@ -103,7 +103,7 @@ public void fileSystemItemWithTheFileSystemIdExistsAndHasThePath(long fileSystem public void fileSystemItemWithTheFileSystemIdExistsAndHasTheName(long fileSystemId, long userId, String name) { fileSystemRepository.save(FileSystemEntity.builder() .name(name) - .createdByUserId(userId) + .lastUpdatedBy(userId) .fileSystemId(fileSystemId) .build()); } @@ -133,7 +133,7 @@ public void fileSystemItemWithTheFileSystemIdIsAFolder(long fileSystemId) { public void userIsOwnerOfFileOrFolderWithId(long userId, long fsItemId) { FileSystemEntity fileSystemEntity = fileSystemRepository.findByFileSystemId(fsItemId); - fileSystemEntity.setCreatedByUserId(userId); + fileSystemEntity.setLastUpdatedBy(userId); fileSystemRepository.save(fileSystemEntity); } diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index 7f598582..dbe06d0f 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -31,7 +31,9 @@ class FileSystemBusinessServiceUnitTest { private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); private final FileSystemHelperService fileSystemHelperServiceMock = mock(FileSystemHelperService.class); - private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, mongoTemplateMock); + private final UserBusinessService userBusinessService = mock(UserBusinessService.class); + + private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, userBusinessService, mongoTemplateMock); @Test void getFolderContentsByPathThrows() { @@ -64,7 +66,7 @@ void getFolderContentsByPathThrows() { ArrayList fileSystemEntityArrayList = new ArrayList<>(); fileSystemEntityArrayList.add(FileSystemEntity.builder().isFile(true).build()); fileSystemEntityArrayList.add(FileSystemEntity.builder().isFile(false).typeId(-1).build()); - fileSystemEntityArrayList.add(FileSystemEntity.builder().createdByUserId(420).build()); + fileSystemEntityArrayList.add(FileSystemEntity.builder().lastUpdatedBy(420).build()); when(fileSystemRepositoryMock.findByPath(validPath)).thenReturn(fileSystemEntityArrayList); @@ -80,7 +82,7 @@ void getFolderContentsByPathWorks() { long userId = 420; long fileIdInFolder = 123; User user = User.builder().userId(userId).build(); - FileSystemEntity foundFolder = FileSystemEntity.builder().isFile(false).createdByUserId(userId).typeId(0).itemIds(new long[]{fileIdInFolder}).build(); + FileSystemEntity foundFolder = FileSystemEntity.builder().isFile(false).lastUpdatedBy(userId).typeId(0).itemIds(new long[]{fileIdInFolder}).build(); ArrayList entities = new ArrayList<>(); entities.add(foundFolder); @@ -89,7 +91,7 @@ void getFolderContentsByPathWorks() { when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundFolder, user, true, false)).thenReturn(entities); when(fileSystemHelperServiceMock.createDTO(foundFolder, user, pathToRequest)).thenReturn(FileSystemItem.builder().build()); when(fileSystemRepositoryMock.findByPath(path)).thenReturn(entities); - when(fileSystemRepositoryMock.findByFileSystemId(fileIdInFolder)).thenReturn(FileSystemEntity.builder().createdByUserId(userId).build()); + when(fileSystemRepositoryMock.findByFileSystemId(fileIdInFolder)).thenReturn(FileSystemEntity.builder().lastUpdatedBy(userId).build()); when(userBusinessServiceMock.getUserById(userId)).thenReturn(User.builder().build()); ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(pathToRequest, user); @@ -152,7 +154,7 @@ void deleteFileSystemItemByIdThrows() { fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + fsItemId, ex.getMessage()); - foundEntity = FileSystemEntity.builder().createdByUserId(userId).isFile(true).typeId(0).build(); + foundEntity = FileSystemEntity.builder().lastUpdatedBy(userId).isFile(true).typeId(0).build(); when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ))).thenReturn(true); when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE))).thenReturn(true); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); @@ -162,11 +164,11 @@ void deleteFileSystemItemByIdThrows() { assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FileType was wrong. " + foundEntity, ex1.getMessage()); long folderContentId = 13287132; - FileSystemEntity folderContentEntity = FileSystemEntity.builder().createdByUserId(userId).isFile(true).typeId(0).build(); + FileSystemEntity folderContentEntity = FileSystemEntity.builder().lastUpdatedBy(userId).isFile(true).typeId(0).build(); ArrayList fileSystemEntitiesMock = new ArrayList<>(); fileSystemEntitiesMock.add(folderContentEntity); when(fileSystemRepositoryMock.findByFileSystemId(folderContentId)).thenReturn(folderContentEntity); - foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).createdByUserId(userId).itemIds(new long[]{folderContentId}).build(); + foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).lastUpdatedBy(userId).itemIds(new long[]{folderContentId}).build(); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); @@ -181,7 +183,7 @@ void deleteFileSystemItemByIdWorksWithFile() { long fsItemId = 12332123; long userId = 243724328; User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity foundEntity = FileSystemEntity.builder().fileSystemId(fsItemId).typeId(1).isFile(true).createdByUserId(userId).build(); + FileSystemEntity foundEntity = FileSystemEntity.builder().fileSystemId(fsItemId).typeId(1).isFile(true).lastUpdatedBy(userId).build(); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); @@ -197,7 +199,7 @@ void deleteFileSystemItemByIdWorksWithFolder() { long fileId = 420; long userId = 243724328; User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity folder = FileSystemEntity.builder().fileSystemId(folderId).typeId(0).isFile(false).createdByUserId(userId).build(); + FileSystemEntity folder = FileSystemEntity.builder().fileSystemId(folderId).typeId(0).isFile(false).lastUpdatedBy(userId).build(); when(fileSystemRepositoryMock.findByFileSystemId(folderId)).thenReturn(folder); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); @@ -205,7 +207,7 @@ void deleteFileSystemItemByIdWorksWithFolder() { when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.READ)).thenReturn(true); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - FileSystemEntity file = FileSystemEntity.builder().typeId(2).fileSystemId(fileId).isFile(true).createdByUserId(userId).itemIds(new long[0]).build(); + FileSystemEntity file = FileSystemEntity.builder().typeId(2).fileSystemId(fileId).isFile(true).lastUpdatedBy(userId).itemIds(new long[0]).build(); ArrayList foundFiles = new ArrayList<>(); foundFiles.add(file); when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(folder, authenticatedUser, false, false)).thenReturn(foundFiles); @@ -229,10 +231,10 @@ void deleteFileSystemItemByIdWorksWithFolderWhenAllItemsCanBeDeleted() { long itemId0 = 1233212; long itemId1 = 9872317; long itemId2 = 1923847; - FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().isFile(false).typeId(0).createdByUserId(userId).fileSystemId(itemId0).build(); - FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().fileSystemId(itemId1).typeId(1).createdByUserId(userId).isFile(true).build(); - FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().fileSystemId(itemId2).typeId(1).createdByUserId(userId).isFile(true).build(); - FileSystemEntity parentFolder = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).createdByUserId(userId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); + FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().isFile(false).typeId(0).lastUpdatedBy(userId).fileSystemId(itemId0).build(); + FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().fileSystemId(itemId1).typeId(1).lastUpdatedBy(userId).isFile(true).build(); + FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().fileSystemId(itemId2).typeId(1).lastUpdatedBy(userId).isFile(true).build(); + FileSystemEntity parentFolder = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).lastUpdatedBy(userId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(parentFolder); @@ -276,11 +278,11 @@ void deleteFileSystemItemByIdWorksWithFolderWhenSomeItemsCannotBeDeleted() { long itemId2 = 1923847; long itemId3 = 9817232; User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity foundFolder = FileSystemEntity.builder().typeId(0).isFile(false).createdByUserId(userId).itemIds(new long[]{itemId0, itemId1, itemId2, itemId3}).build(); - FileSystemEntity visibleEditableEmptyFolder = FileSystemEntity.builder().isFile(false).typeId(0).createdByUserId(userId).fileSystemId(itemId0).build(); + FileSystemEntity foundFolder = FileSystemEntity.builder().typeId(0).isFile(false).lastUpdatedBy(userId).itemIds(new long[]{itemId0, itemId1, itemId2, itemId3}).build(); + FileSystemEntity visibleEditableEmptyFolder = FileSystemEntity.builder().isFile(false).typeId(0).lastUpdatedBy(userId).fileSystemId(itemId0).build(); FileSystemEntity invisibleFile = FileSystemEntity.builder().fileSystemId(itemId1).isFile(true).build(); FileSystemEntity visibleNonEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).visibleForUserIds(new long[]{userId}).isFile(true).build(); - FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId3).createdByUserId(userId).isFile(true).build(); + FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId3).lastUpdatedBy(userId).isFile(true).build(); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundFolder); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); @@ -387,7 +389,7 @@ void getFileSystemItemInfoWorks() { long userId = 1234321; String name = "Folder"; User dummyUser = User.builder().userId(userId).build(); - FileSystemEntity entity = FileSystemEntity.builder().name(name).createdByUserId(userId).build(); + FileSystemEntity entity = FileSystemEntity.builder().name(name).lastUpdatedBy(userId).build(); FileSystemItem item = FileSystemItem.builder().build(); when(userBusinessServiceMock.getUserById(userId)).thenReturn(dummyUser); diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java index 44eab450..84c877d7 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -77,7 +77,7 @@ void getFolderContentsOfEntityWorks() { FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().visibleForUserIds(new long[]{userId}).build(); FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().editableForUserIds(new long[]{userId}).build(); - FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().createdByUserId(userId).build(); + FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().lastUpdatedBy(userId).build(); FileSystemEntity rootFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId0, fileSystemId1, fileSystemId2}).build(); @@ -124,14 +124,13 @@ void removeTrailingWhiteSpaces() { void userIsAllowedToReadFileSystemEntity() { long userId = 1232783672; User user = User.builder().userId(userId).build(); - FileSystemEntity fileSystemEntity = FileSystemEntity.builder().createdByUserId(userId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().lastUpdatedBy(userId).build(); // user created fileSystemItem assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); // user created containing folder - fileSystemEntity.setCreatedByUserId(1203891230); - fileSystemEntity.setOwnerIds(new long[]{userId}); + fileSystemEntity.setLastUpdatedBy(1203891230); assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); // user got it shared. @@ -145,7 +144,7 @@ void userIsAllowedToReadFileSystemEntity() { // user is not allowed. user = User.builder().userId(123).groups(new Group[]{Group.UNDEFINED}).build(); - fileSystemEntity = FileSystemEntity.builder().createdByUserId(321).visibleForGroupIds(new long[]{1}).build(); + fileSystemEntity = FileSystemEntity.builder().lastUpdatedBy(321).visibleForGroupIds(new long[]{1}).build(); assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); } @@ -153,19 +152,18 @@ void userIsAllowedToReadFileSystemEntity() { void userIsAllowedToEditFileSystemEntity() { long userId = 1232783672; User user = User.builder().userId(userId).build(); - FileSystemEntity fileSystemEntity = FileSystemEntity.builder().createdByUserId(userId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().lastUpdatedBy(userId).build(); // fileSystemEntity was created by runtime user. - assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity.builder().createdByUserId(RestConfiguration.RUNTIME_USER_ID).editableForUserIds(new long[]{userId}).build(), user, CHANGE)); + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity.builder().lastUpdatedBy(RestConfiguration.RUNTIME_USER_ID).editableForUserIds(new long[]{userId}).build(), user, CHANGE)); - assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity.builder().createdByUserId(RestConfiguration.RUNTIME_USER_ID).editableForUserIds(new long[]{userId}).build(), user, DELETE)); + assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity.builder().lastUpdatedBy(RestConfiguration.RUNTIME_USER_ID).editableForUserIds(new long[]{userId}).build(), user, DELETE)); // user created fileSystemItem assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); // user created containing folder - fileSystemEntity.setCreatedByUserId(1203891230); - fileSystemEntity.setOwnerIds(new long[]{userId}); + fileSystemEntity.setLastUpdatedBy(1203891230); assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); // user got it shared. @@ -179,14 +177,14 @@ void userIsAllowedToEditFileSystemEntity() { // user is not allowed. user = User.builder().userId(123).groups(new Group[]{Group.UNDEFINED}).build(); - fileSystemEntity = FileSystemEntity.builder().createdByUserId(321).editableFoGroupIds(new long[]{1}).build(); + fileSystemEntity = FileSystemEntity.builder().lastUpdatedBy(321).editableFoGroupIds(new long[]{1}).build(); assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); } @Test void createDTOThrows() { long userId = 420; - FileSystemEntity entity = FileSystemEntity.builder().createdByUserId(userId).build(); + FileSystemEntity entity = FileSystemEntity.builder().lastUpdatedBy(userId).build(); User user = User.builder().build(); when(userBusinessServiceMock.getUserById(userId)).thenThrow(UserNotFoundException.class); @@ -212,7 +210,7 @@ void createDTOWorks() { User userThatCreatedFile = User.builder().userId(createdByUserId).build(); FileSystemEntity fileSystemEntity = FileSystemEntity .builder() - .createdByUserId(createdByUserId) + .lastUpdatedBy(createdByUserId) .itemIds(items) .fileSystemId(fileSystemId) .isFile(isFile) @@ -228,7 +226,7 @@ void createDTOWorks() { FileSystemItem actual = fileSystemHelperService.createDTO(fileSystemEntity, authenticatedUser, basePath); - assertEquals(createdByUserId, actual.getCreatedByUser().getUserId()); + assertEquals(createdByUserId, actual.getLastUpdatedBy().getUserId()); assertEquals(fileSystemId, actual.getFileSystemId()); assertEquals(lastUpdated, actual.getLastUpdated()); assertEquals(name, actual.getName()); From eed930e9e391779b0ffd792947b7d941557fcfe5 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sat, 3 Apr 2021 13:36:06 +0200 Subject: [PATCH 05/20] adapt feature files to refactoring --- .../rest/cucumber/CommonCucumberSteps.java | 34 ++++++++++++++++++- .../cucumber/ViewFolderContentsSteps.java | 17 ++++++++++ src/test/resources/ViewFolderContents.feature | 11 ++++-- 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index 66141866..bdc1822d 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -98,6 +98,16 @@ public void fileSystemItemWithTheFileSystemIdExistsAndHasThePath(long fileSystem .name(name) .build()); } + @And("fileSystemItem with the fileSystemId {long} exists, has owner with userId {long} has the path {string} and name {string}") + public void filesystemitemWithTheFileSystemIdExistsHasOwnerWithUserIdHasThePathStringAndNameString(long fileSystemId, long ownerId, String path, String name) { + fileSystemRepository.save(FileSystemEntity.builder() + .path(path) + .lastUpdatedBy(ownerId) + .ownerId(ownerId) + .fileSystemId(fileSystemId) + .name(name) + .build()); + } @And("fileSystemItem with the fileSystemId {long} exists, was created by user with userId {long} and has the name {string}") public void fileSystemItemWithTheFileSystemIdExistsAndHasTheName(long fileSystemId, long userId, String name) { @@ -108,6 +118,16 @@ public void fileSystemItemWithTheFileSystemIdExistsAndHasTheName(long fileSystem .build()); } + @And("fileSystemItem with the fileSystemId {long} exists, has owner with userId {int} and name {string}") + public void filesystemitemWithTheFileSystemIdExistsHasOwnerWithUserIdAndName(long fileSystemId, long ownerId, String name) { + fileSystemRepository.save(FileSystemEntity.builder() + .name(name) + .lastUpdatedBy(ownerId) + .ownerId(ownerId) + .fileSystemId(fileSystemId) + .build()); + } + @And("fileSystemItem with the fileSystemId {long} is a folder and contains the fileSystemId {long}") public void fileSystemItemWithTheFileSystemIdIsAFolderAndContainsTheFileSystemId(long fileSystemIdFolder, long fileSystemId) { Query query = new Query(); @@ -174,5 +194,17 @@ public void responseContainsKeyAndADifferentValueThan(String key, String differe assertNotEquals(differentValue, actualValue); } - + @And("user with userId {long} has HomeFolder with Id {long}") + public void userWithUserIdHasHomeFolderWithId(long userId, long folderId) { + fileSystemRepository.save(FileSystemEntity.builder() + .name("HOME_" + userId) + .lastUpdatedBy(0) + .ownerId(userId) + .fileSystemId(folderId) + .path("/") + .typeId(0) + .isFile(false) + .editableForUserIds(new long[]{userId}) + .build()); + } } diff --git a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java index a08c48f3..8119da7d 100644 --- a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java @@ -110,4 +110,21 @@ public void theResponseContainsTheFolderWithFileSystemIdAndName(long fileSystemI } Assertions.assertTrue(found); } + + @And("the response contains the folder with name {string}") + public void theResponseContainsTheFolderWithName(String name) throws JsonProcessingException { + ArrayNode rootNode = (ArrayNode) objectMapper.readTree(latestResponse.getBody()); + if (!rootNode.isContainerNode() || rootNode.isEmpty()) + throw new AssertionError("Response was not an Array or empty."); + + boolean found = false; + for (JsonNode node : rootNode) { + if (node.get("name").asText().equals(name) && + node.get("type").asText().equals("FOLDER")) + found = true; + } + Assertions.assertTrue(found); + } + + } diff --git a/src/test/resources/ViewFolderContents.feature b/src/test/resources/ViewFolderContents.feature index d97ce605..f4001043 100644 --- a/src/test/resources/ViewFolderContents.feature +++ b/src/test/resources/ViewFolderContents.feature @@ -2,16 +2,20 @@ Feature: View Folder As a user I want to see the content of folders and navigate in them, so they can see and interact with their uploaded and shared files. + # the user exist step should also create the + Background: Given database is empty And user with userId 1234 exists and has username "Richard", password "badPassword" And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" And accessToken with value "900000" exists for user 1234 And accessToken with value "222222" exists for user 420 - And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 1234 has the path "/bla" and name "bla" + And user with userId 1234 has HomeFolder with Id 1234 + And user with userId 420 has HomeFolder with Id 420 + And fileSystemItem with the fileSystemId 42 exists, has owner with userId 1234 has the path "/bla" and name "bla" # should the path contain the user id ? like: "/420/bla" Then the fe requests /Gimleux/bla and you can easily look it up in the database # then created by user would be useless and it should be replaced with 'last modified by' (basically it is the same) - And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 1234 and has the name "wow.txt" + And fileSystemItem with the fileSystemId 72 exists, has owner with userId 1234 and name "wow.txt" And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 Scenario: Successful interaction @@ -30,6 +34,7 @@ Feature: View Folder Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + # failing !! Scenario: insufficient authorization When user with token "222222" wants to see the content of folder with path "/Richard/bla" Then response status code is 400 @@ -43,7 +48,7 @@ Feature: View Folder And the response contains the file with fileSystemId 72 and name "wow.txt" Scenario: empty directory - Given fileSystemItem with the fileSystemId 44 exists, was created by user with userId 1234 has the path "/empty" and name "empty" + Given fileSystemItem with the fileSystemId 44 exists, has owner with userId 1234 has the path "/empty" and name "empty" And fileSystemItem with the fileSystemId 44 is a folder When user with token "900000" wants to see the content of folder with path "/Richard/empty" Then response status code is 200 From 38e01485af18cd9f0585fd2404c9bb8d8d191b76 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Sun, 4 Apr 2021 11:19:37 +0200 Subject: [PATCH 06/20] minor changes. --- .../business/FileSystemBusinessService.java | 2 +- .../business/FileSystemHelperService.java | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 8b9193cc..d7e055b1 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -159,7 +159,7 @@ public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSyst if (countDeleted != 1) // TODO: check this number again. throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); - // update. + // unbind the deleted file. Query query = new Query().addCriteria(Criteria.where("itemIds").is(parentFileSystemEntity.getFileSystemId())); Update newUpdate = new Update().pull("itemIds", parentFileSystemEntity.getFileSystemId()); mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java index 84978e11..86f2f8b0 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -98,8 +98,8 @@ public boolean userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity file && fileSystemEntity.getLastUpdatedBy() == RestConfiguration.RUNTIME_USER_ID) return false; - // user created the item - if (fileSystemEntity.getLastUpdatedBy() == authenticatedUser.getUserId()) + // user own the file. + if (fileSystemEntity.getOwnerId() == authenticatedUser.getUserId()) return true; // user got the item shared. @@ -191,13 +191,17 @@ public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenti public void createBasicFilesForNewUser(UserEntity registeredUserEntity) { fileSystemRepository.save(FileSystemEntity .builder() - .lastUpdatedBy(0) + .fileSystemId(generateNextFileSystemId()) + .ownerId(registeredUserEntity.getUserId()) + .lastUpdatedBy(RestConfiguration.RUNTIME_USER_ID) + .lastUpdated(getCurrentTimeStamp()) .typeId(FileSystemType.FOLDER.getId()) .isFile(false) - .name("HOME_" + registeredUserEntity.getUsername()) + .name("HOME_" + registeredUserEntity.getUserId()) .path("/") .lastUpdated(Instant.now().getEpochSecond()) - .fileSystemId(generateNextFileSystemId()) + .size(0) + .mimeType(null) .build()); } @@ -223,6 +227,6 @@ public long generateNextFileSystemId() { } public long getCurrentTimeStamp() { - return System.currentTimeMillis() / 1000; + return Instant.now().getEpochSecond(); } } From e5429762aeae02ca2eeae56076637eecf24c8132 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Sun, 4 Apr 2021 16:33:23 +0200 Subject: [PATCH 07/20] Fixed failing request. Happy Easter btw lol --- .../business/FileSystemBusinessService.java | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index d7e055b1..87c79297 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -80,18 +80,19 @@ public List getFolderContentsByPath(String path, User authentica pathToFind = fileSystemHelperService.removeTrailingBackSlashes(pathToFind).toLowerCase(); // find the folder with matching path. - ArrayList listOfFileSystemEntities = fileSystemRepository.findByPath(pathToFind); - if (null == listOfFileSystemEntities) // does return null and not a empty collection. + ArrayList listOfPossibleDirectories = fileSystemRepository.findByPath(pathToFind); + if (null == listOfPossibleDirectories) // does return null and not a empty collection. throw new FileSystemContentsNotAccessibleException(); // remove all not accessible items. // this is only the case if the real / was requested. -> filter by visibility - if (null == ownerOfRequestedFolder) { - listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || !fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(entity, authenticatedUser, InteractionType.READ)); - // do not get the actual contents here but display the folder names as a fake directory. + boolean actualRootWasRequested = null == ownerOfRequestedFolder; + if (actualRootWasRequested) { + listOfPossibleDirectories.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || !fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(entity, authenticatedUser, InteractionType.READ)); + // do not get the actual contents here but display the folder names as a fake directory. ArrayList fileSystemItems = new ArrayList<>(); - for (FileSystemEntity folder : listOfFileSystemEntities) { + for (FileSystemEntity folder : listOfPossibleDirectories) { // change names here accordingly. fileSystemItems.add(fileSystemHelperService.createDTO(folder, authenticatedUser, "/")); } @@ -99,18 +100,22 @@ public List getFolderContentsByPath(String path, User authentica return fileSystemItems; } else { User finalOwnerOfRequestedFolder = ownerOfRequestedFolder; - listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || entity.getOwnerId() != finalOwnerOfRequestedFolder.getUserId()); + listOfPossibleDirectories.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || entity.getOwnerId() != finalOwnerOfRequestedFolder.getUserId()); - if (listOfFileSystemEntities.isEmpty()) + if (listOfPossibleDirectories.isEmpty()) throw new FileSystemContentsNotAccessibleException(); // now one Folder should remain - if (listOfFileSystemEntities.size() != 1) + if (listOfPossibleDirectories.size() != 1) throw new FileFighterDataException("Found more than one folder with the path " + pathToFind); + // check if the autheticatedUser can access this. + if (!fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(listOfPossibleDirectories.get(0), authenticatedUser, InteractionType.READ)) + throw new FileSystemContentsNotAccessibleException(); + ArrayList fileSystemItems = new ArrayList<>(); ArrayList folderContents = - (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfFileSystemEntities.get(0), authenticatedUser, false, false); + (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfPossibleDirectories.get(0), authenticatedUser, false, false); for (FileSystemEntity fileSystemEntityInFolder : folderContents) { fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, "/" + ownerOfRequestedFolder.getUsername() + pathToFind)); From 1a25d83c59c8bf7f3a9ce2d9e52c5698a5057183 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Tue, 6 Apr 2021 11:36:17 +0200 Subject: [PATCH 08/20] minor fix of feature files --- src/test/resources/ViewFolderContents.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/resources/ViewFolderContents.feature b/src/test/resources/ViewFolderContents.feature index f4001043..c4758ad8 100644 --- a/src/test/resources/ViewFolderContents.feature +++ b/src/test/resources/ViewFolderContents.feature @@ -43,7 +43,7 @@ Feature: View Folder Scenario: shared folder (group) And user with userId 420 is in group with groupId 1 And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 42 - When user with token "222222" wants to see the content of folder with path "/bla" + When user with token "222222" wants to see the content of folder with path "/Richard/bla" Then response status code is 200 And the response contains the file with fileSystemId 72 and name "wow.txt" @@ -69,10 +69,10 @@ Feature: View Folder Scenario: nested shared folder - Given fileSystemItem with the fileSystemId 4 exists, was created by user with userId 1234 has the path "/pläne" and name "pläne" - And fileSystemItem with the fileSystemId 5 exists, was created by user with userId 1234 has the path "/pläne/städte" and name "städte" - And fileSystemItem with the fileSystemId 12 exists, was created by user with userId 1234 has the path "/pläne/städte/jerusalem" and name "jerusalem" - And fileSystemItem with the fileSystemId 13 exists, was created by user with userId 1234 and has the name "we_will_take.mp3" + Given fileSystemItem with the fileSystemId 4 exists, has owner with userId 1234 has the path "/pläne" and name "pläne" + And fileSystemItem with the fileSystemId 5 exists, has owner with userId 1234 has the path "/pläne/städte" and name "städte" + And fileSystemItem with the fileSystemId 12 exists, has owner with userId 1234 has the path "/pläne/städte/jerusalem" and name "jerusalem" + And fileSystemItem with the fileSystemId 13 exists, has owner with userId 1234 and name "we_will_take.mp3" And fileSystemItem with the fileSystemId 12 is a folder and contains the fileSystemId 13 And fileSystemItem with the fileSystemId 4 is a folder and contains the fileSystemId 5 And fileSystemItem with the fileSystemId 5 is a folder and contains the fileSystemId 12 From 3eace47fca8ca13ea8fbe9f1dad9e3571b6bb0f9 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Tue, 6 Apr 2021 11:54:49 +0200 Subject: [PATCH 09/20] Implemented getFolderContents with feature file. --- .../business/FileSystemBusinessService.java | 3 +- .../rest/cucumber/CommonCucumberSteps.java | 19 ++++++++++- src/test/resources/ViewFolderContents.feature | 33 ++++++++----------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 87c79297..994ac37f 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -45,6 +45,7 @@ public FileSystemBusinessService(FileSystemRepository fileSystemRepository, File this.mongoTemplate = mongoTemplate; } + @SuppressWarnings("java:S3776") public List getFolderContentsByPath(String path, User authenticatedUser) { String[] pathWithoutSlashes = path.split("/"); @@ -115,7 +116,7 @@ public List getFolderContentsByPath(String path, User authentica ArrayList fileSystemItems = new ArrayList<>(); ArrayList folderContents = - (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfPossibleDirectories.get(0), authenticatedUser, false, false); + (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfPossibleDirectories.get(0), authenticatedUser, true, false); for (FileSystemEntity fileSystemEntityInFolder : folderContents) { fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, "/" + ownerOfRequestedFolder.getUsername() + pathToFind)); diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index bdc1822d..d9a22398 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -21,6 +21,8 @@ import java.io.IOException; +import static de.filefighter.rest.configuration.RestConfiguration.RUNTIME_USER_ID; +import static de.filefighter.rest.domain.user.group.Group.SYSTEM; import static org.junit.jupiter.api.Assertions.*; @Log4j2 @@ -98,6 +100,7 @@ public void fileSystemItemWithTheFileSystemIdExistsAndHasThePath(long fileSystem .name(name) .build()); } + @And("fileSystemItem with the fileSystemId {long} exists, has owner with userId {long} has the path {string} and name {string}") public void filesystemitemWithTheFileSystemIdExistsHasOwnerWithUserIdHasThePathStringAndNameString(long fileSystemId, long ownerId, String path, String name) { fileSystemRepository.save(FileSystemEntity.builder() @@ -194,11 +197,12 @@ public void responseContainsKeyAndADifferentValueThan(String key, String differe assertNotEquals(differentValue, actualValue); } + @And("user with userId {long} has HomeFolder with Id {long}") public void userWithUserIdHasHomeFolderWithId(long userId, long folderId) { fileSystemRepository.save(FileSystemEntity.builder() .name("HOME_" + userId) - .lastUpdatedBy(0) + .lastUpdatedBy(RUNTIME_USER_ID) .ownerId(userId) .fileSystemId(folderId) .path("/") @@ -207,4 +211,17 @@ public void userWithUserIdHasHomeFolderWithId(long userId, long folderId) { .editableForUserIds(new long[]{userId}) .build()); } + + @And("runtime user exists") + public void runtimeUserExists() { + userRepository.save(UserEntity + .builder() + .userId(RUNTIME_USER_ID) + .username("FileFighter") + .lowercaseUsername("filefighter") + .password(null) + .refreshToken(null) + .groupIds(new long[]{SYSTEM.getGroupId()}) + .build()); + } } diff --git a/src/test/resources/ViewFolderContents.feature b/src/test/resources/ViewFolderContents.feature index c4758ad8..7d47457d 100644 --- a/src/test/resources/ViewFolderContents.feature +++ b/src/test/resources/ViewFolderContents.feature @@ -2,10 +2,9 @@ Feature: View Folder As a user I want to see the content of folders and navigate in them, so they can see and interact with their uploaded and shared files. - # the user exist step should also create the - Background: Given database is empty + And runtime user exists And user with userId 1234 exists and has username "Richard", password "badPassword" And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" And accessToken with value "900000" exists for user 1234 @@ -13,8 +12,6 @@ Feature: View Folder And user with userId 1234 has HomeFolder with Id 1234 And user with userId 420 has HomeFolder with Id 420 And fileSystemItem with the fileSystemId 42 exists, has owner with userId 1234 has the path "/bla" and name "bla" - # should the path contain the user id ? like: "/420/bla" Then the fe requests /Gimleux/bla and you can easily look it up in the database - # then created by user would be useless and it should be replaced with 'last modified by' (basically it is the same) And fileSystemItem with the fileSystemId 72 exists, has owner with userId 1234 and name "wow.txt" And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 @@ -34,7 +31,6 @@ Feature: View Folder Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." - # failing !! Scenario: insufficient authorization When user with token "222222" wants to see the content of folder with path "/Richard/bla" Then response status code is 400 @@ -60,14 +56,12 @@ Feature: View Folder And the response contains the folder with name "Richard" Scenario: root folder shared - Given user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + Given user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 1234 When user with token "222222" wants to see the content of folder with path "/" Then response status code is 200 And the response contains the folder with name "Richard" And the response contains the folder with name "Nasir" - - Scenario: nested shared folder Given fileSystemItem with the fileSystemId 4 exists, has owner with userId 1234 has the path "/pläne" and name "pläne" And fileSystemItem with the fileSystemId 5 exists, has owner with userId 1234 has the path "/pläne/städte" and name "städte" @@ -77,17 +71,18 @@ Feature: View Folder And fileSystemItem with the fileSystemId 4 is a folder and contains the fileSystemId 5 And fileSystemItem with the fileSystemId 5 is a folder and contains the fileSystemId 12 And user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 12 - # Could he also only see the file? - When user with token "222222" wants to see the content of folder with path "/Richard" - Then response status code is 200 - And the response does not contains the file with fileSystemId 42 and name "bla" - And the response contains the folder with fileSystemId 4 and name "pläne" - When user with token "222222" wants to see the content of folder with path "/Richard/pläne" - Then response status code is 200 - And the response contains the folder with fileSystemId 5 and name "städte" - When user with token "222222" wants to see the content of folder with path "/Richard/pläne/städte" - Then response status code is 200 - And the response contains the folder with fileSystemId 12 and name "jerusalem" + And user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 13 + # Use this is the crud permissions feature file. + #When user with token "222222" wants to see the content of folder with path "/Richard" + #Then response status code is 200 + #And the response does not contains the file with fileSystemId 42 and name "bla" + #And the response contains the folder with fileSystemId 4 and name "pläne" + #When user with token "222222" wants to see the content of folder with path "/Richard/pläne" + #Then response status code is 200 + #And the response contains the folder with fileSystemId 5 and name "städte" + #When user with token "222222" wants to see the content of folder with path "/Richard/pläne/städte" + #Then response status code is 200 + #And the response contains the folder with fileSystemId 12 and name "jerusalem" When user with token "222222" wants to see the content of folder with path "/Richard/pläne/städte/jerusalem" Then response status code is 200 And the response contains the file with fileSystemId 13 and name "we_will_take.mp3" From 917f61530a5fbceae716ec6c9a145ee3ddc0aaa4 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Wed, 7 Apr 2021 10:05:57 +0200 Subject: [PATCH 10/20] Rewrote Deletion Endpoint. --- .../rest/configuration/PrepareDataBase.java | 31 ++- .../business/FileSystemBusinessService.java | 192 ++++++++---------- .../business/FileSystemHelperService.java | 26 ++- .../rest/FileSystemRestController.java | 4 +- .../rest/FileSystemRestService.java | 11 +- .../rest/FileSystemRestServiceInterface.java | 4 +- .../FileSystemHelperServiceUnitTest.java | 4 +- .../FileSystemRestControllerUnitTest.java | 9 +- 8 files changed, 152 insertions(+), 129 deletions(-) diff --git a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java index dd193ec6..9f5fdf15 100644 --- a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java +++ b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java @@ -194,7 +194,7 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo log.error("Inserting Users " + MESSAGE_ON_FAILURE); } - if (fileSystemRepository.findAll().size() == 6) { + if (fileSystemRepository.findAll().size() == 8) { log.info("Inserting FileSystemEntities " + MESSAGE_ON_SUCCESS); } else { log.error("Inserting FileSystemEntities " + MESSAGE_ON_FAILURE); @@ -262,7 +262,7 @@ private void addDefaultAdminAndRuntimeUser(UserRepository userRepository) { } private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository) { - log.info("Inserting default fsItems:\n {}\n {}\n {}\n {}\n {}\n {}.", + log.info("Inserting default fsItems:\n {}\n {}\n {}\n {}\n {}\n {}\n {}\n {}.", fileSystemRepository.save(FileSystemEntity.builder() .lastUpdatedBy(RUNTIME_USER_ID) .ownerId(1) @@ -273,7 +273,7 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .name("HOME_1") .size(4866) .typeId(FOLDER.getId()) - .itemIds(new long[]{2, 3}) + .itemIds(new long[]{2, 3, 7}) .visibleForGroupIds(new long[]{FAMILY.getGroupId(), ADMIN.getGroupId()}) .visibleForUserIds(new long[]{0}) .editableForUserIds(new long[]{0}) @@ -305,6 +305,18 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) .build()), + fileSystemRepository.save(FileSystemEntity.builder() + .lastUpdatedBy(1) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1) + .fileSystemId(7) + .isFile(true) + .name("visibleNonDeletableText.tex") + .size(42) + .typeId(TEXT.getId()) + .mimeType("text/plain") + .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) + .build()), fileSystemRepository.save(FileSystemEntity.builder() .lastUpdatedBy(1) .lastUpdated(Instant.now().getEpochSecond()) @@ -317,7 +329,7 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .typeId(FOLDER.getId()) .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) - .itemIds(new long[]{4, 5}) + .itemIds(new long[]{4, 5, 6}) .build()), fileSystemRepository.save(FileSystemEntity.builder() .lastUpdatedBy(1) @@ -344,6 +356,17 @@ private void addTestingFileSystemItems(FileSystemRepository fileSystemRepository .mimeType("video/mp4") .editableFoGroupIds(new long[]{FAMILY.getGroupId()}) .visibleForGroupIds(new long[]{FAMILY.getGroupId()}) + .build()), + fileSystemRepository.save(FileSystemEntity.builder() + .lastUpdatedBy(1) + .lastUpdated(Instant.now().getEpochSecond()) + .ownerId(1) + .fileSystemId(6) + .isFile(true) + .name("invisible_secret_video.mp4") + .size(1232) + .typeId(VIDEO.getId()) + .mimeType("video/mp4") .build()) ); } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 994ac37f..3738174e 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -13,6 +13,7 @@ import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; +import de.filefighter.rest.domain.user.group.Group; import lombok.extern.log4j.Log4j2; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; @@ -21,9 +22,9 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.LongStream; +import java.util.concurrent.LinkedBlockingQueue; @Log4j2 @Service @@ -35,7 +36,7 @@ public class FileSystemBusinessService { private final UserBusinessService userBusinessService; private final MongoTemplate mongoTemplate; - private static final String DELETION_FAILED_MSG = "Failed to delete FileSystemEntity with id "; + public static final String DELETION_FAILED_MSG = "Failed to delete FileSystemEntity with id "; public FileSystemBusinessService(FileSystemRepository fileSystemRepository, FileSystemHelperService fileSystemHelperService, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService, MongoTemplate mongoTemplate) { this.fileSystemRepository = fileSystemRepository; @@ -137,7 +138,7 @@ public FileSystemItem getFileSystemItemInfo(long fsItemId, User authenticatedUse return fileSystemHelperService.createDTO(fileSystemEntity, authenticatedUser, null); } - public boolean deleteFileSystemItemById(long fsItemId, User authenticatedUser) { + public List deleteFileSystemItemById(long fsItemId, User authenticatedUser) { FileSystemEntity fileSystemEntity = fileSystemRepository.findByFileSystemId(fsItemId); if (null == fileSystemEntity) throw new FileSystemItemCouldNotBeDeletedException(fsItemId); @@ -145,117 +146,96 @@ public boolean deleteFileSystemItemById(long fsItemId, User authenticatedUser) { if (!(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, authenticatedUser, InteractionType.READ) && fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, authenticatedUser, InteractionType.DELETE))) throw new FileSystemItemCouldNotBeDeletedException(fsItemId); - return recursivelyDeleteFileSystemEntity(fileSystemEntity, authenticatedUser); + return deleteFileSystemEntity(fileSystemEntity, authenticatedUser); } - /** - * Deletes the folder recursively. - * - * @param parentFileSystemEntity parent fileSystem entity, can be both folder and file. - * @param authenticatedUser user that wants to delete - * @return true if the folder and all the folders / items were deleted. - */ - @SuppressWarnings({"squid:S3776", "squid:S1192"}) - public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSystemEntity, User authenticatedUser) { - boolean everythingWasDeleted = false; - if (parentFileSystemEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(parentFileSystemEntity.getTypeId()) != FileSystemType.FOLDER) { - // 1. Base of recursion - // Delete File and update parentFolder. - Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); - if (countDeleted != 1) // TODO: check this number again. - throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); - - // unbind the deleted file. - Query query = new Query().addCriteria(Criteria.where("itemIds").is(parentFileSystemEntity.getFileSystemId())); - Update newUpdate = new Update().pull("itemIds", parentFileSystemEntity.getFileSystemId()); - mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); - - everythingWasDeleted = true; - } else if (!parentFileSystemEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(parentFileSystemEntity.getTypeId()) == FileSystemType.FOLDER) { - List foundList = fileSystemHelperService.getFolderContentsOfEntityAndPermissions(parentFileSystemEntity, authenticatedUser, false, false); - - if (null == foundList || foundList.isEmpty()) { - // 2. Base of recursion - Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); - if (countDeleted != 1) - throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); - - everythingWasDeleted = true; - } else { - ArrayList foundEntities = (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(parentFileSystemEntity, authenticatedUser, false, false); - ArrayList invisibleEntities = new ArrayList<>(); - List updatedItemIds = LongStream.of(parentFileSystemEntity.getItemIds()).boxed().collect(Collectors.toList()); - int deletedEntities = 0; - - for (FileSystemEntity childrenEntity : foundEntities) { - if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(childrenEntity, authenticatedUser, InteractionType.READ)) { - if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(childrenEntity, authenticatedUser, InteractionType.DELETE)) { - - // Folder. - if (!childrenEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(childrenEntity.getTypeId()) == FileSystemType.FOLDER) { - // Step of recursion - if (recursivelyDeleteFileSystemEntity(childrenEntity, authenticatedUser)) { - // there is no need to remove the child entity, because it was already deleted in the recursive function call. - // if it wasn't removed (if = false) we don't remove the folder and we don't delete it. - updatedItemIds.remove(childrenEntity.getFileSystemId()); - deletedEntities++; + @SuppressWarnings({"squid:S3776", "squid:S2142"}) + public List deleteFileSystemEntity(FileSystemEntity parentEntity, User authenticatedUser) { + ArrayList returnList = new ArrayList<>(); + try { + LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); + queue.put(parentEntity); + + FileSystemEntity currentEntity; + do { + currentEntity = queue.poll(); + if (null == currentEntity) + throw new FileFighterDataException("Queue was empty."); + + if (currentEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(currentEntity.getTypeId()) != FileSystemType.FOLDER) { + log.info("Found file to delete: {}.", currentEntity); + fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); + returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); + } else { + boolean foundNonDeletable = false; + boolean foundInvisible = false; + if (currentEntity.getItemIds().length != 0) { + List items = fileSystemHelperService.getFolderContentsOfEntityAndPermissions(currentEntity, authenticatedUser, false, false); + for (FileSystemEntity item : items) { + if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(item, authenticatedUser, InteractionType.READ)) { + if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(item, authenticatedUser, InteractionType.DELETE)) { + queue.put(item); + } else { + // a entity could not be removed disable the deletion of the parent folder. (current Entity) + foundNonDeletable = true; } - // File - } else if (childrenEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(childrenEntity.getTypeId()) != FileSystemType.FOLDER) { - // 3. Base of recursion - Long countDeleted = fileSystemRepository.deleteByFileSystemId(childrenEntity.getFileSystemId()); - if (countDeleted != 1) - throw new FileFighterDataException(DELETION_FAILED_MSG + childrenEntity.getFileSystemId()); - - updatedItemIds.remove(childrenEntity.getFileSystemId()); - deletedEntities++; } else { - throw new FileFighterDataException("FileType was wrong. " + childrenEntity); + // the entity also cannot be deleted BUT the current User looses the permissions. + foundInvisible = true; } } - // otherwise the item stays as it is. - } else { - invisibleEntities.add(childrenEntity); - } - } - // some entities could not be deleted because he is not allowed or cannot see them. - if (foundEntities.size() != deletedEntities) { - - // update itemIds. - parentFileSystemEntity.setItemIds(updatedItemIds.stream().mapToLong(Long::longValue).toArray()); - - // save changes of parentFolder to db. - Query query = new Query().addCriteria(Criteria.where("fileSystemId").is(parentFileSystemEntity.getFileSystemId())); - Update newUpdate = new Update().set("itemIds", parentFileSystemEntity.getItemIds()); - - // only problem appears when there are only invisible entities left. - boolean onlyInvisibleEntitiesAreLeftAfterRemovingDeletableEntities = !invisibleEntities.isEmpty() && (invisibleEntities.size() == updatedItemIds.size()); - if (onlyInvisibleEntitiesAreLeftAfterRemovingDeletableEntities) { - // some files do not include the current user to see them. By adding up all these permissions and applying them the the parent folder - // we can make sure, that the views of the other users stay the same, while the current user cannot see the folder anymore. - // EdgeCase: that the user who requests the deletion is owner of the folder but cannot see cannot happen anymore, - // because he the owner has all rights on all files except ones created by runtime users. - parentFileSystemEntity = fileSystemHelperService.sumUpAllPermissionsOfFileSystemEntities(parentFileSystemEntity, invisibleEntities); - - newUpdate.set("visibleForUserIds", parentFileSystemEntity.getVisibleForUserIds()) - .set("visibleForGroupIds", parentFileSystemEntity.getVisibleForGroupIds()) - .set("editableForUserIds", parentFileSystemEntity.getEditableForUserIds()) - .set("editableForGroupIds", parentFileSystemEntity.getEditableFoGroupIds()); - } - mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); - } else { - // No FileSystemEntities left in folder. -> can be deleted. - Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); - if (countDeleted != 1) - throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); + log.info("Currently working on: {}.", currentEntity); + + if (foundInvisible && !foundNonDeletable) { + // only invisible files left. + log.info("Found invisible FileSystemEntity {}", currentEntity); + + Query query = new Query().addCriteria(Criteria.where("fileSystemId").is(currentEntity.getFileSystemId())); + Update newUpdate = new Update(); + + // user is either directly in the visible ids or in a group that is visible. + long[] newIdsWithoutCurrentUserId = Arrays.stream(currentEntity.getVisibleForUserIds()).filter(userId -> userId != authenticatedUser.getUserId()).toArray(); + if (newIdsWithoutCurrentUserId.length != currentEntity.getVisibleForUserIds().length) { + // apply it. + newUpdate.set("visibleForUserIds", newIdsWithoutCurrentUserId); + } - everythingWasDeleted = true; + // or user is in a group that can see the filesystem entity. + long[] newGroupIds = currentEntity.getVisibleForGroupIds(); + if (newGroupIds.length != 0) { + for (Group group : authenticatedUser.getGroups()) { + newGroupIds = Arrays.stream(newGroupIds).filter(id -> id != group.getGroupId()).toArray(); + } + newUpdate.set("visibleForGroupIds", newGroupIds); + } + + // update time stamp + newUpdate + .set("lastUpdated", fileSystemHelperService.getCurrentTimeStamp()) + .set("lastUpdatedBy", authenticatedUser.getUserId()); + + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); + } else if (!foundInvisible && !foundNonDeletable) { + // every child item of the entity can be deleted. + log.info("Found no invisible or non deletable FileSystemEntities."); + fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); + returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); + } else { + // else some files are left. invisible or not. but the entity cannot be deleted. + log.info("Some visible entites could not be deleted."); + } + } else { + fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); + returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); + } } - } - } else { - throw new FileFighterDataException("FileType was wrong. " + parentFileSystemEntity); + } while (!queue.isEmpty()); + } catch (InterruptedException ex) { + log.error(ex); + throw new FileFighterDataException(ex.getMessage()); } - return everythingWasDeleted; + + return returnList; } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java index 86f2f8b0..65306db5 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -13,22 +13,30 @@ import de.filefighter.rest.domain.user.data.persistence.UserEntity; import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import de.filefighter.rest.domain.user.group.Group; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; import java.time.Instant; import java.util.*; +import static de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService.DELETION_FAILED_MSG; + @Service public class FileSystemHelperService { private final FileSystemRepository fileSystemRepository; private final FileSystemTypeRepository fileSystemTypeRepository; private final UserBusinessService userBusinessService; + private final MongoTemplate mongoTemplate; - public FileSystemHelperService(FileSystemRepository fileSystemRepository, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService) { + public FileSystemHelperService(FileSystemRepository fileSystemRepository, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService, MongoTemplate mongoTemplate) { this.fileSystemRepository = fileSystemRepository; this.fileSystemTypeRepository = fileSystemTypeRepository; this.userBusinessService = userBusinessService; + this.mongoTemplate = mongoTemplate; } public FileSystemEntity sumUpAllPermissionsOfFileSystemEntities(FileSystemEntity parentFileSystemEntity, List fileSystemEntities) { @@ -205,6 +213,22 @@ public void createBasicFilesForNewUser(UserEntity registeredUserEntity) { .build()); } + public void deleteAndUnbindFileSystemEntity(FileSystemEntity fileSystemEntity) { + Long countDeleted = fileSystemRepository.deleteByFileSystemId(fileSystemEntity.getFileSystemId()); + if (countDeleted != 1) + throw new FileFighterDataException(DELETION_FAILED_MSG + fileSystemEntity.getFileSystemId()); + + Query query = new Query().addCriteria(Criteria.where("itemIds").is(fileSystemEntity.getFileSystemId())); + Update newUpdate; + // only reduce size if the entity is a file. + if (fileSystemEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(fileSystemEntity.getTypeId()) != FileSystemType.FOLDER) { + newUpdate = new Update().pull("itemIds", fileSystemEntity.getFileSystemId()).inc("size", fileSystemEntity.getSize() * -1); // hacky stuff. + } else { + newUpdate = new Update().pull("itemIds", fileSystemEntity.getFileSystemId()); + } + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); + } + public double getTotalFileSize() { ArrayList entities = fileSystemRepository.findByPath("/"); if (null == entities) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java index 6331a22a..db9c736b 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java @@ -2,13 +2,13 @@ import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; -import de.filefighter.rest.rest.ServerResponse; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.log4j.Log4j2; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; +import java.util.List; import static de.filefighter.rest.configuration.RestConfiguration.*; @@ -76,7 +76,7 @@ public ResponseEntity updateExistingFileOrFolder( } @DeleteMapping(FS_BASE_URI + "{fsItemId}/delete") - public ResponseEntity deleteFileOrFolder( + public ResponseEntity> deleteFileOrFolder( @PathVariable long fsItemId, @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken ) { diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java index d1838fd4..71e00ab1 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java @@ -6,12 +6,12 @@ import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; import de.filefighter.rest.domain.user.data.dto.User; -import de.filefighter.rest.rest.ServerResponse; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.List; @Service public class FileSystemRestService implements FileSystemRestServiceInterface { @@ -57,13 +57,8 @@ public ResponseEntity updateFileSystemItemWithIdAndAccessToken(l } @Override - public ResponseEntity deleteFileSystemItemWithIdAndAccessToken(long fsItemId, String accessTokenValue) { + public ResponseEntity> deleteFileSystemItemWithIdAndAccessToken(long fsItemId, String accessTokenValue) { User authenticatedUser = authenticationService.bearerAuthenticationWithAccessToken(accessTokenValue); - boolean everythingWasDeleted = fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - if (everythingWasDeleted) { - return new ResponseEntity<>(new ServerResponse(HttpStatus.OK, "Successfully deleted all requested FileSystemItems."), HttpStatus.OK); - } else { - return new ResponseEntity<>(new ServerResponse(HttpStatus.OK, "Not everything got deleted, because you are not allowed to edit some files."), HttpStatus.OK); - } + return new ResponseEntity<>(fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser), HttpStatus.OK); } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java index 2ba796e3..5217b07f 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java @@ -2,10 +2,10 @@ import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; -import de.filefighter.rest.rest.ServerResponse; import org.springframework.http.ResponseEntity; import java.util.ArrayList; +import java.util.List; public interface FileSystemRestServiceInterface { ResponseEntity> getContentsOfFolderByPathAndAccessToken(String path, String accessToken); @@ -18,5 +18,5 @@ public interface FileSystemRestServiceInterface { ResponseEntity updateFileSystemItemWithIdAndAccessToken(long fsItemId, FileSystemItemUpdate fileSystemItemUpdate, String accessToken); - ResponseEntity deleteFileSystemItemWithIdAndAccessToken(long fsItemId, String accessToken); + ResponseEntity> deleteFileSystemItemWithIdAndAccessToken(long fsItemId, String accessToken); } diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java index 84c877d7..dfb0f0cd 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -13,6 +13,7 @@ import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import de.filefighter.rest.domain.user.group.Group; import org.junit.jupiter.api.Test; +import org.springframework.data.mongodb.core.MongoTemplate; import java.util.ArrayList; @@ -26,8 +27,9 @@ class FileSystemHelperServiceUnitTest { private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); private final FileSystemRepository fileSystemRepositoryMock = mock(FileSystemRepository.class); private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); + private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); - private final FileSystemHelperService fileSystemHelperService = new FileSystemHelperService(fileSystemRepositoryMock, fileSystemTypeRepositoryMock, userBusinessServiceMock); + private final FileSystemHelperService fileSystemHelperService = new FileSystemHelperService(fileSystemRepositoryMock, fileSystemTypeRepositoryMock, userBusinessServiceMock, mongoTemplateMock); @Test void sumUpAllPermissionsOfFileSystemEntitiesWorks() { diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java index 238d07a9..8ed27925 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java @@ -2,19 +2,18 @@ import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; -import de.filefighter.rest.rest.ServerResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import java.util.ArrayList; +import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.springframework.http.HttpStatus.OK; -import static org.springframework.http.HttpStatus.UNAUTHORIZED; class FileSystemRestControllerUnitTest { @@ -99,15 +98,15 @@ void updateExistingFileOrFolder() { @Test void deleteFileOrFolder() { - ServerResponse response = new ServerResponse(UNAUTHORIZED, "not authorized"); - ResponseEntity expectedModel = new ResponseEntity<>(response, OK); + ArrayList expectedItems = new ArrayList<>(); + ResponseEntity> expectedModel = new ResponseEntity<>(expectedItems, OK); long id = 420; String token = "token"; when(fileSystemRestServiceMock.deleteFileSystemItemWithIdAndAccessToken(id, token)).thenReturn(expectedModel); - ResponseEntity actualModel = fileSystemRestController.deleteFileOrFolder(id, token); + ResponseEntity> actualModel = fileSystemRestController.deleteFileOrFolder(id, token); assertEquals(expectedModel, actualModel); } } \ No newline at end of file From 1e36127f4847954a807849c79a3a07f95ec2fd6e Mon Sep 17 00:00:00 2001 From: open-schnick Date: Wed, 7 Apr 2021 18:33:46 +0200 Subject: [PATCH 11/20] Implemented recursive updating of timestamps --- .../business/FileSystemBusinessService.java | 9 +++---- .../business/FileSystemHelperService.java | 24 ++++++++++++++++++- .../FileSystemBusinessServiceUnitTest.java | 8 +++---- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 3738174e..3c54ec04 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -209,12 +209,6 @@ public List deleteFileSystemEntity(FileSystemEntity parentEntity } newUpdate.set("visibleForGroupIds", newGroupIds); } - - // update time stamp - newUpdate - .set("lastUpdated", fileSystemHelperService.getCurrentTimeStamp()) - .set("lastUpdatedBy", authenticatedUser.getUserId()); - mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } else if (!foundInvisible && !foundNonDeletable) { // every child item of the entity can be deleted. @@ -236,6 +230,9 @@ public List deleteFileSystemEntity(FileSystemEntity parentEntity throw new FileFighterDataException(ex.getMessage()); } + // update the time stamps in the file tree + fileSystemHelperService.recursivlyUpdateTimeStamps(parentEntity, authenticatedUser, fileSystemHelperService.getCurrentTimeStamp()); + return returnList; } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java index 65306db5..48d71e20 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -71,7 +71,6 @@ public void addPermissionsToSets(Set visibleForUserIds, Set visibleF } } - // TODO: refactor this to a list of interaction types. public List getFolderContentsOfEntityAndPermissions(FileSystemEntity fileSystemEntity, User authenticatedUser, boolean needsToBeVisible, boolean needsToBeEditable) { long[] folderContentItemIds = fileSystemEntity.getItemIds(); List fileSystemEntities = new ArrayList<>(folderContentItemIds.length); @@ -220,6 +219,8 @@ public void deleteAndUnbindFileSystemEntity(FileSystemEntity fileSystemEntity) { Query query = new Query().addCriteria(Criteria.where("itemIds").is(fileSystemEntity.getFileSystemId())); Update newUpdate; + + // TODO: fix this sizing. // only reduce size if the entity is a file. if (fileSystemEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(fileSystemEntity.getTypeId()) != FileSystemType.FOLDER) { newUpdate = new Update().pull("itemIds", fileSystemEntity.getFileSystemId()).inc("size", fileSystemEntity.getSize() * -1); // hacky stuff. @@ -229,6 +230,27 @@ public void deleteAndUnbindFileSystemEntity(FileSystemEntity fileSystemEntity) { mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } + public void recursivlyUpdateTimeStamps(FileSystemEntity currentEntity, User autheticatedUser, long currentTimeStamp) { + Query query = new Query().addCriteria(Criteria.where("fileSystemId").is(currentEntity.getFileSystemId())); + Update update = new Update().set("lastUpdated", currentTimeStamp).set("lastUpdatedBy", autheticatedUser.getUserId()); + mongoTemplate.findAndModify(query, update, FileSystemEntity.class); + + Query queryParentEntity = new Query().addCriteria(Criteria.where("itemIds").is(currentEntity.getFileSystemId())); + List parentFileSystemEntities = mongoTemplate.find(queryParentEntity, FileSystemEntity.class); + + if (parentFileSystemEntities.isEmpty()) { + if (!currentEntity.getPath().equals("/")) + throw new FileFighterDataException("Found no parent entity for a non root entity: " + currentEntity); + // else return. + + } else { + if (parentFileSystemEntities.size() > 1) + throw new FileFighterDataException("Found more than one parent entity for entity: " + currentEntity); + + recursivlyUpdateTimeStamps(parentFileSystemEntities.get(0), autheticatedUser, currentTimeStamp); + } + } + public double getTotalFileSize() { ArrayList entities = fileSystemRepository.findByPath("/"); if (null == entities) diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index dbe06d0f..060d6468 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -108,14 +108,14 @@ void recursivelyDeleteFileSystemEntityThrows() { FileSystemEntity rootFile = FileSystemEntity.builder().fileSystemId(fsItemId).build(); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(rootFile); FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFile, authenticatedUser)); + fileSystemBusinessService.deleteFileSystemEntity(rootFile, authenticatedUser)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); FileSystemEntity rootFolder = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).build(); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, false)).thenReturn(new ArrayList<>()); ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFolder, authenticatedUser)); + fileSystemBusinessService.deleteFileSystemEntity(rootFolder, authenticatedUser)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); FileSystemEntity rootFolder1 = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).itemIds(new long[]{fileSystemId0}).build(); @@ -129,12 +129,12 @@ void recursivelyDeleteFileSystemEntityThrows() { when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFolder1, authenticatedUser)); + fileSystemBusinessService.deleteFileSystemEntity(rootFolder1, authenticatedUser)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fileSystemId0, ex.getMessage()); when(fileSystemRepositoryMock.deleteByFileSystemId(fileSystemId0)).thenReturn(1L); ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFolder1, authenticatedUser)); + fileSystemBusinessService.deleteFileSystemEntity(rootFolder1, authenticatedUser)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); } From 95f911182ef89bab162aa5152b5188dc31021005 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Thu, 8 Apr 2021 09:04:35 +0200 Subject: [PATCH 12/20] Updated Tests, fixed cov. --- .../business/FileSystemHelperService.java | 18 ++++-- .../rest/cucumber/CommonCucumberSteps.java | 4 ++ .../FileSystemHelperServiceUnitTest.java | 60 ++++++++++++++++--- src/test/resources/ViewFolderContents.feature | 4 ++ 4 files changed, 73 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java index 48d71e20..4a7ac4e9 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -13,6 +13,7 @@ import de.filefighter.rest.domain.user.data.persistence.UserEntity; import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import de.filefighter.rest.domain.user.group.Group; +import lombok.extern.log4j.Log4j2; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; @@ -25,6 +26,7 @@ import static de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService.DELETION_FAILED_MSG; @Service +@Log4j2 public class FileSystemHelperService { private final FileSystemRepository fileSystemRepository; @@ -163,7 +165,8 @@ public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenti ownerOfFileSystemItem = userBusinessService.getUserById(fileSystemEntity.getOwnerId()); lastUpdatedByUser = userBusinessService.getUserById(fileSystemEntity.getLastUpdatedBy()); } catch (UserNotFoundException exception) { - throw new FileFighterDataException("Owner or auther of last change could not be found. Entity: " + fileSystemEntity); + log.debug("Found UserNotFoundException in createDTO. Entity: {}.", fileSystemEntity); + throw new FileFighterDataException("Owner or auther of last change could not be found."); } boolean isShared = ownerOfFileSystemItem.getUserId() != RestConfiguration.RUNTIME_USER_ID @@ -239,13 +242,16 @@ public void recursivlyUpdateTimeStamps(FileSystemEntity currentEntity, User auth List parentFileSystemEntities = mongoTemplate.find(queryParentEntity, FileSystemEntity.class); if (parentFileSystemEntities.isEmpty()) { - if (!currentEntity.getPath().equals("/")) - throw new FileFighterDataException("Found no parent entity for a non root entity: " + currentEntity); + if (!currentEntity.getPath().equals("/")) { + log.debug("Found no parent entity for a non root entity: " + currentEntity); + throw new FileFighterDataException("Found no parent entity for a non root entity."); + } // else return. - } else { - if (parentFileSystemEntities.size() > 1) - throw new FileFighterDataException("Found more than one parent entity for entity: " + currentEntity); + if (parentFileSystemEntities.size() > 1) { + log.debug("Found more than one parent entity for entity: " + currentEntity); + throw new FileFighterDataException("Found more than one parent entity for entity."); + } recursivlyUpdateTimeStamps(parentFileSystemEntities.get(0), autheticatedUser, currentTimeStamp); } diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index d9a22398..8c2b0282 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -20,6 +20,7 @@ import org.springframework.data.mongodb.core.query.Update; import java.io.IOException; +import java.time.Instant; import static de.filefighter.rest.configuration.RestConfiguration.RUNTIME_USER_ID; import static de.filefighter.rest.domain.user.group.Group.SYSTEM; @@ -95,6 +96,7 @@ public void userWithIdIsInGroupWithId(long userId, long groupId) { public void fileSystemItemWithTheFileSystemIdExistsAndHasThePath(long fileSystemId, long userId, String path, String name) { fileSystemRepository.save(FileSystemEntity.builder() .path(path) + .ownerId(userId) .lastUpdatedBy(userId) .fileSystemId(fileSystemId) .name(name) @@ -116,7 +118,9 @@ public void filesystemitemWithTheFileSystemIdExistsHasOwnerWithUserIdHasThePathS public void fileSystemItemWithTheFileSystemIdExistsAndHasTheName(long fileSystemId, long userId, String name) { fileSystemRepository.save(FileSystemEntity.builder() .name(name) + .ownerId(userId) .lastUpdatedBy(userId) + .lastUpdated(Instant.now().getEpochSecond()) .fileSystemId(fileSystemId) .build()); } diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java index dfb0f0cd..1803e6ce 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -14,13 +14,17 @@ import de.filefighter.rest.domain.user.group.Group; import org.junit.jupiter.api.Test; import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; import java.util.ArrayList; +import static de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService.DELETION_FAILED_MSG; import static de.filefighter.rest.domain.filesystem.data.InteractionType.*; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; class FileSystemHelperServiceUnitTest { @@ -79,7 +83,7 @@ void getFolderContentsOfEntityWorks() { FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().visibleForUserIds(new long[]{userId}).build(); FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().editableForUserIds(new long[]{userId}).build(); - FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().lastUpdatedBy(userId).build(); + FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().ownerId(userId).build(); FileSystemEntity rootFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId0, fileSystemId1, fileSystemId2}).build(); @@ -126,7 +130,7 @@ void removeTrailingWhiteSpaces() { void userIsAllowedToReadFileSystemEntity() { long userId = 1232783672; User user = User.builder().userId(userId).build(); - FileSystemEntity fileSystemEntity = FileSystemEntity.builder().lastUpdatedBy(userId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().ownerId(userId).build(); // user created fileSystemItem assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); @@ -154,7 +158,7 @@ void userIsAllowedToReadFileSystemEntity() { void userIsAllowedToEditFileSystemEntity() { long userId = 1232783672; User user = User.builder().userId(userId).build(); - FileSystemEntity fileSystemEntity = FileSystemEntity.builder().lastUpdatedBy(userId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().ownerId(userId).build(); // fileSystemEntity was created by runtime user. assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(FileSystemEntity.builder().lastUpdatedBy(RestConfiguration.RUNTIME_USER_ID).editableForUserIds(new long[]{userId}).build(), user, CHANGE)); @@ -193,7 +197,7 @@ void createDTOThrows() { FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> fileSystemHelperService.createDTO(entity, user, null)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Owner of a file could not be found.", ex.getMessage()); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Owner or auther of last change could not be found.", ex.getMessage()); } @Test @@ -212,10 +216,11 @@ void createDTOWorks() { User userThatCreatedFile = User.builder().userId(createdByUserId).build(); FileSystemEntity fileSystemEntity = FileSystemEntity .builder() - .lastUpdatedBy(createdByUserId) + .ownerId(createdByUserId) .itemIds(items) .fileSystemId(fileSystemId) .isFile(isFile) + .lastUpdatedBy(createdByUserId) .lastUpdated(lastUpdated) .name(name) .path("") // is empty because its a file. @@ -245,6 +250,47 @@ void getTotalFileSizeThrows() { assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Couldn't find any Home directories!", ex.getMessage()); } + @Test + void deleteAndUnbindFileSystemEntityThrows() { + long fileSystemId = 420; + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().fileSystemId(fileSystemId).build(); + + when(fileSystemRepositoryMock.deleteByFileSystemId(fileSystemId)).thenReturn(1234L); + + FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> + fileSystemHelperService.deleteAndUnbindFileSystemEntity(fileSystemEntity)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " " + DELETION_FAILED_MSG + fileSystemId, ex.getMessage()); + } + + @Test + void recursivlyUpdateTimeStampsThrows() { + ArrayList entities = new ArrayList<>(); + entities.add(FileSystemEntity.builder().build()); + entities.add(FileSystemEntity.builder().build()); + when(mongoTemplateMock.find(any(), eq(FileSystemEntity.class))).thenReturn(entities); + + FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> + fileSystemHelperService.recursivlyUpdateTimeStamps(FileSystemEntity.builder().build(), User.builder().build(), 420)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Found more than one parent entity for entity.", ex.getMessage()); + } + + // this is definitly not a good unit test. just for the 2% + @Test + void recursivlyUpdateTimeStampsWorks() { + long fsItemId = 420; + long fsItemId2 = 1234; + ArrayList entities = new ArrayList<>(); + entities.add(FileSystemEntity.builder().fileSystemId(fsItemId2).path("/").build()); + ArrayList emptyList = new ArrayList<>(); + + when(mongoTemplateMock.find(eq(new Query().addCriteria(Criteria.where("itemIds").is(fsItemId))), eq(FileSystemEntity.class))).thenReturn(entities); + when(mongoTemplateMock.find(eq(new Query().addCriteria(Criteria.where("itemIds").is(fsItemId2))), eq(FileSystemEntity.class))).thenReturn(emptyList); + + fileSystemHelperService.recursivlyUpdateTimeStamps(FileSystemEntity.builder().fileSystemId(fsItemId).build(), User.builder().build(), 420); + + verify(mongoTemplateMock, times(2)).findAndModify(any(), any(), any()); + } + @Test void getTotalFileSizeWorks() { double size0 = 1.3; diff --git a/src/test/resources/ViewFolderContents.feature b/src/test/resources/ViewFolderContents.feature index 7d47457d..52e5022a 100644 --- a/src/test/resources/ViewFolderContents.feature +++ b/src/test/resources/ViewFolderContents.feature @@ -21,7 +21,10 @@ Feature: View Folder And the response contains the file with fileSystemId 72 and name "wow.txt" Scenario: Successful interaction shared folder + # the folder Given user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + # the file + And user with the userId 420 is allowed to VIEW the fileSystemItem with the fileSystemId 72 When user with token "222222" wants to see the content of folder with path "/Richard/bla" Then response status code is 200 And the response contains the file with fileSystemId 72 and name "wow.txt" @@ -39,6 +42,7 @@ Feature: View Folder Scenario: shared folder (group) And user with userId 420 is in group with groupId 1 And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 72 When user with token "222222" wants to see the content of folder with path "/Richard/bla" Then response status code is 200 And the response contains the file with fileSystemId 72 and name "wow.txt" From af8854a221affc3c8a548da28229c163a28bde65 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Thu, 8 Apr 2021 14:55:38 +0200 Subject: [PATCH 13/20] fix some preperation steps for delte, add check for last modified --- .../rest/cucumber/CommonCucumberSteps.java | 3 ++ .../rest/cucumber/CrudFileSystemSteps.java | 12 +++++++ .../resources/deleteFileSystemItems.feature | 36 +++++++++++-------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index 8c2b0282..26738e72 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -12,6 +12,7 @@ import io.cucumber.java.en.And; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; @@ -228,4 +229,6 @@ public void runtimeUserExists() { .groupIds(new long[]{SYSTEM.getGroupId()}) .build()); } + + } diff --git a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java index e76d906e..a9bd80aa 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java @@ -29,4 +29,16 @@ public void userWithTokenWantsToDeleteTheFileSystemItemWithTheFileSystemId(Strin executeRestApiCall(HttpMethod.DELETE, BASE_API_URI + FS_BASE_URI + fileSystemId + "/delete", authHeader); } + + @When("user with token {string} to get the info of fileSystemItem with the fileSystemId {long}") + public void userWithTokenToGetTheInfoOfFileSystemItemWithTheFileSystemId(String accessTokenValue, long fileSystemId) { + String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessTokenValue; + + HashMap authHeader = new HashMap<>(); + authHeader.put("Authorization", authHeaderString); + + executeRestApiCall(HttpMethod.GET, BASE_API_URI + FS_BASE_URI + fileSystemId + "/info", authHeader); + + } + } diff --git a/src/test/resources/deleteFileSystemItems.feature b/src/test/resources/deleteFileSystemItems.feature index f3d0fb51..6a3599d9 100644 --- a/src/test/resources/deleteFileSystemItems.feature +++ b/src/test/resources/deleteFileSystemItems.feature @@ -1,16 +1,19 @@ Feature: FileSystem Delete As a user i want to delete FileSystemItems. - Background: - Given database is empty - And user with userId 1234 exists and has username "Richard", password "badPassword" - And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" - And accessToken with value "900000" exists for user 1234 - And accessToken with value "222222" exists for user 420 - And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 1234 has the path "/bla" and name "bla" - # todo add owner? (1234 in this case) - And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 1234 and has the name "wow.txt" - And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 +Background: + Given database is empty + And runtime user exists + And user with userId 1234 exists and has username "Richard", password "badPassword" + And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" + And accessToken with value "900000" exists for user 1234 + And accessToken with value "222222" exists for user 420 + And user with userId 1234 has HomeFolder with Id 1234 + And user with userId 420 has HomeFolder with Id 420 + And fileSystemItem with the fileSystemId 42 exists, has owner with userId 1234 has the path "/bla" and name "bla" + And fileSystemItem with the fileSystemId 72 exists, has owner with userId 1234 and name "wow.txt" + And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 + And fileSystemItem with the fileSystemId 1234 is a folder and contains the fileSystemId 42 Scenario: File Deletion When user with token "900000" wants to see the content of folder with path "/Richard/bla" @@ -22,6 +25,9 @@ Feature: FileSystem Delete When user with token "900000" wants to see the content of folder with path "/Richard/bla" Then the response contains an empty list for files and folders And response status code is 200 + When user with token "900000" to get the info of fileSystemItem with the fileSystemId 72 + Then response status code is 200 + And response contains key "lastUpdated" and value of at least 1617885970 Scenario: Folder and content Deletion When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 @@ -30,13 +36,12 @@ Feature: FileSystem Delete Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." - # todo add owners Scenario: recursion - Given fileSystemItem with the fileSystemId 0 exists, was created by user with userId 1234 has the path "/foo" and name "foo" + Given fileSystemItem with the fileSystemId 0 exists, has owner with userId 1234 has the path "/foo" and name "foo" And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 - And fileSystemItem with the fileSystemId 1 exists, was created by user with userId 1234 has the path "/foo/bar" and name "bar" + And fileSystemItem with the fileSystemId 1 exists, has owner with userId 1234 has the path "/foo/bar" and name "bar" And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 - And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 1234 and has the name "git.exe" + And fileSystemItem with the fileSystemId 2 exists, has owner with userId 1234 and name "git.exe" When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 0 Then response status code is 200 When user with token "900000" wants to see the content of folder with path "/Richard/foo/bar" @@ -45,6 +50,9 @@ Feature: FileSystem Delete When user with token "900000" wants to see the content of folder with path "/Richard/foo" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + When user with token "900000" wants to see the content of folder with path "/Richard" + Then the response contains an empty list for files and folders + And response status code is 200 Scenario: insufficient authorization From c9a0c3ed773cfe597412c8c7209e5eafba9a209c Mon Sep 17 00:00:00 2001 From: open-schnick Date: Thu, 8 Apr 2021 22:19:16 +0200 Subject: [PATCH 14/20] dirty hack, have a better idea ? --- .../business/FileSystemBusinessService.java | 2 +- .../FileSystemBusinessServiceUnitTest.java | 82 ++++++++++++++++--- .../FileSystemHelperServiceUnitTest.java | 1 + 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 3c54ec04..d73fe586 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -102,7 +102,7 @@ public List getFolderContentsByPath(String path, User authentica return fileSystemItems; } else { User finalOwnerOfRequestedFolder = ownerOfRequestedFolder; - listOfPossibleDirectories.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || entity.getOwnerId() != finalOwnerOfRequestedFolder.getUserId()); + listOfPossibleDirectories.removeIf(entity -> (entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || entity.getOwnerId() != finalOwnerOfRequestedFolder.getUserId())); if (listOfPossibleDirectories.isEmpty()) throw new FileSystemContentsNotAccessibleException(); diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index 060d6468..f20494f2 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -12,6 +12,7 @@ import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; +import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.data.mongodb.core.MongoTemplate; @@ -20,6 +21,7 @@ import java.util.ArrayList; +import static de.filefighter.rest.domain.filesystem.type.FileSystemType.FOLDER; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.*; @@ -27,26 +29,27 @@ class FileSystemBusinessServiceUnitTest { private final FileSystemRepository fileSystemRepositoryMock = mock(FileSystemRepository.class); - private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); + private UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); private final FileSystemHelperService fileSystemHelperServiceMock = mock(FileSystemHelperService.class); - private final UserBusinessService userBusinessService = mock(UserBusinessService.class); - private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, userBusinessService, mongoTemplateMock); + private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, userBusinessServiceMock, mongoTemplateMock); @Test void getFolderContentsByPathThrows() { String notValid = ""; String wrongFormat = "asd"; String wrongFormat1 = "as/d"; - String validPath = "/uga/uga/as/sasda/sassasd"; + String validUsername = "kevin"; + String validPathToFind = "/path"; + String validPath = "/" + validUsername + validPathToFind; User dummyUser = User.builder().userId(0).build(); FileSystemContentsNotAccessibleException ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(notValid, dummyUser)); - assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix() + " Path was in wrong format.", ex.getMessage()); ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(wrongFormat, dummyUser)); @@ -57,6 +60,7 @@ void getFolderContentsByPathThrows() { assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix() + " Path was in wrong format. Use a leading backslash.", ex.getMessage()); when(fileSystemRepositoryMock.findByPath(validPath)).thenReturn(null); + when(userBusinessServiceMock.findUserByUsername(validUsername)).thenReturn(User.builder().username(validUsername + "somethingelse").build()); when(fileSystemHelperServiceMock.removeTrailingBackSlashes(validPath)).thenReturn(validPath); ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> @@ -73,6 +77,60 @@ void getFolderContentsByPathThrows() { ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(validPath, dummyUser)); assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix(), ex.getMessage()); + + // throws because the user was not found. + when(userBusinessServiceMock.findUserByUsername(validUsername)).thenThrow(new UserNotFoundException("Like what?")); + ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> + fileSystemBusinessService.getFolderContentsByPath(validPath, dummyUser)); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix(), ex.getMessage()); + } + + @Test + void getFolderContentsByPathStillThrows() { + String validUsername = "kevin"; + String validPathToFind = "/path"; + String validPath = "/" + validUsername + validPathToFind; + long dummyUserId = 420124; + User authenticatedUser = User.builder().userId(0).build(); + User ownerOfFiles = User.builder().userId(dummyUserId).username(validUsername).build(); + + when(fileSystemHelperServiceMock.removeTrailingBackSlashes(validPathToFind)).thenReturn(validPathToFind); + + // throws because no folder was found. + when(fileSystemRepositoryMock.findByPath(validPathToFind)).thenReturn(null); + when(userBusinessServiceMock.findUserByUsername(validUsername)).thenReturn(ownerOfFiles); + FileSystemContentsNotAccessibleException ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> + fileSystemBusinessService.getFolderContentsByPath(validPath, authenticatedUser)); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix(), ex.getMessage()); + + // collection is empty after removing files. + ArrayList listOfPossibleFolders = new ArrayList<>(); + listOfPossibleFolders.add(FileSystemEntity.builder().isFile(true).typeId(FOLDER.getId()).build()); + when(fileSystemRepositoryMock.findByPath(validPathToFind)).thenReturn(listOfPossibleFolders); + + ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> + fileSystemBusinessService.getFolderContentsByPath(validPath, authenticatedUser)); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix(), ex.getMessage()); + + // more than one folder was found. + listOfPossibleFolders = new ArrayList<>(); + listOfPossibleFolders.add(FileSystemEntity.builder().fileSystemId(-420).ownerId(dummyUserId).isFile(false).typeId(FOLDER.getId()).build()); + listOfPossibleFolders.add(FileSystemEntity.builder().fileSystemId(1234).isFile(false).ownerId(dummyUserId).typeId(FOLDER.getId()).build()); + when(fileSystemRepositoryMock.findByPath(validPathToFind)).thenReturn(listOfPossibleFolders); + + FileFighterDataException dataException = assertThrows(FileFighterDataException.class, () -> + fileSystemBusinessService.getFolderContentsByPath(validPath, authenticatedUser)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Found more than one folder with the path " + validPathToFind, dataException.getMessage()); + + // not the rights for the actual entity + listOfPossibleFolders = new ArrayList<>(); + listOfPossibleFolders.add(FileSystemEntity.builder().fileSystemId(-420).ownerId(dummyUserId).isFile(false).typeId(FOLDER.getId()).build()); + when(fileSystemRepositoryMock.findByPath(validPathToFind)).thenReturn(listOfPossibleFolders); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(any(), eq(authenticatedUser), eq(InteractionType.READ))).thenReturn(false); + + ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> + fileSystemBusinessService.getFolderContentsByPath(validPath, authenticatedUser)); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix(), ex.getMessage()); } @Test @@ -112,7 +170,7 @@ void recursivelyDeleteFileSystemEntityThrows() { assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); FileSystemEntity rootFolder = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).build(); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, false)).thenReturn(new ArrayList<>()); ex = assertThrows(FileFighterDataException.class, () -> fileSystemBusinessService.deleteFileSystemEntity(rootFolder, authenticatedUser)); @@ -126,7 +184,7 @@ void recursivelyDeleteFileSystemEntityThrows() { when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileInRootFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileInRootFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(fileInRootFolder); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); ex = assertThrows(FileFighterDataException.class, () -> fileSystemBusinessService.deleteFileSystemEntity(rootFolder1, authenticatedUser)); @@ -158,7 +216,7 @@ void deleteFileSystemItemByIdThrows() { when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ))).thenReturn(true); when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE))).thenReturn(true); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); FileFighterDataException ex1 = assertThrows(FileFighterDataException.class, () -> fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FileType was wrong. " + foundEntity, ex1.getMessage()); @@ -202,7 +260,7 @@ void deleteFileSystemItemByIdWorksWithFolder() { FileSystemEntity folder = FileSystemEntity.builder().fileSystemId(folderId).typeId(0).isFile(false).lastUpdatedBy(userId).build(); when(fileSystemRepositoryMock.findByFileSystemId(folderId)).thenReturn(folder); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); when(fileSystemRepositoryMock.deleteByFileSystemId(folderId)).thenReturn(1L); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.READ)).thenReturn(true); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); @@ -236,7 +294,7 @@ void deleteFileSystemItemByIdWorksWithFolderWhenAllItemsCanBeDeleted() { FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().fileSystemId(itemId2).typeId(1).lastUpdatedBy(userId).isFile(true).build(); FileSystemEntity parentFolder = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).lastUpdatedBy(userId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(parentFolder); when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(fileSystemEntity0); when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(fileSystemEntity1); @@ -302,7 +360,7 @@ void deleteFileSystemItemByIdWorksWithFolderWhenSomeItemsCannotBeDeleted() { when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundFolder, authenticatedUser, false, false)).thenReturn(foundEntities); when(fileSystemHelperServiceMock.sumUpAllPermissionsOfFileSystemEntities(any(), any())).thenReturn(foundFolder); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(-1)).thenReturn(FileSystemType.UNDEFINED); when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(visibleEditableEmptyFolder); when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(invisibleFile); @@ -345,7 +403,7 @@ void deleteFileSystemItemByIdWorksWithFolderOnlyInvisible() { when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundEntity, authenticatedUser, false, false)).thenReturn(foundEntities); when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(-1)).thenReturn(FileSystemType.UNDEFINED); when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(visibleEditableEmptyFolder); when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(invisibleFile); diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java index 1803e6ce..5bc5a3c6 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -262,6 +262,7 @@ void deleteAndUnbindFileSystemEntityThrows() { assertEquals(FileFighterDataException.getErrorMessagePrefix() + " " + DELETION_FAILED_MSG + fileSystemId, ex.getMessage()); } + @SuppressWarnings("squid:S5778") @Test void recursivlyUpdateTimeStampsThrows() { ArrayList entities = new ArrayList<>(); From f5357214e2f6f9739a1e3beadfb8b59244ef54a1 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Fri, 9 Apr 2021 10:36:10 +0200 Subject: [PATCH 15/20] bad things happen when you forget about that one little change you made ages ago --- .../FileSystemBusinessServiceUnitTest.java | 55 ++++++++++++++----- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index f20494f2..85b00b4e 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -1,5 +1,6 @@ package de.filefighter.rest.domain.filesystem.business; +import de.filefighter.rest.configuration.RestConfiguration; import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; import de.filefighter.rest.domain.filesystem.data.InteractionType; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; @@ -29,7 +30,7 @@ class FileSystemBusinessServiceUnitTest { private final FileSystemRepository fileSystemRepositoryMock = mock(FileSystemRepository.class); - private UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); + private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); private final FileSystemHelperService fileSystemHelperServiceMock = mock(FileSystemHelperService.class); @@ -134,26 +135,52 @@ void getFolderContentsByPathStillThrows() { } @Test - void getFolderContentsByPathWorks() { - String path = "/uga/buga/buga"; - String pathToRequest = path + "/"; + void getFolderContentsByPathWorksWhenRequestingRoot() { + String path = "/"; long userId = 420; - long fileIdInFolder = 123; User user = User.builder().userId(userId).build(); - FileSystemEntity foundFolder = FileSystemEntity.builder().isFile(false).lastUpdatedBy(userId).typeId(0).itemIds(new long[]{fileIdInFolder}).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().path("/").ownerId(userId).lastUpdatedBy(RestConfiguration.RUNTIME_USER_ID).isFile(false).lastUpdatedBy(userId).typeId(FOLDER.getId()).build(); + FileSystemItem fileSystemItem = FileSystemItem.builder().build(); ArrayList entities = new ArrayList<>(); - entities.add(foundFolder); + entities.add(fileSystemEntity); - when(fileSystemHelperServiceMock.removeTrailingBackSlashes(pathToRequest)).thenReturn(path); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundFolder, user, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundFolder, user, true, false)).thenReturn(entities); - when(fileSystemHelperServiceMock.createDTO(foundFolder, user, pathToRequest)).thenReturn(FileSystemItem.builder().build()); + when(fileSystemHelperServiceMock.removeTrailingBackSlashes(path)).thenReturn(path); when(fileSystemRepositoryMock.findByPath(path)).thenReturn(entities); - when(fileSystemRepositoryMock.findByFileSystemId(fileIdInFolder)).thenReturn(FileSystemEntity.builder().lastUpdatedBy(userId).build()); - when(userBusinessServiceMock.getUserById(userId)).thenReturn(User.builder().build()); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.createDTO(fileSystemEntity, user, path)).thenReturn(fileSystemItem); - ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(pathToRequest, user); + ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(path, user); assertEquals(1, fileSystemItems.size()); + assertEquals(fileSystemItem, fileSystemItems.get(0)); + } + + @Test + void getFolderContentsByPathWorksWhenRequestingNonRoot() { + String ownerName = "foobar"; + String path = "/"; + String requestingPath = path + ownerName; + long userId = 420; + User user = User.builder().userId(userId).username(ownerName).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().path("/").ownerId(userId).lastUpdatedBy(RestConfiguration.RUNTIME_USER_ID).isFile(false).lastUpdatedBy(userId).typeId(FOLDER.getId()).build(); + FileSystemItem fileSystemItem = FileSystemItem.builder().build(); + ArrayList entities = new ArrayList<>(); + entities.add(fileSystemEntity); + + ArrayList children = new ArrayList<>(); + FileSystemEntity child = FileSystemEntity.builder().build(); + FileSystemItem childItem = FileSystemItem.builder().build(); + children.add(child); + + when(userBusinessServiceMock.findUserByUsername(ownerName)).thenReturn(user); + when(fileSystemHelperServiceMock.removeTrailingBackSlashes(path)).thenReturn(path); + when(fileSystemRepositoryMock.findByPath(path)).thenReturn(entities); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(fileSystemEntity, user, true, false)).thenReturn(children); + when(fileSystemHelperServiceMock.createDTO(child, user, requestingPath + path)).thenReturn(childItem); + + ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(requestingPath, user); + assertEquals(1, fileSystemItems.size()); + assertEquals(fileSystemItem, fileSystemItems.get(0)); } @Test From c3b04c15cc7989bb106a2556b5a7bb4b7df11835 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Fri, 9 Apr 2021 19:50:49 +0200 Subject: [PATCH 16/20] Finished UnitTests. Changed logger level to debug. --- .../business/FileSystemBusinessService.java | 10 +- .../FileSystemBusinessServiceUnitTest.java | 389 ++++++------------ 2 files changed, 140 insertions(+), 259 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index d73fe586..9d406cb4 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -163,7 +163,7 @@ public List deleteFileSystemEntity(FileSystemEntity parentEntity throw new FileFighterDataException("Queue was empty."); if (currentEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(currentEntity.getTypeId()) != FileSystemType.FOLDER) { - log.info("Found file to delete: {}.", currentEntity); + log.debug("Found file to delete: {}.", currentEntity); fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); } else { @@ -185,11 +185,11 @@ public List deleteFileSystemEntity(FileSystemEntity parentEntity } } - log.info("Currently working on: {}.", currentEntity); + log.debug("Currently working on: {}.", currentEntity); if (foundInvisible && !foundNonDeletable) { // only invisible files left. - log.info("Found invisible FileSystemEntity {}", currentEntity); + log.debug("Found invisible FileSystemEntity {}", currentEntity); Query query = new Query().addCriteria(Criteria.where("fileSystemId").is(currentEntity.getFileSystemId())); Update newUpdate = new Update(); @@ -212,12 +212,12 @@ public List deleteFileSystemEntity(FileSystemEntity parentEntity mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } else if (!foundInvisible && !foundNonDeletable) { // every child item of the entity can be deleted. - log.info("Found no invisible or non deletable FileSystemEntities."); + log.debug("Found no invisible or non deletable FileSystemEntities."); fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); } else { // else some files are left. invisible or not. but the entity cannot be deleted. - log.info("Some visible entites could not be deleted."); + log.debug("Some visible entites could not be deleted."); } } else { fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index 85b00b4e..43324099 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -9,11 +9,11 @@ import de.filefighter.rest.domain.filesystem.exceptions.FileSystemContentsNotAccessibleException; import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemCouldNotBeDeletedException; import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemNotFoundException; -import de.filefighter.rest.domain.filesystem.type.FileSystemType; import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; +import de.filefighter.rest.domain.user.group.Group; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.data.mongodb.core.MongoTemplate; @@ -21,10 +21,13 @@ import org.springframework.data.mongodb.core.query.Update; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import static de.filefighter.rest.domain.filesystem.type.FileSystemType.FOLDER; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static de.filefighter.rest.domain.filesystem.type.FileSystemType.TEXT; +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; class FileSystemBusinessServiceUnitTest { @@ -184,272 +187,150 @@ void getFolderContentsByPathWorksWhenRequestingNonRoot() { } @Test - void recursivelyDeleteFileSystemEntityThrows() { - long fsItemId = 12301231; - long fileSystemId0 = 420; - + void deleteFileSystemItemByIdThrows() { + long requestId = 420; User authenticatedUser = User.builder().build(); + FileSystemEntity entityToDelete = FileSystemEntity.builder().build(); - FileSystemEntity rootFile = FileSystemEntity.builder().fileSystemId(fsItemId).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(rootFile); - FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.deleteFileSystemEntity(rootFile, authenticatedUser)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); - - FileSystemEntity rootFolder = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).build(); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(rootFolder, authenticatedUser, false, false)).thenReturn(new ArrayList<>()); - ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.deleteFileSystemEntity(rootFolder, authenticatedUser)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); - - FileSystemEntity rootFolder1 = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).itemIds(new long[]{fileSystemId0}).build(); - ArrayList arrayListMock = new ArrayList<>(1); - FileSystemEntity fileInRootFolder = FileSystemEntity.builder().fileSystemId(fileSystemId0).build(); - arrayListMock.add(fileInRootFolder); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(rootFolder1, authenticatedUser, false, false)).thenReturn(arrayListMock); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileInRootFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileInRootFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(fileInRootFolder); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); - - ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.deleteFileSystemEntity(rootFolder1, authenticatedUser)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fileSystemId0, ex.getMessage()); - - when(fileSystemRepositoryMock.deleteByFileSystemId(fileSystemId0)).thenReturn(1L); - ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.deleteFileSystemEntity(rootFolder1, authenticatedUser)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); - } - - @Test - void deleteFileSystemItemByIdThrows() { - long fsItemId = 12332123; - long userId = 123123123; - User authenticatedUser = User.builder().userId(userId).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(null); FileSystemItemCouldNotBeDeletedException ex = assertThrows(FileSystemItemCouldNotBeDeletedException.class, () -> - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); - assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + fsItemId, ex.getMessage()); - - FileSystemEntity foundEntity = FileSystemEntity.builder().build(); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - ex = assertThrows(FileSystemItemCouldNotBeDeletedException.class, () -> - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); - assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + fsItemId, ex.getMessage()); - - foundEntity = FileSystemEntity.builder().lastUpdatedBy(userId).isFile(true).typeId(0).build(); - when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ))).thenReturn(true); - when((fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE))).thenReturn(true); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); - FileFighterDataException ex1 = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FileType was wrong. " + foundEntity, ex1.getMessage()); - - long folderContentId = 13287132; - FileSystemEntity folderContentEntity = FileSystemEntity.builder().lastUpdatedBy(userId).isFile(true).typeId(0).build(); - ArrayList fileSystemEntitiesMock = new ArrayList<>(); - fileSystemEntitiesMock.add(folderContentEntity); - when(fileSystemRepositoryMock.findByFileSystemId(folderContentId)).thenReturn(folderContentEntity); - foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).lastUpdatedBy(userId).itemIds(new long[]{folderContentId}).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundEntity, authenticatedUser, false, false)).thenReturn(fileSystemEntitiesMock); - ex1 = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); - assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FileType was wrong. " + folderContentEntity, ex1.getMessage()); - } - - @Test - void deleteFileSystemItemByIdWorksWithFile() { - long fsItemId = 12332123; - long userId = 243724328; - User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity foundEntity = FileSystemEntity.builder().fileSystemId(fsItemId).typeId(1).isFile(true).lastUpdatedBy(userId).build(); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); - - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(fsItemId); - } + fileSystemBusinessService.deleteFileSystemItemById(requestId, authenticatedUser)); + assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + requestId, ex.getMessage()); - @Test - void deleteFileSystemItemByIdWorksWithFolder() { - long folderId = 12332123; - long fileId = 420; - long userId = 243724328; - User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity folder = FileSystemEntity.builder().fileSystemId(folderId).typeId(0).isFile(false).lastUpdatedBy(userId).build(); - - when(fileSystemRepositoryMock.findByFileSystemId(folderId)).thenReturn(folder); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); - when(fileSystemRepositoryMock.deleteByFileSystemId(folderId)).thenReturn(1L); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(folder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - - FileSystemEntity file = FileSystemEntity.builder().typeId(2).fileSystemId(fileId).isFile(true).lastUpdatedBy(userId).itemIds(new long[0]).build(); - ArrayList foundFiles = new ArrayList<>(); - foundFiles.add(file); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(folder, authenticatedUser, false, false)).thenReturn(foundFiles); - - when(fileSystemRepositoryMock.findByFileSystemId(fileId)).thenReturn(file); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(file, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(file, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(2)).thenReturn(FileSystemType.VIDEO); - when(fileSystemRepositoryMock.deleteByFileSystemId(fileId)).thenReturn(1L); - - fileSystemBusinessService.deleteFileSystemItemById(folderId, authenticatedUser); - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(folderId); - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(fileId); - } + when(fileSystemRepositoryMock.findByFileSystemId(requestId)).thenReturn(entityToDelete); - @Test - void deleteFileSystemItemByIdWorksWithFolderWhenAllItemsCanBeDeleted() { - long fsItemId = 12332123; - long userId = 243724328; - User authenticatedUser = User.builder().userId(userId).build(); - long itemId0 = 1233212; - long itemId1 = 9872317; - long itemId2 = 1923847; - FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().isFile(false).typeId(0).lastUpdatedBy(userId).fileSystemId(itemId0).build(); - FileSystemEntity fileSystemEntity1 = FileSystemEntity.builder().fileSystemId(itemId1).typeId(1).lastUpdatedBy(userId).isFile(true).build(); - FileSystemEntity fileSystemEntity2 = FileSystemEntity.builder().fileSystemId(itemId2).typeId(1).lastUpdatedBy(userId).isFile(true).build(); - FileSystemEntity parentFolder = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).lastUpdatedBy(userId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); - - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(parentFolder); - when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(fileSystemEntity0); - when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(fileSystemEntity1); - when(fileSystemRepositoryMock.findByFileSystemId(itemId2)).thenReturn(fileSystemEntity2); - - ArrayList contentList = new ArrayList<>(); - contentList.add(fileSystemEntity0); - contentList.add(fileSystemEntity1); - contentList.add(fileSystemEntity2); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(parentFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(parentFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity0, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity0, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity1, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity1, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity2, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity2, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(parentFolder, authenticatedUser, false, false)).thenReturn(contentList); - - when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); - when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); - when(fileSystemRepositoryMock.deleteByFileSystemId(itemId1)).thenReturn(1L); - when(fileSystemRepositoryMock.deleteByFileSystemId(itemId2)).thenReturn(1L); - - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(fsItemId); - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId0); // empty folder - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId1); - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId2); + ex = assertThrows(FileSystemItemCouldNotBeDeletedException.class, () -> + fileSystemBusinessService.deleteFileSystemItemById(requestId, authenticatedUser)); + assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + requestId, ex.getMessage()); } @Test - void deleteFileSystemItemByIdWorksWithFolderWhenSomeItemsCannotBeDeleted() { - long fsItemId = 12332123; - long userId = 243724328; - long itemId0 = 1233212; - long itemId1 = 9872317; - long itemId2 = 1923847; - long itemId3 = 9817232; - User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity foundFolder = FileSystemEntity.builder().typeId(0).isFile(false).lastUpdatedBy(userId).itemIds(new long[]{itemId0, itemId1, itemId2, itemId3}).build(); - FileSystemEntity visibleEditableEmptyFolder = FileSystemEntity.builder().isFile(false).typeId(0).lastUpdatedBy(userId).fileSystemId(itemId0).build(); - FileSystemEntity invisibleFile = FileSystemEntity.builder().fileSystemId(itemId1).isFile(true).build(); - FileSystemEntity visibleNonEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).visibleForUserIds(new long[]{userId}).isFile(true).build(); - FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId3).lastUpdatedBy(userId).isFile(true).build(); - - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundFolder); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableEmptyFolder, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableEmptyFolder, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleNonEditableFile, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleNonEditableFile, authenticatedUser, InteractionType.DELETE)).thenReturn(false); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableFile, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(visibleEditableFile, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - - ArrayList foundEntities = new ArrayList<>(); - foundEntities.add(visibleEditableFile); - foundEntities.add(invisibleFile); - foundEntities.add(visibleNonEditableFile); - foundEntities.add(visibleEditableEmptyFolder); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundFolder, authenticatedUser, false, false)).thenReturn(foundEntities); - when(fileSystemHelperServiceMock.sumUpAllPermissionsOfFileSystemEntities(any(), any())).thenReturn(foundFolder); - - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(-1)).thenReturn(FileSystemType.UNDEFINED); - when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(visibleEditableEmptyFolder); - when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(invisibleFile); - when(fileSystemRepositoryMock.findByFileSystemId(itemId2)).thenReturn(visibleNonEditableFile); - when(fileSystemRepositoryMock.findByFileSystemId(itemId3)).thenReturn(visibleEditableFile); - when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); - when(fileSystemRepositoryMock.deleteByFileSystemId(itemId3)).thenReturn(1L); - - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - - // verify deleted entities. - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId0); - verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId3); - - ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); - verify(mongoTemplateMock, times(1)).findAndModify(any(), updateArgumentCaptor.capture(), any()); - assertEquals("{ \"$set\" : { \"itemIds\" : [ " + itemId1 + ", " + itemId2 + " ] } }", updateArgumentCaptor.getValue().toString()); // no better way to assert requested changes. + void deleteFileSystemItemByIdWorksWithDeletableItemsOnly() { + long requestId = 420; + User authenticatedUser = User.builder().build(); + FileSystemEntity entityFolderToDelete = FileSystemEntity.builder().fileSystemId(requestId).isFile(false).fileSystemId(FOLDER.getId()).itemIds(new long[]{123, 321, 1234}).build(); + FileSystemEntity entity0 = FileSystemEntity.builder().isFile(true).typeId(TEXT.getId()).fileSystemId(321).build(); + FileSystemEntity entity1 = FileSystemEntity.builder().isFile(true).typeId(TEXT.getId()).fileSystemId(123).build(); + FileSystemEntity entity2 = FileSystemEntity.builder().isFile(false).typeId(FOLDER.getId()).fileSystemId(1234).build(); + List contentsOfDirectoryToDelete = Arrays.asList(entity0, entity1, entity2); + + FileSystemItem folderItem = FileSystemItem.builder().build(); + FileSystemItem file0 = FileSystemItem.builder().build(); + FileSystemItem file1 = FileSystemItem.builder().build(); + FileSystemItem file2 = FileSystemItem.builder().build(); + List dtoReturnList = Arrays.asList(folderItem, file0, file1, file2); + + when(fileSystemRepositoryMock.findByFileSystemId(requestId)).thenReturn(entityFolderToDelete); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entityFolderToDelete, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entityFolderToDelete, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(entityFolderToDelete, authenticatedUser, false, false)).thenReturn(contentsOfDirectoryToDelete); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity0, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity0, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity1, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity1, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity2, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity2, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + + // create dtos. + when(fileSystemHelperServiceMock.createDTO(entityFolderToDelete, authenticatedUser, null)).thenReturn(folderItem); + when(fileSystemHelperServiceMock.createDTO(entity0, authenticatedUser, null)).thenReturn(file0); + when(fileSystemHelperServiceMock.createDTO(entity1, authenticatedUser, null)).thenReturn(file1); + when(fileSystemHelperServiceMock.createDTO(entity2, authenticatedUser, null)).thenReturn(file2); + + // call function + List actual = fileSystemBusinessService.deleteFileSystemItemById(requestId, authenticatedUser); + + // verify deletion + verify(fileSystemHelperServiceMock, times(4)).deleteAndUnbindFileSystemEntity(any()); + + // check for returns + assertEquals(dtoReturnList, actual); } @Test - void deleteFileSystemItemByIdWorksWithFolderOnlyInvisible() { - long fsItemId = 12332123; - long userId = 243724328; - User authenticatedUser = User.builder().userId(userId).build(); - long itemId0 = 1233212; - long itemId1 = 9872317; - long itemId2 = 1923847; - FileSystemEntity foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).fileSystemId(fsItemId).itemIds(new long[]{itemId0, itemId1, itemId2}).build(); - FileSystemEntity visibleEditableEmptyFolder = FileSystemEntity.builder().isFile(false).typeId(0).fileSystemId(itemId0).build(); - FileSystemEntity invisibleFile = FileSystemEntity.builder().fileSystemId(itemId1).isFile(true).visibleForUserIds(new long[]{userId - 1}).build(); - FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).isFile(true).build(); - - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.READ)).thenReturn(true); - when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(foundEntity, authenticatedUser, InteractionType.DELETE)).thenReturn(true); - - ArrayList foundEntities = new ArrayList<>(); - foundEntities.add(visibleEditableFile); - foundEntities.add(invisibleFile); - foundEntities.add(visibleEditableEmptyFolder); - when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(foundEntity, authenticatedUser, false, false)).thenReturn(foundEntities); - - when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FOLDER); - when(fileSystemTypeRepositoryMock.findFileSystemTypeById(-1)).thenReturn(FileSystemType.UNDEFINED); - when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(visibleEditableEmptyFolder); - when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(invisibleFile); - when(fileSystemRepositoryMock.findByFileSystemId(itemId2)).thenReturn(visibleEditableFile); - when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); - when(fileSystemRepositoryMock.deleteByFileSystemId(itemId2)).thenReturn(1L); - - FileSystemEntity entityWithSummedUpPermissions = FileSystemEntity.builder().build(); - entityWithSummedUpPermissions.setVisibleForUserIds(invisibleFile.getVisibleForUserIds()); - when(fileSystemHelperServiceMock.sumUpAllPermissionsOfFileSystemEntities(foundEntity, foundEntities)).thenReturn(entityWithSummedUpPermissions); - fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); - - // nothing should be deleted, but parent folder should be changed, so the user cannot see the "deleted" folder anymore. + void deleteFileSystemItemByIdWorksWithInvisibleItemsOnly() { + long requestId = 420; + long userId = 1234; + long notUserId0 = 123898901; + long notUserId1 = 908137452; + User authenticatedUser = User.builder().userId(userId).groups(new Group[]{Group.FAMILY}).build(); + FileSystemEntity entityFolderToDelete = FileSystemEntity.builder() + .visibleForGroupIds(new long[]{Group.FAMILY.getGroupId(), Group.ADMIN.getGroupId()}) + .visibleForUserIds(new long[]{userId, notUserId0, notUserId1}) + .fileSystemId(requestId) + .isFile(false) + .typeId(FOLDER.getId()) + .itemIds(new long[]{123}) + .build(); + FileSystemEntity entity0 = FileSystemEntity.builder().isFile(true).typeId(TEXT.getId()).fileSystemId(321).build(); + + List contentsOfDirectoryToDelete = Collections.singletonList(entity0); + + FileSystemItem folderItem = FileSystemItem.builder().build(); + FileSystemItem file0 = FileSystemItem.builder().build(); + List dtoReturnList = Arrays.asList(folderItem, file0); + + when(fileSystemRepositoryMock.findByFileSystemId(requestId)).thenReturn(entityFolderToDelete); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entityFolderToDelete, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entityFolderToDelete, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(entityFolderToDelete, authenticatedUser, false, false)).thenReturn(contentsOfDirectoryToDelete); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity0, authenticatedUser, InteractionType.READ)).thenReturn(false); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity0, authenticatedUser, InteractionType.DELETE)).thenReturn(false); + + // create dtos. + when(fileSystemHelperServiceMock.createDTO(entityFolderToDelete, authenticatedUser, null)).thenReturn(folderItem); + when(fileSystemHelperServiceMock.createDTO(entity0, authenticatedUser, null)).thenReturn(file0); + + // call function + fileSystemBusinessService.deleteFileSystemItemById(requestId, authenticatedUser); + + // verify change of parent ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); ArgumentCaptor queryArgumentCaptor = ArgumentCaptor.forClass(Query.class); verify(mongoTemplateMock, times(1)).findAndModify(queryArgumentCaptor.capture(), updateArgumentCaptor.capture(), eq(FileSystemEntity.class)); - assertEquals("Query: { \"fileSystemId\" : " + fsItemId + "}, Fields: {}, Sort: {}", queryArgumentCaptor.getValue().toString()); - assertEquals("{ \"$set\" : { \"itemIds\" : [ " + itemId0 + ", " + itemId1 + ", " + itemId2 + " ], \"visibleForUserIds\" : [ " + (userId - 1) + " ], \"visibleForGroupIds\" : [ ], \"editableForUserIds\" : [ ], \"editableForGroupIds\" : [ ] } }", updateArgumentCaptor.getValue().toString()); // no better way to assert requested changes. + assertEquals("Query: { \"fileSystemId\" : " + requestId + "}, Fields: {}, Sort: {}", queryArgumentCaptor.getValue().toString()); + assertEquals("{ \"$set\" : { \"visibleForUserIds\" : [ " + notUserId0 + ", " + notUserId1 + " ], \"visibleForGroupIds\" : [ " + Group.ADMIN.getGroupId() + " ] } }", updateArgumentCaptor.getValue().toString()); + } + + @Test + void deleteFileSystemItemByIdWorksWithNonDeletableItems() { + long requestId = 420; + long userId = 1234; + long notUserId0 = 123898901; + long notUserId1 = 908137452; + User authenticatedUser = User.builder().userId(userId).groups(new Group[]{Group.FAMILY}).build(); + FileSystemEntity entityFolderToDelete = FileSystemEntity.builder() + .visibleForGroupIds(new long[]{Group.FAMILY.getGroupId(), Group.ADMIN.getGroupId()}) + .visibleForUserIds(new long[]{userId, notUserId0, notUserId1}) + .fileSystemId(requestId) + .isFile(false) + .typeId(FOLDER.getId()) + .itemIds(new long[]{123}) + .build(); + FileSystemEntity entity0 = FileSystemEntity.builder().isFile(true).typeId(TEXT.getId()).fileSystemId(321).build(); + + List contentsOfDirectoryToDelete = Collections.singletonList(entity0); + + FileSystemItem folderItem = FileSystemItem.builder().build(); + FileSystemItem file0 = FileSystemItem.builder().build(); + + when(fileSystemRepositoryMock.findByFileSystemId(requestId)).thenReturn(entityFolderToDelete); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entityFolderToDelete, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entityFolderToDelete, authenticatedUser, InteractionType.DELETE)).thenReturn(true); + when(fileSystemHelperServiceMock.getFolderContentsOfEntityAndPermissions(entityFolderToDelete, authenticatedUser, false, false)).thenReturn(contentsOfDirectoryToDelete); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity0, authenticatedUser, InteractionType.READ)).thenReturn(true); + when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entity0, authenticatedUser, InteractionType.DELETE)).thenReturn(false); + + // create dtos. + when(fileSystemHelperServiceMock.createDTO(entityFolderToDelete, authenticatedUser, null)).thenReturn(folderItem); + when(fileSystemHelperServiceMock.createDTO(entity0, authenticatedUser, null)).thenReturn(file0); + + // call function + List actual = fileSystemBusinessService.deleteFileSystemItemById(requestId, authenticatedUser); + + // verify no deletion. + verify(fileSystemHelperServiceMock, times(0)).deleteAndUnbindFileSystemEntity(any()); + assertTrue(actual.isEmpty()); } @Test From 1b22626e4a948dc81ac01c190417ecdf66701578 Mon Sep 17 00:00:00 2001 From: qvalentin Date: Sun, 11 Apr 2021 17:32:26 +0200 Subject: [PATCH 17/20] add return values to delte feature file --- .../de/filefighter/rest/cucumber/CrudFileSystemSteps.java | 4 ++-- src/test/resources/deleteFileSystemItems.feature | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java index a9bd80aa..48fcc8e8 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java @@ -30,8 +30,8 @@ public void userWithTokenWantsToDeleteTheFileSystemItemWithTheFileSystemId(Strin executeRestApiCall(HttpMethod.DELETE, BASE_API_URI + FS_BASE_URI + fileSystemId + "/delete", authHeader); } - @When("user with token {string} to get the info of fileSystemItem with the fileSystemId {long}") - public void userWithTokenToGetTheInfoOfFileSystemItemWithTheFileSystemId(String accessTokenValue, long fileSystemId) { + @When("user with token {string} wants to get the info of fileSystemItem with the fileSystemId {long}") + public void userWithTokenWantsToGetTheInfoOfFileSystemItemWithTheFileSystemId(String accessTokenValue, long fileSystemId) { String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessTokenValue; HashMap authHeader = new HashMap<>(); diff --git a/src/test/resources/deleteFileSystemItems.feature b/src/test/resources/deleteFileSystemItems.feature index 6a3599d9..d89db23c 100644 --- a/src/test/resources/deleteFileSystemItems.feature +++ b/src/test/resources/deleteFileSystemItems.feature @@ -25,13 +25,16 @@ Background: When user with token "900000" wants to see the content of folder with path "/Richard/bla" Then the response contains an empty list for files and folders And response status code is 200 - When user with token "900000" to get the info of fileSystemItem with the fileSystemId 72 + When user with token "900000" wants to get the info of fileSystemItem with the fileSystemId 72 Then response status code is 200 And response contains key "lastUpdated" and value of at least 1617885970 + And the response contains the file with fileSystemId 72 and name "wow.txt" Scenario: Folder and content Deletion When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 Then response status code is 200 + And the response contains the file with fileSystemId 72 and name "wow.txt" + And the response contains the folder with fileSystemId 42 and name "bla" When user with token "900000" wants to see the content of folder with path "/Richard/bla" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." @@ -44,6 +47,9 @@ Background: And fileSystemItem with the fileSystemId 2 exists, has owner with userId 1234 and name "git.exe" When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 0 Then response status code is 200 + And the response contains the file with fileSystemId 2 and name "git.exe" + And the response contains the folder with fileSystemId 1 and name "bar" + And the response contains the folder with fileSystemId 0 and name "foo" When user with token "900000" wants to see the content of folder with path "/Richard/foo/bar" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." From f2b3e0651ab666d8316bd437cfb07cbeea90089d Mon Sep 17 00:00:00 2001 From: open-schnick Date: Tue, 13 Apr 2021 12:43:08 +0200 Subject: [PATCH 18/20] FF-331 rewrote deletion endpoint logic for the 12398th time. --- .../business/FileSystemBusinessService.java | 155 +++++++----------- .../business/FileSystemHelperService.java | 27 ++- .../rest/FileSystemRestController.java | 16 +- .../resources/application-test.properties | 1 + .../rest/cucumber/CommonCucumberSteps.java | 21 ++- .../rest/cucumber/CrudFileSystemSteps.java | 2 +- .../FileSystemBusinessServiceUnitTest.java | 2 +- .../resources/deleteFileSystemItems.feature | 54 +++--- 8 files changed, 151 insertions(+), 127 deletions(-) create mode 100644 src/main/resources/application-test.properties diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index 9d406cb4..a77f1f02 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -13,18 +13,12 @@ import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; -import de.filefighter.rest.domain.user.group.Group; +import lombok.Data; import lombok.extern.log4j.Log4j2; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.concurrent.LinkedBlockingQueue; @Log4j2 @Service @@ -34,16 +28,14 @@ public class FileSystemBusinessService { private final FileSystemHelperService fileSystemHelperService; private final FileSystemTypeRepository fileSystemTypeRepository; private final UserBusinessService userBusinessService; - private final MongoTemplate mongoTemplate; public static final String DELETION_FAILED_MSG = "Failed to delete FileSystemEntity with id "; - public FileSystemBusinessService(FileSystemRepository fileSystemRepository, FileSystemHelperService fileSystemHelperService, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService, MongoTemplate mongoTemplate) { + public FileSystemBusinessService(FileSystemRepository fileSystemRepository, FileSystemHelperService fileSystemHelperService, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService) { this.fileSystemRepository = fileSystemRepository; this.fileSystemHelperService = fileSystemHelperService; this.fileSystemTypeRepository = fileSystemTypeRepository; this.userBusinessService = userBusinessService; - this.mongoTemplate = mongoTemplate; } @SuppressWarnings("java:S3776") @@ -116,8 +108,8 @@ public List getFolderContentsByPath(String path, User authentica throw new FileSystemContentsNotAccessibleException(); ArrayList fileSystemItems = new ArrayList<>(); - ArrayList folderContents = - (ArrayList) fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfPossibleDirectories.get(0), authenticatedUser, true, false); + List folderContents = + fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfPossibleDirectories.get(0), authenticatedUser, true, false); for (FileSystemEntity fileSystemEntityInFolder : folderContents) { fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, "/" + ownerOfRequestedFolder.getUsername() + pathToFind)); @@ -139,100 +131,77 @@ public FileSystemItem getFileSystemItemInfo(long fsItemId, User authenticatedUse } public List deleteFileSystemItemById(long fsItemId, User authenticatedUser) { - FileSystemEntity fileSystemEntity = fileSystemRepository.findByFileSystemId(fsItemId); - if (null == fileSystemEntity) + FileSystemEntity parentEntity = fileSystemRepository.findByFileSystemId(fsItemId); + if (null == parentEntity) throw new FileSystemItemCouldNotBeDeletedException(fsItemId); - if (!(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, authenticatedUser, InteractionType.READ) && fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, authenticatedUser, InteractionType.DELETE))) + if (!(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(parentEntity, authenticatedUser, InteractionType.READ) && fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(parentEntity, authenticatedUser, InteractionType.DELETE))) throw new FileSystemItemCouldNotBeDeletedException(fsItemId); - return deleteFileSystemEntity(fileSystemEntity, authenticatedUser); - } + // update the time stamps in the file tree + fileSystemHelperService.recursivlyUpdateTimeStamps(parentEntity, authenticatedUser, fileSystemHelperService.getCurrentTimeStamp()); + + log.info("User is {}.", authenticatedUser); - @SuppressWarnings({"squid:S3776", "squid:S2142"}) - public List deleteFileSystemEntity(FileSystemEntity parentEntity, User authenticatedUser) { ArrayList returnList = new ArrayList<>(); - try { - LinkedBlockingQueue queue = new LinkedBlockingQueue<>(); - queue.put(parentEntity); - - FileSystemEntity currentEntity; - do { - currentEntity = queue.poll(); - if (null == currentEntity) - throw new FileFighterDataException("Queue was empty."); - - if (currentEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(currentEntity.getTypeId()) != FileSystemType.FOLDER) { - log.debug("Found file to delete: {}.", currentEntity); - fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); - returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); - } else { - boolean foundNonDeletable = false; - boolean foundInvisible = false; - if (currentEntity.getItemIds().length != 0) { - List items = fileSystemHelperService.getFolderContentsOfEntityAndPermissions(currentEntity, authenticatedUser, false, false); - for (FileSystemEntity item : items) { - if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(item, authenticatedUser, InteractionType.READ)) { - if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(item, authenticatedUser, InteractionType.DELETE)) { - queue.put(item); - } else { - // a entity could not be removed disable the deletion of the parent folder. (current Entity) - foundNonDeletable = true; - } - } else { - // the entity also cannot be deleted BUT the current User looses the permissions. - foundInvisible = true; - } - } + recursivlyDeleteFileSystemEntity(parentEntity, authenticatedUser, returnList); + return returnList; + } + + private RecursiveReturn recursivlyDeleteFileSystemEntity(FileSystemEntity parentEntity, User authenticatedUser, ArrayList returnList) { + boolean foundNonDeletable = false; + boolean foundInvisible = false; - log.debug("Currently working on: {}.", currentEntity); - - if (foundInvisible && !foundNonDeletable) { - // only invisible files left. - log.debug("Found invisible FileSystemEntity {}", currentEntity); - - Query query = new Query().addCriteria(Criteria.where("fileSystemId").is(currentEntity.getFileSystemId())); - Update newUpdate = new Update(); - - // user is either directly in the visible ids or in a group that is visible. - long[] newIdsWithoutCurrentUserId = Arrays.stream(currentEntity.getVisibleForUserIds()).filter(userId -> userId != authenticatedUser.getUserId()).toArray(); - if (newIdsWithoutCurrentUserId.length != currentEntity.getVisibleForUserIds().length) { - // apply it. - newUpdate.set("visibleForUserIds", newIdsWithoutCurrentUserId); - } - - // or user is in a group that can see the filesystem entity. - long[] newGroupIds = currentEntity.getVisibleForGroupIds(); - if (newGroupIds.length != 0) { - for (Group group : authenticatedUser.getGroups()) { - newGroupIds = Arrays.stream(newGroupIds).filter(id -> id != group.getGroupId()).toArray(); - } - newUpdate.set("visibleForGroupIds", newGroupIds); - } - mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); - } else if (!foundInvisible && !foundNonDeletable) { - // every child item of the entity can be deleted. - log.debug("Found no invisible or non deletable FileSystemEntities."); - fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); - returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); + // the parentEntity is already checked. + if (parentEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(parentEntity.getTypeId()) != FileSystemType.FOLDER) { + log.debug("Found file to delete: {}.", parentEntity); + fileSystemHelperService.deleteAndUnbindFileSystemEntity(parentEntity); + returnList.add(fileSystemHelperService.createDTO(parentEntity, authenticatedUser, null)); + } else { + if (parentEntity.getItemIds().length != 0) { + List items = fileSystemHelperService.getFolderContentsOfEntityAndPermissions(parentEntity, authenticatedUser, false, false); + for (FileSystemEntity item : items) { + if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(item, authenticatedUser, InteractionType.READ)) { + if (fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(item, authenticatedUser, InteractionType.DELETE)) { + RecursiveReturn recursiveReturn = recursivlyDeleteFileSystemEntity(item, authenticatedUser, returnList); + foundInvisible = recursiveReturn.foundInvisibleEntities || foundInvisible; + foundNonDeletable = recursiveReturn.foundNonDeletableEntities || foundNonDeletable; } else { - // else some files are left. invisible or not. but the entity cannot be deleted. - log.debug("Some visible entites could not be deleted."); + // a entity could not be removed disable the deletion of the parent folder. (current Entity) + foundNonDeletable = true; } } else { - fileSystemHelperService.deleteAndUnbindFileSystemEntity(currentEntity); - returnList.add(fileSystemHelperService.createDTO(currentEntity, authenticatedUser, null)); + // the entity also cannot be deleted BUT the current User looses the permissions. + foundInvisible = true; } } - } while (!queue.isEmpty()); - } catch (InterruptedException ex) { - log.error(ex); - throw new FileFighterDataException(ex.getMessage()); - } - // update the time stamps in the file tree - fileSystemHelperService.recursivlyUpdateTimeStamps(parentEntity, authenticatedUser, fileSystemHelperService.getCurrentTimeStamp()); + log.info("Currently working on: {}.", parentEntity); + + if (foundInvisible && !foundNonDeletable) { + // only invisible files left. + log.info("Found invisible FileSystemEntity {}", parentEntity); + fileSystemHelperService.removeVisibilityRightsOfFileSystemEntityForUser(parentEntity, authenticatedUser); + } else if (!foundInvisible && !foundNonDeletable) { + // every child item of the entity can be deleted. + log.info("Found no invisible or non deletable FileSystemEntities."); + fileSystemHelperService.deleteAndUnbindFileSystemEntity(parentEntity); + returnList.add(fileSystemHelperService.createDTO(parentEntity, authenticatedUser, null)); + } else { + // else some files are left. invisible or not. but the entity cannot be deleted. + log.info("Some visible entites could not be deleted but are visible."); + } + } else { + fileSystemHelperService.deleteAndUnbindFileSystemEntity(parentEntity); + returnList.add(fileSystemHelperService.createDTO(parentEntity, authenticatedUser, null)); + } + } + return new RecursiveReturn(foundInvisible, foundNonDeletable); + } - return returnList; + @Data + private static class RecursiveReturn { + private final boolean foundInvisibleEntities; + private final boolean foundNonDeletableEntities; } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java index 4a7ac4e9..37375d00 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -73,6 +73,28 @@ public void addPermissionsToSets(Set visibleForUserIds, Set visibleF } } + public void removeVisibilityRightsOfFileSystemEntityForUser(FileSystemEntity entity, User authenticatedUser) { + Query query = new Query().addCriteria(Criteria.where("fileSystemId").is(entity.getFileSystemId())); + Update newUpdate = new Update(); + + // user is either directly in the visible ids or in a group that is visible. + long[] newIdsWithoutCurrentUserId = Arrays.stream(entity.getVisibleForUserIds()).filter(userId -> userId != authenticatedUser.getUserId()).toArray(); + if (newIdsWithoutCurrentUserId.length != entity.getVisibleForUserIds().length) { + // apply it. + newUpdate.set("visibleForUserIds", newIdsWithoutCurrentUserId); + } + + // or user is in a group that can see the filesystem entity. + long[] newGroupIds = entity.getVisibleForGroupIds(); + if (newGroupIds.length != 0) { + for (Group group : authenticatedUser.getGroups()) { + newGroupIds = Arrays.stream(newGroupIds).filter(id -> id != group.getGroupId()).toArray(); + } + newUpdate.set("visibleForGroupIds", newGroupIds); + } + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); + } + public List getFolderContentsOfEntityAndPermissions(FileSystemEntity fileSystemEntity, User authenticatedUser, boolean needsToBeVisible, boolean needsToBeEditable) { long[] folderContentItemIds = fileSystemEntity.getItemIds(); List fileSystemEntities = new ArrayList<>(folderContentItemIds.length); @@ -242,7 +264,10 @@ public void recursivlyUpdateTimeStamps(FileSystemEntity currentEntity, User auth List parentFileSystemEntities = mongoTemplate.find(queryParentEntity, FileSystemEntity.class); if (parentFileSystemEntities.isEmpty()) { - if (!currentEntity.getPath().equals("/")) { + // no parents found -> either root folder or an exception + boolean isFile = currentEntity.isFile() && currentEntity.getTypeId() != FileSystemType.FOLDER.getId(); + boolean isRootFolder = !isFile && currentEntity.getPath().equals("/"); + if (!isRootFolder) { log.debug("Found no parent entity for a non root entity: " + currentEntity); throw new FileFighterDataException("Found no parent entity for a non root entity."); } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java index db9c736b..d0337a85 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java @@ -27,7 +27,7 @@ public FileSystemRestController(FileSystemRestServiceInterface fileSystemRestSer @GetMapping(FS_BASE_URI + "contents") public ResponseEntity> getContentsOfFolder( @RequestHeader(value = FS_PATH_HEADER, defaultValue = "/") String path, - @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken + @RequestHeader(value = "Authorization") String accessToken ) { log.info("Requested Folder contents of folder with path {}.", path); @@ -37,7 +37,7 @@ public ResponseEntity> getContentsOfFolder( @GetMapping(FS_BASE_URI + "{fsItemId}/info") public ResponseEntity getFileOrFolderInfo( @PathVariable long fsItemId, - @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken + @RequestHeader(value = "Authorization") String accessToken ) { log.info("Requested information about FileSystemItem with id {}.", fsItemId); @@ -47,18 +47,18 @@ public ResponseEntity getFileOrFolderInfo( @GetMapping(FS_BASE_URI + "search") public ResponseEntity searchFileOrFolderByName( @RequestParam(name = "name", defaultValue = "name") String name, - @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken + @RequestHeader(value = "Authorization") String accessToken ) { log.info("Searching for file or folder with name {}", name); return fileSystemRestService.findFileOrFolderByNameAndAccessToken(name, accessToken); } - @PostMapping(FS_BASE_URI+"upload") + @PostMapping(FS_BASE_URI + "upload") public ResponseEntity uploadFileOrFolder( @RequestBody FileSystemItemUpdate fileSystemItemUpdate, - @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken - ){ + @RequestHeader(value = "Authorization") String accessToken + ) { log.info("Tried uploading new FileSystemItem {}", fileSystemItemUpdate); return fileSystemRestService.uploadFileSystemItemWithAccessToken(fileSystemItemUpdate, accessToken); @@ -68,7 +68,7 @@ public ResponseEntity uploadFileOrFolder( public ResponseEntity updateExistingFileOrFolder( @PathVariable long fsItemId, @RequestBody FileSystemItemUpdate fileSystemItemUpdate, - @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken + @RequestHeader(value = "Authorization") String accessToken ) { log.info("Tried updating FileSystemItem {} with {}.", fsItemId, fileSystemItemUpdate); @@ -78,7 +78,7 @@ public ResponseEntity updateExistingFileOrFolder( @DeleteMapping(FS_BASE_URI + "{fsItemId}/delete") public ResponseEntity> deleteFileOrFolder( @PathVariable long fsItemId, - @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken + @RequestHeader(value = "Authorization") String accessToken ) { log.info("Tried deleting FileSystemItem with id {}", fsItemId); diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties new file mode 100644 index 00000000..d897a5af --- /dev/null +++ b/src/main/resources/application-test.properties @@ -0,0 +1 @@ +logging.level.root=DEBUG \ No newline at end of file diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index 26738e72..4c753d52 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -12,7 +12,6 @@ import io.cucumber.java.en.And; import io.cucumber.java.en.Given; import io.cucumber.java.en.Then; -import io.cucumber.java.en.When; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; @@ -195,6 +194,18 @@ public void responseContainsKeyAndValueOfAtLeast(String key, int value) throws J assertTrue(actualValue >= value); } + @And("response contains a valid timestamp at key {string}.") + public void responseContainsValidTimeStampAtKey(String key) throws JsonProcessingException { + JsonNode rootNode = objectMapper.readTree(latestResponse.getBody()); + long actualValue = rootNode.get(key).asLong(); + + long validRange = 10; + long expected = Instant.now().getEpochSecond(); + + assertTrue(expected - validRange < actualValue && actualValue < expected + 10); + } + + @And("response contains key {string} and a different value than {string}") public void responseContainsKeyAndADifferentValueThan(String key, String differentValue) throws JsonProcessingException { JsonNode rootNode = objectMapper.readTree(latestResponse.getBody()); @@ -231,4 +242,12 @@ public void runtimeUserExists() { } + @And("response contains the user with userId {long} at key {string}") + public void responseContainsTheUserWithUserIdAtKey(long userId, String key) throws JsonProcessingException { + JsonNode rootNode = objectMapper.readTree(latestResponse.getBody()); + JsonNode userNode = rootNode.get(key); + long actualUserId = userNode.get("userId").asLong(); + + assertEquals(userId, actualUserId); + } } diff --git a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java index a9bd80aa..70431104 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java @@ -30,7 +30,7 @@ public void userWithTokenWantsToDeleteTheFileSystemItemWithTheFileSystemId(Strin executeRestApiCall(HttpMethod.DELETE, BASE_API_URI + FS_BASE_URI + fileSystemId + "/delete", authHeader); } - @When("user with token {string} to get the info of fileSystemItem with the fileSystemId {long}") + @When("user with token {string} wants to get the info of fileSystemItem with the fileSystemId {long}") public void userWithTokenToGetTheInfoOfFileSystemItemWithTheFileSystemId(String accessTokenValue, long fileSystemId) { String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessTokenValue; diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index 43324099..c60b68db 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -38,7 +38,7 @@ class FileSystemBusinessServiceUnitTest { private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); private final FileSystemHelperService fileSystemHelperServiceMock = mock(FileSystemHelperService.class); - private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, userBusinessServiceMock, mongoTemplateMock); + private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, userBusinessServiceMock); @Test void getFolderContentsByPathThrows() { diff --git a/src/test/resources/deleteFileSystemItems.feature b/src/test/resources/deleteFileSystemItems.feature index 6a3599d9..362ce734 100644 --- a/src/test/resources/deleteFileSystemItems.feature +++ b/src/test/resources/deleteFileSystemItems.feature @@ -1,19 +1,19 @@ Feature: FileSystem Delete As a user i want to delete FileSystemItems. -Background: - Given database is empty - And runtime user exists - And user with userId 1234 exists and has username "Richard", password "badPassword" - And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" - And accessToken with value "900000" exists for user 1234 - And accessToken with value "222222" exists for user 420 - And user with userId 1234 has HomeFolder with Id 1234 - And user with userId 420 has HomeFolder with Id 420 - And fileSystemItem with the fileSystemId 42 exists, has owner with userId 1234 has the path "/bla" and name "bla" - And fileSystemItem with the fileSystemId 72 exists, has owner with userId 1234 and name "wow.txt" - And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 - And fileSystemItem with the fileSystemId 1234 is a folder and contains the fileSystemId 42 + Background: + Given database is empty + And runtime user exists + And user with userId 1234 exists and has username "Richard", password "badPassword" + And user with userId 420 exists and has username "Nasir", password "AlsoBadPassword" + And accessToken with value "900000" exists for user 1234 + And accessToken with value "222222" exists for user 420 + And user with userId 1234 has HomeFolder with Id 1234 + And user with userId 420 has HomeFolder with Id 420 + And fileSystemItem with the fileSystemId 42 exists, has owner with userId 1234 has the path "/bla" and name "bla" + And fileSystemItem with the fileSystemId 72 exists, has owner with userId 1234 and name "wow.txt" + And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 + And fileSystemItem with the fileSystemId 1234 is a folder and contains the fileSystemId 42 Scenario: File Deletion When user with token "900000" wants to see the content of folder with path "/Richard/bla" @@ -21,13 +21,15 @@ Background: And the response contains the file with fileSystemId 72 and name "wow.txt" When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 72 Then response status code is 200 - #And response contains key "message" and value "Successfully deleted all requested FileSystemItems." + And the response contains the file with fileSystemId 72 and name "wow.txt" When user with token "900000" wants to see the content of folder with path "/Richard/bla" Then the response contains an empty list for files and folders And response status code is 200 - When user with token "900000" to get the info of fileSystemItem with the fileSystemId 72 + # this is the folder that contained the file that was deleted. + When user with token "900000" wants to get the info of fileSystemItem with the fileSystemId 42 Then response status code is 200 - And response contains key "lastUpdated" and value of at least 1617885970 + And response contains a valid timestamp at key "lastUpdated". + And response contains the user with userId 1234 at key "lastUpdatedBy" Scenario: Folder and content Deletion When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 @@ -38,6 +40,7 @@ Background: Scenario: recursion Given fileSystemItem with the fileSystemId 0 exists, has owner with userId 1234 has the path "/foo" and name "foo" + And fileSystemItem with the fileSystemId 1234 is a folder and contains the fileSystemId 0 And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 And fileSystemItem with the fileSystemId 1 exists, has owner with userId 1234 has the path "/foo/bar" and name "bar" And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 @@ -50,6 +53,14 @@ Background: When user with token "900000" wants to see the content of folder with path "/Richard/foo" Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 + Then response status code is 200 + When user with token "900000" wants to see the content of folder with path "/Richard/bla" + Then response status code is 400 + And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + When user with token "900000" wants to get the info of fileSystemItem with the fileSystemId 72 + Then response status code is 400 + And response contains key "message" and value "FileSystemItem could not be found or you are not allowed to view it. FileSystemId was 72" When user with token "900000" wants to see the content of folder with path "/Richard" Then the response contains an empty list for files and folders And response status code is 200 @@ -73,10 +84,8 @@ Background: Then response status code is 400 And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 42432567" - # todo Scenario: Folder was created by runtime user. Given database is empty - # If this fails check the runtime user id. And fileSystemItem with the fileSystemId 0 exists, was created by user with userId 0 has the path "/" and name "HOME_kevin" And user with userId 123123123 exists and has username "kevin", password "securePassword123" And user with the userId 123123123 is allowed to VIEW the fileSystemItem with the fileSystemId 0 @@ -86,18 +95,19 @@ Background: Then response status code is 400 And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 0" - # todo Scenario: File was created by runtime user. Given database is empty + And user with userId 123123123 has HomeFolder with Id 420 + And fileSystemItem with the fileSystemId 420 is a folder and contains the fileSystemId 0 And user with userId 123123123 exists and has username "kevin", password "securePassword123" - And user with the userId 123123123 is allowed to VIEW the fileSystemItem with the fileSystemId 2 - And user with the userId 123123123 is allowed to EDIT the fileSystemItem with the fileSystemId 2 And accessToken with value "token" exists for user 123123123 And fileSystemItem with the fileSystemId 0 exists, was created by user with userId 123123123 has the path "/foo" and name "foo" And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 And fileSystemItem with the fileSystemId 1 exists, was created by user with userId 123123123 has the path "/foo/bar" and name "bar" And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 0 and has the name "veryImportantDocumentDon'tDeleteMePls.exe" + And user with the userId 123123123 is allowed to VIEW the fileSystemItem with the fileSystemId 2 + And user with the userId 123123123 is allowed to EDIT the fileSystemItem with the fileSystemId 2 When user with token "token" wants to delete the fileSystemItem with the fileSystemId 0 Then response status code is 200 - And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." + And the response contains an empty list for files and folders \ No newline at end of file From 9891c608ee307f259f8ebdafa3398b93914af7e7 Mon Sep 17 00:00:00 2001 From: open-schnick Date: Tue, 13 Apr 2021 20:59:48 +0200 Subject: [PATCH 19/20] Fixed tests. --- .../business/FileSystemBusinessService.java | 4 ++-- .../FileSystemBusinessServiceUnitTest.java | 22 +++++++++---------- .../FileSystemHelperServiceUnitTest.java | 12 +++++++--- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java index a77f1f02..ee866220 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java @@ -13,7 +13,7 @@ import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; -import lombok.Data; +import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; @@ -199,7 +199,7 @@ private RecursiveReturn recursivlyDeleteFileSystemEntity(FileSystemEntity parent return new RecursiveReturn(foundInvisible, foundNonDeletable); } - @Data + @AllArgsConstructor private static class RecursiveReturn { private final boolean foundInvisibleEntities; private final boolean foundNonDeletableEntities; diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index c60b68db..dfb192f0 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -15,10 +15,6 @@ import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import de.filefighter.rest.domain.user.group.Group; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.data.mongodb.core.query.Update; import java.util.ArrayList; import java.util.Arrays; @@ -35,7 +31,6 @@ class FileSystemBusinessServiceUnitTest { private final FileSystemRepository fileSystemRepositoryMock = mock(FileSystemRepository.class); private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); - private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); private final FileSystemHelperService fileSystemHelperServiceMock = mock(FileSystemHelperService.class); private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, userBusinessServiceMock); @@ -267,7 +262,6 @@ void deleteFileSystemItemByIdWorksWithInvisibleItemsOnly() { FileSystemItem folderItem = FileSystemItem.builder().build(); FileSystemItem file0 = FileSystemItem.builder().build(); - List dtoReturnList = Arrays.asList(folderItem, file0); when(fileSystemRepositoryMock.findByFileSystemId(requestId)).thenReturn(entityFolderToDelete); when(fileSystemHelperServiceMock.userIsAllowedToInteractWithFileSystemEntity(entityFolderToDelete, authenticatedUser, InteractionType.READ)).thenReturn(true); @@ -281,15 +275,19 @@ void deleteFileSystemItemByIdWorksWithInvisibleItemsOnly() { when(fileSystemHelperServiceMock.createDTO(entity0, authenticatedUser, null)).thenReturn(file0); // call function - fileSystemBusinessService.deleteFileSystemItemById(requestId, authenticatedUser); + List deletedItems = fileSystemBusinessService.deleteFileSystemItemById(requestId, authenticatedUser); // verify change of parent - ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); - ArgumentCaptor queryArgumentCaptor = ArgumentCaptor.forClass(Query.class); - verify(mongoTemplateMock, times(1)).findAndModify(queryArgumentCaptor.capture(), updateArgumentCaptor.capture(), eq(FileSystemEntity.class)); - assertEquals("Query: { \"fileSystemId\" : " + requestId + "}, Fields: {}, Sort: {}", queryArgumentCaptor.getValue().toString()); - assertEquals("{ \"$set\" : { \"visibleForUserIds\" : [ " + notUserId0 + ", " + notUserId1 + " ], \"visibleForGroupIds\" : [ " + Group.ADMIN.getGroupId() + " ] } }", updateArgumentCaptor.getValue().toString()); + + verify(fileSystemHelperServiceMock, times(1)).removeVisibilityRightsOfFileSystemEntityForUser(entityFolderToDelete, authenticatedUser); + assertEquals(0, deletedItems.size()); + + //ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); + //ArgumentCaptor queryArgumentCaptor = ArgumentCaptor.forClass(Query.class); + //verify(mongoTemplateMock, times(1)).findAndModify(queryArgumentCaptor.capture(), updateArgumentCaptor.capture(), eq(FileSystemEntity.class)); + //assertEquals("Query: { \"fileSystemId\" : " + requestId + "}, Fields: {}, Sort: {}", queryArgumentCaptor.getValue().toString()); + //assertEquals("{ \"$set\" : { \"visibleForUserIds\" : [ " + notUserId0 + ", " + notUserId1 + " ], \"visibleForGroupIds\" : [ " + Group.ADMIN.getGroupId() + " ] } }", updateArgumentCaptor.getValue().toString()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java index 5bc5a3c6..813bbe4f 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -18,6 +18,7 @@ import org.springframework.data.mongodb.core.query.Query; import java.util.ArrayList; +import java.util.List; import static de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService.DELETION_FAILED_MSG; import static de.filefighter.rest.domain.filesystem.data.InteractionType.*; @@ -265,7 +266,7 @@ void deleteAndUnbindFileSystemEntityThrows() { @SuppressWarnings("squid:S5778") @Test void recursivlyUpdateTimeStampsThrows() { - ArrayList entities = new ArrayList<>(); + List entities = new ArrayList<>(); entities.add(FileSystemEntity.builder().build()); entities.add(FileSystemEntity.builder().build()); when(mongoTemplateMock.find(any(), eq(FileSystemEntity.class))).thenReturn(entities); @@ -273,15 +274,20 @@ void recursivlyUpdateTimeStampsThrows() { FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> fileSystemHelperService.recursivlyUpdateTimeStamps(FileSystemEntity.builder().build(), User.builder().build(), 420)); assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Found more than one parent entity for entity.", ex.getMessage()); + + when(mongoTemplateMock.find(any(), any())).thenReturn(new ArrayList<>()); + + ex = assertThrows(FileFighterDataException.class, () -> + fileSystemHelperService.recursivlyUpdateTimeStamps(FileSystemEntity.builder().fileSystemId(123123).isFile(true).path("/").build(), User.builder().build(), 420)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Found no parent entity for a non root entity.", ex.getMessage()); } - // this is definitly not a good unit test. just for the 2% @Test void recursivlyUpdateTimeStampsWorks() { long fsItemId = 420; long fsItemId2 = 1234; ArrayList entities = new ArrayList<>(); - entities.add(FileSystemEntity.builder().fileSystemId(fsItemId2).path("/").build()); + entities.add(FileSystemEntity.builder().fileSystemId(fsItemId2).isFile(false).path("/").build()); ArrayList emptyList = new ArrayList<>(); when(mongoTemplateMock.find(eq(new Query().addCriteria(Criteria.where("itemIds").is(fsItemId))), eq(FileSystemEntity.class))).thenReturn(entities); From 60f8cbf3e4aa4eeb02f616d6970122046849f66c Mon Sep 17 00:00:00 2001 From: open-schnick Date: Tue, 13 Apr 2021 21:25:41 +0200 Subject: [PATCH 20/20] Added missing coverage. --- .../FileSystemBusinessServiceUnitTest.java | 6 ---- .../FileSystemHelperServiceUnitTest.java | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java index dfb192f0..e5bb5c70 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -282,12 +282,6 @@ void deleteFileSystemItemByIdWorksWithInvisibleItemsOnly() { verify(fileSystemHelperServiceMock, times(1)).removeVisibilityRightsOfFileSystemEntityForUser(entityFolderToDelete, authenticatedUser); assertEquals(0, deletedItems.size()); - - //ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); - //ArgumentCaptor queryArgumentCaptor = ArgumentCaptor.forClass(Query.class); - //verify(mongoTemplateMock, times(1)).findAndModify(queryArgumentCaptor.capture(), updateArgumentCaptor.capture(), eq(FileSystemEntity.class)); - //assertEquals("Query: { \"fileSystemId\" : " + requestId + "}, Fields: {}, Sort: {}", queryArgumentCaptor.getValue().toString()); - //assertEquals("{ \"$set\" : { \"visibleForUserIds\" : [ " + notUserId0 + ", " + notUserId1 + " ], \"visibleForGroupIds\" : [ " + Group.ADMIN.getGroupId() + " ] } }", updateArgumentCaptor.getValue().toString()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java index 813bbe4f..b1ab7e0e 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -13,9 +13,11 @@ import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import de.filefighter.rest.domain.user.group.Group; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; import java.util.ArrayList; import java.util.List; @@ -282,6 +284,34 @@ void recursivlyUpdateTimeStampsThrows() { assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Found no parent entity for a non root entity.", ex.getMessage()); } + @Test + void removeVisibilityRightsFromEntityWorks() { + long fsItemId = 123; + long userId = 123123; + long otherUserId = 120938; + long groupId = Group.FAMILY.getGroupId(); + long otherGroupId = Group.ADMIN.getGroupId(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder() + .fileSystemId(fsItemId) + .visibleForGroupIds(new long[]{groupId, otherGroupId}) + .visibleForUserIds(new long[]{userId, otherUserId}) + .build(); + User authenticatedUser = User.builder() + .userId(userId) + .groups(new Group[]{Group.FAMILY}) + .build(); + + // run it + fileSystemHelperService.removeVisibilityRightsOfFileSystemEntityForUser(fileSystemEntity, authenticatedUser); + + // verify it + ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); + ArgumentCaptor queryArgumentCaptor = ArgumentCaptor.forClass(Query.class); + verify(mongoTemplateMock, times(1)).findAndModify(queryArgumentCaptor.capture(), updateArgumentCaptor.capture(), eq(FileSystemEntity.class)); + assertEquals("Query: { \"fileSystemId\" : " + fsItemId + "}, Fields: {}, Sort: {}", queryArgumentCaptor.getValue().toString()); + assertEquals("{ \"$set\" : { \"visibleForUserIds\" : [ " + otherUserId + " ], \"visibleForGroupIds\" : [ " + otherGroupId + " ] } }", updateArgumentCaptor.getValue().toString()); + } + @Test void recursivlyUpdateTimeStampsWorks() { long fsItemId = 420;