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..dd193ec6 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 -> { @@ -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())); @@ -136,7 +132,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."); @@ -268,46 +264,55 @@ 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()}) + .visibleForUserIds(new long[]{1}) + .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()}) @@ -315,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/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..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 @@ -1,8 +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.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; @@ -13,9 +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.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 +20,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,32 +30,54 @@ public class FileSystemBusinessService { private final FileSystemRepository fileSystemRepository; - private final UserBusinessService userBusinessService; + 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, UserBusinessService userBusinessService, FileSystemTypeRepository fileSystemTypeRepository, MongoTemplate mongoTemplate) { + public FileSystemBusinessService(FileSystemRepository fileSystemRepository, FileSystemHelperService fileSystemHelperService, FileSystemTypeRepository fileSystemTypeRepository, UserBusinessService userBusinessService, MongoTemplate mongoTemplate) { this.fileSystemRepository = fileSystemRepository; - this.userBusinessService = userBusinessService; + 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("/") && !"".equals(pathWithoutSlashes[0])) - throw new FileSystemContentsNotAccessibleException("Path was in wrong format. Use a leading backslash."); + 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."); + + // 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(); + + pathToFind = "/"; + } else { + pathToFind = fileSystemPath[1]; + } + } catch (UserNotFoundException exception) { + throw new FileSystemContentsNotAccessibleException(); + } + } - String pathToFind = removeTrailingBackSlashes(path).toLowerCase(); + pathToFind = fileSystemHelperService.removeTrailingBackSlashes(pathToFind).toLowerCase(); // find the folder with matching path. ArrayList listOfFileSystemEntities = fileSystemRepository.findByPath(pathToFind); @@ -66,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() || !userIsAllowedToSeeFileSystemEntity(entity, authenticatedUser)); + // 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()); + + 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); - // now only own or shared folders are left. - ArrayList fileSystemItems = new ArrayList<>(); - String pathWithTrailingSlash = pathToFind.equals("/") ? pathToFind : (pathToFind + "/"); //NOSONAR + 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) getFolderContentsOfEntityAndPermissions(folder, authenticatedUser, true, false); for (FileSystemEntity fileSystemEntityInFolder : folderContents) { - fileSystemItems.add(this.createDTO(fileSystemEntityInFolder, authenticatedUser, pathWithTrailingSlash)); + fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, "/" + ownerOfRequestedFolder.getUsername() + pathToFind)); } + + return fileSystemItems; } - return fileSystemItems; } public FileSystemItem getFileSystemItemInfo(long fsItemId, User authenticatedUser) { @@ -90,10 +125,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 +136,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,19 +156,19 @@ 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. + // 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) { - 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 +176,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 +230,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 +252,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..86f2f8b0 --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java @@ -0,0 +1,232 @@ +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.getLastUpdatedBy() == RestConfiguration.RUNTIME_USER_ID) + return false; + + // user own the file. + if (fileSystemEntity.getOwnerId() == 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 absolutePathWithUsername) { + // for better responses and internal problem handling. + User ownerOfFileSystemItem; + User lastUpdatedByUser; + try { + 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); + } + + 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() + .lastUpdatedBy(lastUpdatedByUser) + .fileSystemId(fileSystemEntity.getFileSystemId()) + .owner(ownerOfFileSystemItem) + .lastUpdated(fileSystemEntity.getLastUpdated()) + .name(entityName) + .size(fileSystemEntity.getSize()) + .type(isAFolder ? FileSystemType.FOLDER : type) + .path(absolutePathWithUsername) + .isShared(isShared) + .mimeType(fileSystemEntity.getMimeType()) + .build(); + } + + public void createBasicFilesForNewUser(UserEntity registeredUserEntity) { + fileSystemRepository.save(FileSystemEntity + .builder() + .fileSystemId(generateNextFileSystemId()) + .ownerId(registeredUserEntity.getUserId()) + .lastUpdatedBy(RestConfiguration.RUNTIME_USER_ID) + .lastUpdated(getCurrentTimeStamp()) + .typeId(FileSystemType.FOLDER.getId()) + .isFile(false) + .name("HOME_" + registeredUserEntity.getUserId()) + .path("/") + .lastUpdated(Instant.now().getEpochSecond()) + .size(0) + .mimeType(null) + .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 Instant.now().getEpochSecond(); + } +} 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..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,8 +15,10 @@ 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/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..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 @@ -18,14 +18,15 @@ public class FileSystemEntity { private String path; @Builder.Default private long typeId = -1; + private String mimeType; 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/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/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/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..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 @@ -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,10 @@ 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 UserBusinessService userBusinessService = mock(UserBusinessService.class); + + private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, fileSystemHelperServiceMock, fileSystemTypeRepositoryMock, userBusinessService, mongoTemplateMock); @Test void getFolderContentsByPathThrows() { @@ -54,6 +57,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)); @@ -62,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); @@ -78,34 +82,22 @@ 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); + 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(fileSystemRepositoryMock.findByFileSystemId(fileIdInFolder)).thenReturn(FileSystemEntity.builder().lastUpdatedBy(userId).build()); when(userBusinessServiceMock.getUserById(userId)).thenReturn(User.builder().build()); ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(pathToRequest, user); 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 +113,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 +138,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; @@ -213,7 +154,9 @@ 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); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); FileFighterDataException ex1 = assertThrows(FileFighterDataException.class, () -> @@ -221,10 +164,15 @@ 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); + 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()); @@ -235,7 +183,9 @@ 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); when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); @@ -245,21 +195,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).lastUpdatedBy(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).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); } @Test @@ -270,17 +231,31 @@ 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 foundEntity = 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(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 +278,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 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); + 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(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); when(fileSystemTypeRepositoryMock.findFileSystemTypeById(-1)).thenReturn(FileSystemType.UNDEFINED); when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(visibleEditableEmptyFolder); @@ -338,10 +330,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 +353,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 @@ -385,169 +389,15 @@ 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); 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..84c877d7 --- /dev/null +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperServiceUnitTest.java @@ -0,0 +1,260 @@ +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().lastUpdatedBy(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().lastUpdatedBy(userId).build(); + + // user created fileSystemItem + assertTrue(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, READ)); + + // user created containing folder + fileSystemEntity.setLastUpdatedBy(1203891230); + 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().lastUpdatedBy(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().lastUpdatedBy(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)); + + 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.setLastUpdatedBy(1203891230); + 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().lastUpdatedBy(321).editableFoGroupIds(new long[]{1}).build(); + assertFalse(fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(fileSystemEntity, user, CHANGE)); + } + + @Test + void createDTOThrows() { + long userId = 420; + FileSystemEntity entity = FileSystemEntity.builder().lastUpdatedBy(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() + .lastUpdatedBy(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.getLastUpdatedBy().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;