diff --git a/pom.xml b/pom.xml index 126989f2..19115091 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ de.filefighter rest - 0.0.6 + 0.0.7 RestApi RestApi for FileFighter diff --git a/src/main/java/de/filefighter/rest/configuration/CorsConfig.java b/src/main/java/de/filefighter/rest/configuration/CorsConfig.java index 1f70a7b2..b8d03d50 100644 --- a/src/main/java/de/filefighter/rest/configuration/CorsConfig.java +++ b/src/main/java/de/filefighter/rest/configuration/CorsConfig.java @@ -12,21 +12,35 @@ @Configuration public class CorsConfig { - @Bean - @Profile("dev") - public CorsFilter corsFilter() { - final CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); - ArrayList allowedOrigins = new ArrayList<>(); - allowedOrigins.add("*"); - config.setAllowedOrigins(allowedOrigins); + private final ArrayList allowedMethods; - ArrayList allowedMethods = new ArrayList<>(); + public CorsConfig() { + this.allowedMethods = new ArrayList<>(); allowedMethods.add("HEAD"); allowedMethods.add("GET"); allowedMethods.add("POST"); allowedMethods.add("PUT"); allowedMethods.add("DELETE"); allowedMethods.add("OPTIONS"); + } + + @Bean + @Profile("dev") + public CorsFilter corsFilterDev() { + final CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); + ArrayList allowedOrigins = new ArrayList<>(); + allowedOrigins.add("*"); + config.setAllowedOrigins(allowedOrigins); + + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + + @Bean + @Profile({"prod","test"}) + public CorsFilter corsFilterProd() { + final CorsConfiguration config = new CorsConfiguration(); config.setAllowedMethods(allowedMethods); final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); diff --git a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java index 645cfa8d..de3114d6 100644 --- a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java +++ b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java @@ -77,7 +77,7 @@ CommandLineRunner cleanDataBase(UserRepository userRepository, FileSystemReposit CommandLineRunner createRuntimeUser(UserRepository userRepository) { return args -> log.info("Preloading system runtime user. {}", userRepository.save(UserEntity .builder() - .userId(0L) + .userId(RestConfiguration.RUNTIME_USER_ID) .username("FileFighter") .lowercaseUsername("filefighter") .password(null) @@ -102,7 +102,7 @@ CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepo log.info("Preloading default fsStructure: {} {}.", fileSystemRepository.save(FileSystemEntity .builder() - .createdByUserId(0) + .createdByUserId(RestConfiguration.RUNTIME_USER_ID) .fileSystemId(0) .isFile(false) .path("/") @@ -171,7 +171,7 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo log.info("Preloading default fsItems: {} {} {}.", fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(0) + .createdByUserId(RestConfiguration.RUNTIME_USER_ID) .fileSystemId(0) .isFile(false) .path("/") @@ -183,7 +183,7 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo .visibleForGroupIds(new long[]{FAMILY.getGroupId(), ADMIN.getGroupId()}) .build()), fileSystemRepository.save(FileSystemEntity.builder() - .createdByUserId(0) + .createdByUserId(RestConfiguration.RUNTIME_USER_ID) .fileSystemId(1) .isFile(false) .path("/") diff --git a/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java b/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java index eb239a69..9addcd05 100644 --- a/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java +++ b/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java @@ -10,6 +10,7 @@ public class RestConfiguration { public static final String FS_PATH_HEADER = "X-FF-PATH"; public static final String USER_BASE_URI = "/users/"; public static final String DEFAULT_ERROR_URI = "/error"; + public static final long RUNTIME_USER_ID = 0; private RestConfiguration(){ // Cannot be instantiated. diff --git a/src/main/java/de/filefighter/rest/rest/exceptions/DataBaseExceptionAdvise.java b/src/main/java/de/filefighter/rest/domain/common/exceptions/DataBaseExceptionAdvise.java similarity index 96% rename from src/main/java/de/filefighter/rest/rest/exceptions/DataBaseExceptionAdvise.java rename to src/main/java/de/filefighter/rest/domain/common/exceptions/DataBaseExceptionAdvise.java index 74fb256a..e2c70d5a 100644 --- a/src/main/java/de/filefighter/rest/rest/exceptions/DataBaseExceptionAdvise.java +++ b/src/main/java/de/filefighter/rest/domain/common/exceptions/DataBaseExceptionAdvise.java @@ -1,4 +1,4 @@ -package de.filefighter.rest.rest.exceptions; +package de.filefighter.rest.domain.common.exceptions; import de.filefighter.rest.domain.health.business.SystemHealthBusinessService; import de.filefighter.rest.domain.health.data.SystemHealth; diff --git a/src/main/java/de/filefighter/rest/domain/common/exceptions/FileFighterDataException.java b/src/main/java/de/filefighter/rest/domain/common/exceptions/FileFighterDataException.java new file mode 100644 index 00000000..49d3dbd7 --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/common/exceptions/FileFighterDataException.java @@ -0,0 +1,16 @@ +package de.filefighter.rest.domain.common.exceptions; + +import org.springframework.dao.DataAccessException; + +public class FileFighterDataException extends DataAccessException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "Internal Error occurred."; + + public FileFighterDataException(String msg) { + super(ERROR_MESSAGE_PREFIX + " " + msg); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; + } +} diff --git a/src/main/java/de/filefighter/rest/domain/common/exceptions/FileFighterException.java b/src/main/java/de/filefighter/rest/domain/common/exceptions/FileFighterException.java new file mode 100644 index 00000000..c85b2d15 --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/common/exceptions/FileFighterException.java @@ -0,0 +1,7 @@ +package de.filefighter.rest.domain.common.exceptions; + +public interface FileFighterException { + static String getErrorMessagePrefix() { + throw new IllegalArgumentException("Custom exception should overwrite this message."); + } +} diff --git a/src/main/java/de/filefighter/rest/domain/common/InputSanitizerService.java b/src/main/java/de/filefighter/rest/domain/common/exceptions/InputSanitizerService.java similarity index 91% rename from src/main/java/de/filefighter/rest/domain/common/InputSanitizerService.java rename to src/main/java/de/filefighter/rest/domain/common/exceptions/InputSanitizerService.java index db0e1bf7..9218dcf3 100644 --- a/src/main/java/de/filefighter/rest/domain/common/InputSanitizerService.java +++ b/src/main/java/de/filefighter/rest/domain/common/exceptions/InputSanitizerService.java @@ -1,6 +1,5 @@ -package de.filefighter.rest.domain.common; +package de.filefighter.rest.domain.common.exceptions; -import de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import org.springframework.stereotype.Service; @Service diff --git a/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsAdvise.java b/src/main/java/de/filefighter/rest/domain/common/exceptions/RequestDidntMeetFormalRequirementsAdvise.java similarity index 94% rename from src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsAdvise.java rename to src/main/java/de/filefighter/rest/domain/common/exceptions/RequestDidntMeetFormalRequirementsAdvise.java index d5ec6199..c7351495 100644 --- a/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsAdvise.java +++ b/src/main/java/de/filefighter/rest/domain/common/exceptions/RequestDidntMeetFormalRequirementsAdvise.java @@ -1,4 +1,4 @@ -package de.filefighter.rest.rest.exceptions; +package de.filefighter.rest.domain.common.exceptions; import de.filefighter.rest.rest.ServerResponse; import lombok.extern.log4j.Log4j2; diff --git a/src/main/java/de/filefighter/rest/domain/common/exceptions/RequestDidntMeetFormalRequirementsException.java b/src/main/java/de/filefighter/rest/domain/common/exceptions/RequestDidntMeetFormalRequirementsException.java new file mode 100644 index 00000000..106f0afd --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/common/exceptions/RequestDidntMeetFormalRequirementsException.java @@ -0,0 +1,18 @@ +package de.filefighter.rest.domain.common.exceptions; + +public class RequestDidntMeetFormalRequirementsException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "Request didnt meet formal requirements."; + + public RequestDidntMeetFormalRequirementsException() { + super(ERROR_MESSAGE_PREFIX); + } + + public RequestDidntMeetFormalRequirementsException(String reason) { + super(ERROR_MESSAGE_PREFIX + " " + reason); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; + } +} 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 311889ca..5e61c529 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,25 +1,32 @@ package de.filefighter.rest.domain.filesystem.business; -import de.filefighter.rest.domain.common.InputSanitizerService; +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.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.exceptions.FileSystemContentsNotAccessibleException; +import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemCouldNotBeDeletedException; import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemNotFoundException; import de.filefighter.rest.domain.filesystem.type.FileSystemType; import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.data.persistence.UserEntity; +import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import de.filefighter.rest.domain.user.group.Groups; -import de.filefighter.rest.rest.exceptions.FileFighterDataException; import lombok.extern.log4j.Log4j2; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Service; import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.LongStream; @Log4j2 @Service @@ -28,11 +35,15 @@ public class FileSystemBusinessService { private final FileSystemRepository fileSystemRepository; private final UserBusinessService userBusinessService; private final FileSystemTypeRepository fileSystemTypeRepository; + private final MongoTemplate mongoTemplate; - public FileSystemBusinessService(FileSystemRepository fileSystemRepository, UserBusinessService userBusinessService, FileSystemTypeRepository fileSystemTypeRepository) { + private static final String DELETION_FAILED_MSG = "Failed to delete FileSystemEntity with id "; + + public FileSystemBusinessService(FileSystemRepository fileSystemRepository, UserBusinessService userBusinessService, FileSystemTypeRepository fileSystemTypeRepository, MongoTemplate mongoTemplate) { this.fileSystemRepository = fileSystemRepository; this.userBusinessService = userBusinessService; this.fileSystemTypeRepository = fileSystemTypeRepository; + this.mongoTemplate = mongoTemplate; } public List getFolderContentsByPath(String path, User authenticatedUser) { @@ -61,29 +72,16 @@ public List getFolderContentsByPath(String path, User authentica throw new FileSystemContentsNotAccessibleException(); // now only own or shared folders are left. - return getFolderContentsOfEntities(listOfFileSystemEntities, authenticatedUser, pathToFind); - } - - public List getFolderContentsOfEntities(List listOfFileSystemEntities, User authenticatedUser, String pathToFind) { - List fileSystemItems = new ArrayList<>(); - - for (FileSystemEntity fileSystemEntity : listOfFileSystemEntities) { - long[] folderContentItemIds = fileSystemEntity.getItemIds(); - - // check if the contents are visible. - 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 (userIsAllowedToSeeFileSystemEntity(fileSystemEntityInFolder, authenticatedUser)) { - String pathWithTrailingSlash = pathToFind.equals("/") ? pathToFind : (pathToFind + "/"); //NOSONAR - fileSystemItems.add(this.createDTO(fileSystemEntityInFolder, authenticatedUser, pathWithTrailingSlash)); - } + ArrayList fileSystemItems = new ArrayList<>(); + String pathWithTrailingSlash = pathToFind.equals("/") ? pathToFind : (pathToFind + "/"); //NOSONAR + + // 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)); } } - return fileSystemItems; } @@ -98,24 +96,195 @@ public FileSystemItem getFileSystemItemInfo(long fsItemId, User authenticatedUse return createDTO(fileSystemEntity, authenticatedUser, null); } - 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); + public boolean deleteFileSystemItemById(long fsItemId, User authenticatedUser) { + FileSystemEntity fileSystemEntity = fileSystemRepository.findByFileSystemId(fsItemId); + if (null == fileSystemEntity) + throw new FileSystemItemCouldNotBeDeletedException(fsItemId); + + if (!(userIsAllowedToSeeFileSystemEntity(fileSystemEntity, authenticatedUser) && userIsAllowedToEditFileSystemEntity(fileSystemEntity, authenticatedUser))) + throw new FileSystemItemCouldNotBeDeletedException(fsItemId); + + return recursivelyDeleteFileSystemEntity(fileSystemEntity, authenticatedUser); + } + + /** + * Deletes the folder recursively. + * + * @param parentFileSystemEntity parent fileSystem entity, can be both folder and file. + * @param authenticatedUser user that wants to delete + * @return true if the folder and all the folders / items were deleted. + */ + @SuppressWarnings("squid:S3776") + public boolean recursivelyDeleteFileSystemEntity(FileSystemEntity parentFileSystemEntity, User authenticatedUser) { + boolean everythingWasDeleted = false; + if (parentFileSystemEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(parentFileSystemEntity.getTypeId()) != FileSystemType.FOLDER) { + // 1. Base of recursion + // Delete File and update parentFolder. + Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); + if (countDeleted != 1) + throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); + + // update. + 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); + + if (null == foundEntities || foundEntities.isEmpty()) { + // 2. Base of recursion + Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); + if (countDeleted != 1) + throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); + + everythingWasDeleted = true; + } else { + ArrayList 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)) { + + // Folder. + if (!childrenEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(childrenEntity.getTypeId()) == FileSystemType.FOLDER) { + // Step of recursion + if (recursivelyDeleteFileSystemEntity(childrenEntity, authenticatedUser)) { + // there is no need to remove the child entity, because it was already deleted in the recursive function call. + // if it wasn't removed (if = false) we don't remove the folder and we don't delete it. + updatedItemIds.remove(childrenEntity.getFileSystemId()); + deletedEntities++; + } + // File + } else if (childrenEntity.isFile() && fileSystemTypeRepository.findFileSystemTypeById(childrenEntity.getTypeId()) != FileSystemType.FOLDER) { + // 3. Base of recursion + Long countDeleted = fileSystemRepository.deleteByFileSystemId(childrenEntity.getFileSystemId()); + if (countDeleted != 1) + throw new FileFighterDataException(DELETION_FAILED_MSG + childrenEntity.getFileSystemId()); + + updatedItemIds.remove(childrenEntity.getFileSystemId()); + deletedEntities++; + } else { + throw new FileFighterDataException("FileType was wrong. " + childrenEntity); + } + } + // otherwise the item stays as it is. + } else { + invisibleEntities.add(childrenEntity); + } + } + + // some entities could not be deleted because he is not allowed or cannot see them. + if (foundEntities.size() != deletedEntities) { + + // update itemIds. + parentFileSystemEntity.setItemIds(updatedItemIds.stream().mapToLong(Long::longValue).toArray()); + + // save changes of parentFolder to db. + Query query = new Query().addCriteria(Criteria.where("fileSystemId").is(parentFileSystemEntity.getFileSystemId())); + Update newUpdate = new Update().set("itemIds", parentFileSystemEntity.getItemIds()); + + // only problem appears when there are only invisible entities left. + boolean onlyInvisibleEntitiesAreLeftAfterRemovingDeletableEntities = !invisibleEntities.isEmpty() && (invisibleEntities.size() == updatedItemIds.size()); + if (onlyInvisibleEntitiesAreLeftAfterRemovingDeletableEntities) { + // some files do not include the current user to see them. By adding up all these permissions and applying them the the parent folder + // we can make sure, that the views of the other users stay the same, while the current user cannot see the folder anymore. + // EdgeCase: that the user who requests the deletion is owner of the folder but cannot see cannot happen anymore, + // because he the owner has all rights on all files except ones created by runtime users. + parentFileSystemEntity = sumUpAllPermissionsOfFileSystemEntities(parentFileSystemEntity, invisibleEntities); + + newUpdate.set("visibleForUserIds", parentFileSystemEntity.getVisibleForUserIds()) + .set("visibleForGroupIds", parentFileSystemEntity.getVisibleForGroupIds()) + .set("editableForUserIds", parentFileSystemEntity.getEditableForUserIds()) + .set("editableForGroupIds", parentFileSystemEntity.getEditableFoGroupIds()); + } + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); + } else { + // No FileSystemEntities left in folder. -> can be deleted. + Long countDeleted = fileSystemRepository.deleteByFileSystemId(parentFileSystemEntity.getFileSystemId()); + if (countDeleted != 1) + throw new FileFighterDataException(DELETION_FAILED_MSG + parentFileSystemEntity.getFileSystemId()); + + everythingWasDeleted = true; + } + } + } else { + throw new FileFighterDataException("FileType was wrong. " + parentFileSystemEntity); } - return pathToFind; + 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; } - // TODO: also for edit. 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())) + if (null != fileSystemEntity.getOwnerIds() && Arrays.stream(fileSystemEntity.getOwnerIds()).asDoubleStream().anyMatch(id -> id == authenticatedUser.getUserId())) return true; // user got the item shared. @@ -136,15 +305,62 @@ public boolean userIsAllowedToSeeFileSystemEntity(FileSystemEntity fileSystemEnt 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 (Groups 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) { - User ownerOfFileSystemItem = userBusinessService.getUserById(fileSystemEntity.getCreatedByUserId()); + // 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() - .createdByUserId(fileSystemEntity.getCreatedByUserId()) + .createdByUser(ownerOfFileSystemItem) .fileSystemId(fileSystemEntity.getFileSystemId()) .lastUpdated(fileSystemEntity.getLastUpdated()) .name(fileSystemEntity.getName()) 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 c0b9f015..1768d341 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 @@ -1,6 +1,7 @@ package de.filefighter.rest.domain.filesystem.data.dto; import de.filefighter.rest.domain.filesystem.type.FileSystemType; +import de.filefighter.rest.domain.user.data.dto.User; import lombok.Builder; import lombok.Data; @@ -14,7 +15,7 @@ public class FileSystemItem { private String name; private boolean isShared; private double size; - private long createdByUserId; //uploadedBy + private User createdByUser; //uploadedBy private long lastUpdated; private FileSystemType type; 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 0287885a..8cc710d9 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 @@ -16,11 +16,13 @@ public class FileSystemEntity { private long fileSystemId = -1; private String name; private String path; - private long typeId; + @Builder.Default + private long typeId = -1; private double size; - private boolean isFile; private long lastUpdated; @Builder.Default + private boolean isFile = true; + @Builder.Default private long createdByUserId = -1; @Builder.Default private long[] ownerIds = new long[0]; diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemRepository.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemRepository.java index e73415c4..bd7bfc19 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemRepository.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/data/persistence/FileSystemRepository.java @@ -9,4 +9,6 @@ public interface FileSystemRepository extends MongoRepository { FileSystemEntity findByFileSystemId(long fileSystemId); ArrayList findByPath(String path); + Long deleteByFileSystemId (long fileSystemId); } + diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemContentsNotAccessibleException.java b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemContentsNotAccessibleException.java index a7d17554..77b27701 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemContentsNotAccessibleException.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemContentsNotAccessibleException.java @@ -1,12 +1,21 @@ package de.filefighter.rest.domain.filesystem.exceptions; -public class FileSystemContentsNotAccessibleException extends RuntimeException { +import de.filefighter.rest.domain.common.exceptions.FileFighterException; + +public class FileSystemContentsNotAccessibleException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "Folder does not exist, or you are not allowed to see the folder."; + public FileSystemContentsNotAccessibleException() { - super("Folder does not exist, or you are not allowed to see the folder."); + super(ERROR_MESSAGE_PREFIX); } public FileSystemContentsNotAccessibleException(String reason) { - super("Folder contents could not be displayed. "+reason); + super(ERROR_MESSAGE_PREFIX + " " + reason); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemCouldNotBeDeletedAdvise.java b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemCouldNotBeDeletedAdvise.java new file mode 100644 index 00000000..2fbfc67f --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemCouldNotBeDeletedAdvise.java @@ -0,0 +1,24 @@ +package de.filefighter.rest.domain.filesystem.exceptions; + +import de.filefighter.rest.rest.ServerResponse; +import lombok.extern.log4j.Log4j2; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; + +@Log4j2 +@ControllerAdvice +public class FileSystemItemCouldNotBeDeletedAdvise { + + @ResponseBody + @ExceptionHandler(FileSystemItemCouldNotBeDeletedException.class) + @ResponseStatus(HttpStatus.BAD_REQUEST) + ResponseEntity fileSystemContentsNotAccessibleAdvise(FileSystemItemCouldNotBeDeletedException ex) { + log.warn(ex.getMessage()); + return new ResponseEntity<>(new ServerResponse(HttpStatus.BAD_REQUEST, ex.getMessage()), HttpStatus.BAD_REQUEST); + } + +} \ No newline at end of file diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemCouldNotBeDeletedException.java b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemCouldNotBeDeletedException.java new file mode 100644 index 00000000..175b5f30 --- /dev/null +++ b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemCouldNotBeDeletedException.java @@ -0,0 +1,24 @@ +package de.filefighter.rest.domain.filesystem.exceptions; + +import de.filefighter.rest.domain.common.exceptions.FileFighterException; + +public class FileSystemItemCouldNotBeDeletedException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "FileSystemEntity could not be deleted."; + + public FileSystemItemCouldNotBeDeletedException() { + super(ERROR_MESSAGE_PREFIX); + } + + public FileSystemItemCouldNotBeDeletedException(long fileSystemId) { + super(ERROR_MESSAGE_PREFIX+" FileSystemId was "+fileSystemId); + } + + public FileSystemItemCouldNotBeDeletedException(String reason) { + super(ERROR_MESSAGE_PREFIX + " " + reason); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; + } +} diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemNotFoundException.java b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemNotFoundException.java index ac36521d..ef9d2393 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemNotFoundException.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/exceptions/FileSystemItemNotFoundException.java @@ -1,12 +1,20 @@ package de.filefighter.rest.domain.filesystem.exceptions; -public class FileSystemItemNotFoundException extends RuntimeException { +import de.filefighter.rest.domain.common.exceptions.FileFighterException; + +public class FileSystemItemNotFoundException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "FileSystemItem could not be found or you are not allowed to view it."; public FileSystemItemNotFoundException() { - super("FileSystemItem could not be found or you are not allowed to view it."); + super(ERROR_MESSAGE_PREFIX); } public FileSystemItemNotFoundException(long fsItemId) { - super("FileSystemItem with id " + fsItemId + " could not be found or you are not allowed to view it."); + super(ERROR_MESSAGE_PREFIX + " FileSystemId was " + fsItemId); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; } } 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 10f32569..966763cd 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,6 +1,6 @@ package de.filefighter.rest.domain.filesystem.rest; -import de.filefighter.rest.domain.common.InputSanitizerService; +import de.filefighter.rest.domain.common.exceptions.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; @@ -70,7 +70,17 @@ public ResponseEntity updatedFileSystemItemWithIdAndAccessToken( } @Override - public ResponseEntity deleteFileSystemItemWithIdAndAccessToken(long fsItemId, String accessToken) { - return null; + public ResponseEntity deleteFileSystemItemWithIdAndAccessToken(long fsItemId, String accessTokenValue) { + String cleanHeader = inputSanitizerService.sanitizeRequestHeader(AUTHORIZATION_BEARER_PREFIX, accessTokenValue); + String cleanValue = inputSanitizerService.sanitizeTokenValue(cleanHeader); + AccessToken accessToken = accessTokenBusinessService.findAccessTokenByValue(cleanValue); + User authenticatedUser = userAuthorizationService.authenticateUserWithAccessToken(accessToken); + + boolean everythingWasDeleted = fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); + if(everythingWasDeleted){ + return new ResponseEntity<>(new ServerResponse(HttpStatus.OK, "Successfully deleted all requested FileSystemItems."), HttpStatus.OK); + }else{ + return new ResponseEntity<>(new ServerResponse(HttpStatus.OK, "Not everything got deleted, because you are not allowed to edit some files."), HttpStatus.OK); + } } } diff --git a/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java index 73e1bfd1..dec599ad 100644 --- a/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessService.java @@ -1,11 +1,11 @@ package de.filefighter.rest.domain.token.business; +import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.token.data.persistence.AccessTokenEntity; import de.filefighter.rest.domain.token.data.persistence.AccessTokenRepository; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException; -import de.filefighter.rest.rest.exceptions.FileFighterDataException; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; diff --git a/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDTOService.java b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDTOService.java index 12f7ba23..97846961 100644 --- a/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDTOService.java +++ b/src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDTOService.java @@ -30,7 +30,7 @@ public AccessToken createDto(AccessTokenEntity entity) { public AccessTokenEntity findEntity(AccessToken dto) { AccessTokenEntity accessTokenEntity = accessTokenRepository.findByUserIdAndValue(dto.getUserId(), dto.getTokenValue()); if (null == accessTokenEntity) - throw new AccessTokenNotFoundException("AccessTokenEntity does not exist for AccessToken with userId "+ dto.getUserId()+"."); + throw new AccessTokenNotFoundException(dto.getUserId()); return accessTokenEntity; } diff --git a/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundException.java b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundException.java index adecc922..c9685d33 100644 --- a/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundException.java +++ b/src/main/java/de/filefighter/rest/domain/token/exceptions/AccessTokenNotFoundException.java @@ -1,8 +1,16 @@ package de.filefighter.rest.domain.token.exceptions; -public class AccessTokenNotFoundException extends RuntimeException { +import de.filefighter.rest.domain.common.exceptions.FileFighterException; - public AccessTokenNotFoundException(String reason) { - super(reason); +public class AccessTokenNotFoundException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "AccessToken could not be found."; + + public AccessTokenNotFoundException(long userId) { + super(ERROR_MESSAGE_PREFIX + " UserId was " + userId); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; } } diff --git a/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java b/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java index 75580651..b0dacabc 100644 --- a/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java +++ b/src/main/java/de/filefighter/rest/domain/user/business/UserAuthorizationService.java @@ -1,13 +1,13 @@ package de.filefighter.rest.domain.user.business; -import de.filefighter.rest.domain.common.InputSanitizerService; +import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; +import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.data.persistence.UserEntity; import de.filefighter.rest.domain.user.data.persistence.UserRepository; import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException; import de.filefighter.rest.domain.user.group.Groups; -import de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; 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 6f3cd967..fae9914a 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.InputSanitizerService.stringIsValid; +import static de.filefighter.rest.domain.common.exceptions.InputSanitizerService.stringIsValid; @Service public class UserBusinessService { @@ -77,7 +77,7 @@ public RefreshToken getRefreshTokenForUser(User user) { public User findUserByUsername(String username) { UserEntity entity = getUserWithUsername(username); if (null == entity) - throw new UserNotFoundException("User with username '" + username + "' not found."); + throw new UserNotFoundException(username); return userDtoService.createDto(entity); } diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java index 39bbc12e..21d351a5 100644 --- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java +++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotAuthenticatedException.java @@ -1,11 +1,20 @@ package de.filefighter.rest.domain.user.exceptions; -public class UserNotAuthenticatedException extends RuntimeException{ - public UserNotAuthenticatedException(String reason){ - super("User could not be authenticated. "+reason); +import de.filefighter.rest.domain.common.exceptions.FileFighterException; + +public class UserNotAuthenticatedException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "User could not be authenticated."; + + public UserNotAuthenticatedException(String reason) { + super(ERROR_MESSAGE_PREFIX + " " + reason); + } + + public UserNotAuthenticatedException(long userId) { + super(ERROR_MESSAGE_PREFIX+" UserId was "+userId); } - public UserNotAuthenticatedException(long id){ - super("User with the id "+id+" could not be authenticated."); + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; } } diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java index f1d187af..407734a4 100644 --- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java +++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotFoundException.java @@ -1,16 +1,24 @@ package de.filefighter.rest.domain.user.exceptions; -public class UserNotFoundException extends RuntimeException { +import de.filefighter.rest.domain.common.exceptions.FileFighterException; - public UserNotFoundException(){ - super("User not found."); +public class UserNotFoundException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "User not found."; + + public UserNotFoundException() { + super(ERROR_MESSAGE_PREFIX); + } + + public UserNotFoundException(long userId) { + super(ERROR_MESSAGE_PREFIX + " UserId was " + userId); } - public UserNotFoundException(long id) { - super("Could not find user with userId " + id+"."); + public UserNotFoundException(String username) { + super(ERROR_MESSAGE_PREFIX + " Username was " + username); } - public UserNotFoundException(String message) { - super(message); + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; } } diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotRegisteredException.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotRegisteredException.java index d43677a7..ef19061f 100644 --- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotRegisteredException.java +++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotRegisteredException.java @@ -1,12 +1,20 @@ package de.filefighter.rest.domain.user.exceptions; -public class UserNotRegisteredException extends RuntimeException{ +import de.filefighter.rest.domain.common.exceptions.FileFighterException; + +public class UserNotRegisteredException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "User could not be registered."; public UserNotRegisteredException() { - super("User could not be registered."); + super(ERROR_MESSAGE_PREFIX); } public UserNotRegisteredException(String reason) { - super("User could not be registered. "+reason); + super(ERROR_MESSAGE_PREFIX + " " + reason); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; } } diff --git a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotUpdatedException.java b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotUpdatedException.java index 0c29e4c8..f1b13f93 100644 --- a/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotUpdatedException.java +++ b/src/main/java/de/filefighter/rest/domain/user/exceptions/UserNotUpdatedException.java @@ -1,11 +1,20 @@ package de.filefighter.rest.domain.user.exceptions; -public class UserNotUpdatedException extends RuntimeException{ +import de.filefighter.rest.domain.common.exceptions.FileFighterException; + +public class UserNotUpdatedException extends RuntimeException implements FileFighterException { + + private static final String ERROR_MESSAGE_PREFIX = "User could not get updated."; + public UserNotUpdatedException() { - super("User could not get updated"); + super(ERROR_MESSAGE_PREFIX); } public UserNotUpdatedException(String reason) { - super("User could not get updated. "+reason); + super(ERROR_MESSAGE_PREFIX + " " + reason); + } + + public static String getErrorMessagePrefix() { + return ERROR_MESSAGE_PREFIX; } } diff --git a/src/main/java/de/filefighter/rest/domain/user/group/GroupRepository.java b/src/main/java/de/filefighter/rest/domain/user/group/GroupRepository.java index f5a6a340..c6514e71 100644 --- a/src/main/java/de/filefighter/rest/domain/user/group/GroupRepository.java +++ b/src/main/java/de/filefighter/rest/domain/user/group/GroupRepository.java @@ -12,7 +12,7 @@ public Groups getGroupById(long id) { return group; } } - throw new IllegalArgumentException("id "+id+" doesnt belong to a group."); + throw new IllegalArgumentException("GroupId "+id+" doesnt belong to a group."); } public Groups[] getGroupsByIds(long... ids){ 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 50dde960..343f2e6e 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,6 +1,6 @@ package de.filefighter.rest.domain.user.rest; -import de.filefighter.rest.domain.common.InputSanitizerService; +import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; import de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; import de.filefighter.rest.domain.token.data.dto.AccessToken; diff --git a/src/main/java/de/filefighter/rest/rest/exceptions/FileFighterDataException.java b/src/main/java/de/filefighter/rest/rest/exceptions/FileFighterDataException.java deleted file mode 100644 index c0169acd..00000000 --- a/src/main/java/de/filefighter/rest/rest/exceptions/FileFighterDataException.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.filefighter.rest.rest.exceptions; - -import org.springframework.core.NestedRuntimeException; - -public class FileFighterDataException extends NestedRuntimeException { - public FileFighterDataException(String msg) { - super("Internal Error occurred. " + msg); - } -} diff --git a/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsException.java b/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsException.java deleted file mode 100644 index ae38e01c..00000000 --- a/src/main/java/de/filefighter/rest/rest/exceptions/RequestDidntMeetFormalRequirementsException.java +++ /dev/null @@ -1,12 +0,0 @@ -package de.filefighter.rest.rest.exceptions; - -public class RequestDidntMeetFormalRequirementsException extends RuntimeException{ - - public RequestDidntMeetFormalRequirementsException() { - super("Request didnt meet formal requirements."); - } - - public RequestDidntMeetFormalRequirementsException(String message) { - super("Request didnt meet formal requirements. "+message); - } -} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3ba536ef..24907479 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,6 +7,6 @@ spring.data.mongodb.database=filefighter spring.data.mongodb.host=localhost spring.data.mongodb.port=27017 #-------------------Custom------------------ -filefighter.version=0.0.6 -filefighter.date=20.12.2020 +filefighter.version=0.0.7 +filefighter.date=09.01.2021 filefighter.disable-password-check=false diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index 78583eb8..d0dca520 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -35,11 +35,11 @@ public class CommonCucumberSteps extends RestApplicationIntegrationTest { MongoTemplate mongoTemplate; @Autowired - public CommonCucumberSteps(UserRepository userRepository, AccessTokenRepository accessTokenRepository, FileSystemRepository fileSystemRepository) { + public CommonCucumberSteps(UserRepository userRepository, AccessTokenRepository accessTokenRepository, FileSystemRepository fileSystemRepository, ObjectMapper objectMapper) { this.userRepository = userRepository; this.accessTokenRepository = accessTokenRepository; this.fileSystemRepository = fileSystemRepository; - this.objectMapper = new ObjectMapper(); + this.objectMapper = objectMapper; } @Given("database is empty") @@ -89,12 +89,13 @@ public void userWithIdIsInGroupWithId(long userId, long groupId) { mongoTemplate.findAndModify(query, newUpdate, UserEntity.class); } - @And("fileSystemItem with the fileSystemId {long} exists, was created by user with userId {long} and has the path {string}") - public void fileSystemItemWithTheFileSystemIdExistsAndHasThePath(long fileSystemId, long userId, String path) { + @And("fileSystemItem with the fileSystemId {long} exists, was created by user with userId {long} has the path {string} and name {string}") + public void fileSystemItemWithTheFileSystemIdExistsAndHasThePath(long fileSystemId, long userId, String path, String name) { fileSystemRepository.save(FileSystemEntity.builder() .path(path) .createdByUserId(userId) .fileSystemId(fileSystemId) + .name(name) .build()); } @@ -110,12 +111,24 @@ public void fileSystemItemWithTheFileSystemIdExistsAndHasTheName(long fileSystem @And("fileSystemItem with the fileSystemId {long} is a folder and contains the fileSystemId {long}") public void fileSystemItemWithTheFileSystemIdIsAFolderAndContainsTheFileSystemId(long fileSystemIdFolder, long fileSystemId) { Query query = new Query(); - Update newUpdate = new Update().set("itemIds", new long[]{fileSystemId}); + Update newUpdate = new Update() + .push("itemIds", fileSystemId) + .set("isFile", false) + .set("typeId", 0); query.addCriteria(Criteria.where("fileSystemId").is(fileSystemIdFolder)); mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } + @And("fileSystemItem with the fileSystemId {long} is a folder") + public void fileSystemItemWithTheFileSystemIdIsAFolder(long fileSystemId) { + Query query = new Query(); + Update newUpdate = new Update().set("typeId", 0).set("isFile", false); + query.addCriteria(Criteria.where("fileSystemId").is(fileSystemId)); + + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); + } + @And("user with userId {long} is owner of file or folder with fileSystemId {long}") public void userIsOwnerOfFileOrFolderWithId(long userId, long fsItemId) { FileSystemEntity fileSystemEntity = fileSystemRepository.findByFileSystemId(fsItemId); diff --git a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java index 5c65d49f..e76d906e 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CrudFileSystemSteps.java @@ -13,11 +13,20 @@ public class CrudFileSystemSteps extends RestApplicationIntegrationTest { @When("user requests fileSystemInfo with fileSystemId {long} and accessTokenValue {string}") public void userRequestsFileSystemInfoWithFileSystemIdAndUserId(long fileSystemId, String accessTokenValue) { String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessTokenValue; - String url = BASE_API_URI + USER_BASE_URI + "auth"; HashMap authHeader = new HashMap<>(); authHeader.put("Authorization", authHeaderString); executeRestApiCall(HttpMethod.GET, BASE_API_URI + FS_BASE_URI + fileSystemId + "/info", authHeader); } + + @When("user with token {string} wants to delete the fileSystemItem with the fileSystemId {long}") + public void userWithTokenWantsToDeleteTheFileSystemItemWithTheFileSystemId(String accessTokenValue, long fileSystemId) { + String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessTokenValue; + + HashMap authHeader = new HashMap<>(); + authHeader.put("Authorization", authHeaderString); + + executeRestApiCall(HttpMethod.DELETE, BASE_API_URI + FS_BASE_URI + fileSystemId + "/delete", authHeader); + } } diff --git a/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java b/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java index ed0552eb..ed29ab26 100644 --- a/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/UserAuthorizationSteps.java @@ -29,8 +29,8 @@ public class UserAuthorizationSteps extends RestApplicationIntegrationTest { private final AccessTokenRepository accessTokenRepository; @Autowired - public UserAuthorizationSteps(AccessTokenRepository accessTokenRepository) { - this.objectMapper = new ObjectMapper(); + public UserAuthorizationSteps(AccessTokenRepository accessTokenRepository, ObjectMapper objectMapper) { + this.objectMapper = objectMapper; this.accessTokenRepository = accessTokenRepository; } diff --git a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java index 6d24c1e6..73bfec8e 100644 --- a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java @@ -13,6 +13,7 @@ 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 { @@ -46,7 +47,7 @@ public void theResponseContainsTheFileWithIdAndName(long fsItemId, String name) for (JsonNode node : rootNode) { if (node.get("fileSystemId").asLong() == fsItemId && node.get("name").asText().equals(name) && - node.get("type").asText().equals("FOLDER")) + !node.get("type").asText().equals("FOLDER")) found = true; } assertTrue(found); @@ -60,4 +61,39 @@ public void theResponseContainsAnEmptyListForFilesAndFolders() throws JsonProces assertTrue(rootNode.isEmpty()); } + + @And("the response does not contains the file with fileSystemId {long} and name {string}") + public void theResponseNotContainsTheFileWithFileSystemIdAndName(long fsItemId, String name) throws JsonProcessingException { + + ArrayNode rootNode = (ArrayNode) objectMapper.readTree(latestResponse.getBody()); + if (!rootNode.isContainerNode()) + throw new AssertionError("Response was not an Array."); + + // if it's empty is also okay. + if (!rootNode.isEmpty()) { + boolean found = false; + for (JsonNode node : rootNode) { + if (node.get("fileSystemId").asLong() == fsItemId && node.get("name").asText().equals(name)) { + found = true; + } + } + assertFalse(found); + } + } + + @And("the response contains the folder with fileSystemId {long} and name {string}") + public void theResponseContainsTheFolderWithFileSystemIdAndName(long fileSystemId, 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("fileSystemId").asLong() == fileSystemId && + node.get("name").asText().equals(name) && + node.get("type").asText().equals("FOLDER")) + found = true; + } + assertTrue(found); + } } 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 af9ab1d2..4e7cb15f 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,7 @@ package de.filefighter.rest.domain.common; -import de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; +import de.filefighter.rest.domain.common.exceptions.InputSanitizerService; +import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -25,11 +26,11 @@ void sanitizeStringThrows() { RequestDidntMeetFormalRequirementsException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> InputSanitizerService.sanitizeString(string0)); - assertEquals("Request didnt meet formal requirements. String was empty.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> InputSanitizerService.sanitizeString(string1)); - assertEquals("Request didnt meet formal requirements. String was empty.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); } @Test @@ -53,19 +54,19 @@ void sanitizeRequestHeaderThrows() { RequestDidntMeetFormalRequirementsException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeRequestHeader(header, string0)); - assertEquals("Request didnt meet formal requirements. 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("Request didnt meet formal requirements. 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("Request didnt meet formal requirements. 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("Request didnt meet formal requirements. 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()); } @@ -87,11 +88,11 @@ void sanitizeTokenThrows() { RequestDidntMeetFormalRequirementsException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeTokenValue(string0)); - assertEquals("Request didnt meet formal requirements. String was empty.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> inputSanitizerService.sanitizeTokenValue(string1)); - assertEquals("Request didnt meet formal requirements. String was empty.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix()+" String was empty.", ex.getMessage()); } 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 517bd312..8a8a6c4e 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,30 +1,36 @@ 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.exceptions.FileSystemContentsNotAccessibleException; +import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemCouldNotBeDeletedException; import de.filefighter.rest.domain.filesystem.exceptions.FileSystemItemNotFoundException; import de.filefighter.rest.domain.filesystem.type.FileSystemType; import de.filefighter.rest.domain.filesystem.type.FileSystemTypeRepository; import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; +import de.filefighter.rest.domain.user.exceptions.UserNotFoundException; import de.filefighter.rest.domain.user.group.Groups; -import de.filefighter.rest.rest.exceptions.FileFighterDataException; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Update; import java.util.ArrayList; import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; class FileSystemBusinessServiceUnitTest { private final FileSystemRepository fileSystemRepositoryMock = mock(FileSystemRepository.class); private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); - private final FileSystemTypeRepository fileSystemTypeRepository = mock(FileSystemTypeRepository.class); - private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, userBusinessServiceMock, fileSystemTypeRepository); + private final FileSystemTypeRepository fileSystemTypeRepositoryMock = mock(FileSystemTypeRepository.class); + private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); + private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, userBusinessServiceMock, fileSystemTypeRepositoryMock, mongoTemplateMock); @Test void getFolderContentsByPathThrows() { @@ -37,21 +43,21 @@ void getFolderContentsByPathThrows() { FileSystemContentsNotAccessibleException ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(notValid, dummyUser)); - assertEquals("Folder contents could not be displayed. Path was not valid.", ex.getMessage()); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix() + " Path was not valid.", ex.getMessage()); ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(wrongFormat, dummyUser)); - assertEquals("Folder contents could not be displayed. Path was in wrong format.", ex.getMessage()); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix() + " Path was in wrong format.", ex.getMessage()); ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(wrongFormat1, dummyUser)); - assertEquals("Folder contents could not be displayed. Path was in wrong format. Use a leading backslash.", ex.getMessage()); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix() + " Path was in wrong format. Use a leading backslash.", ex.getMessage()); when(fileSystemRepositoryMock.findByPath(validPath)).thenReturn(null); ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(validPath, dummyUser)); - assertEquals("Folder does not exist, or you are not allowed to see the folder.", ex.getMessage()); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix(), ex.getMessage()); ArrayList fileSystemEntityArrayList = new ArrayList<>(); fileSystemEntityArrayList.add(FileSystemEntity.builder().isFile(true).build()); @@ -62,7 +68,7 @@ void getFolderContentsByPathThrows() { ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> fileSystemBusinessService.getFolderContentsByPath(validPath, dummyUser)); - assertEquals("Folder does not exist, or you are not allowed to see the folder.", ex.getMessage()); + assertEquals(FileSystemContentsNotAccessibleException.getErrorMessagePrefix(), ex.getMessage()); } @Test @@ -72,7 +78,7 @@ void getFolderContentsByPathWorks() { long userId = 420; long fileIdInFolder = 123; User user = User.builder().userId(userId).build(); - FileSystemEntity foundFolder = FileSystemEntity.builder().createdByUserId(userId).itemIds(new long[]{fileIdInFolder}).build(); + FileSystemEntity foundFolder = FileSystemEntity.builder().isFile(false).createdByUserId(userId).typeId(0).itemIds(new long[]{fileIdInFolder}).build(); ArrayList entities = new ArrayList<>(); entities.add(foundFolder); @@ -86,38 +92,275 @@ void getFolderContentsByPathWorks() { @Test void getFolderContentsOfEntityThrows() { - long fileSystemId = 420; + long fileSystemId0 = 420; + long fileSystemId1 = 1234; User authenticatedUser = User.builder().build(); - FileSystemEntity foundFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId}).build(); - ArrayList arrayList = new ArrayList<>(); - arrayList.add(foundFolder); + FileSystemEntity rootFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId0, fileSystemId1}).build(); - when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId)).thenReturn(null); + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId0)).thenReturn(FileSystemEntity.builder().build()); + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId1)).thenReturn(null); FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> - fileSystemBusinessService.getFolderContentsOfEntities(arrayList, authenticatedUser, "/")); - assertEquals("Internal Error occurred. FolderContents expected fileSystemItem with id " + fileSystemId + " but was empty.", ex.getMessage()); + 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; + long fileSystemId0 = 420; + + User authenticatedUser = User.builder().build(); + + FileSystemEntity rootFile = FileSystemEntity.builder().fileSystemId(fsItemId).build(); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(rootFile); + FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> + fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFile, authenticatedUser)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); + + FileSystemEntity rootFolder = FileSystemEntity.builder().fileSystemId(fsItemId).isFile(false).typeId(0).build(); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + + 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()); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + + ex = assertThrows(FileFighterDataException.class, () -> + fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFolder1, authenticatedUser)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fileSystemId0, ex.getMessage()); + + when(fileSystemRepositoryMock.deleteByFileSystemId(fileSystemId0)).thenReturn(1L); + ex = assertThrows(FileFighterDataException.class, () -> + fileSystemBusinessService.recursivelyDeleteFileSystemEntity(rootFolder1, authenticatedUser)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Failed to delete FileSystemEntity with id " + fsItemId, ex.getMessage()); } @Test void getFolderContentsOfEntityWorks() { - long userId = 420; + 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; + long userId = 123123123; + User authenticatedUser = User.builder().userId(userId).build(); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(null); + FileSystemItemCouldNotBeDeletedException ex = assertThrows(FileSystemItemCouldNotBeDeletedException.class, () -> + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); + assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + fsItemId, ex.getMessage()); + + FileSystemEntity foundEntity = FileSystemEntity.builder().build(); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + ex = assertThrows(FileSystemItemCouldNotBeDeletedException.class, () -> + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); + assertEquals(FileSystemItemCouldNotBeDeletedException.getErrorMessagePrefix() + " FileSystemId was " + fsItemId, ex.getMessage()); + + foundEntity = FileSystemEntity.builder().createdByUserId(userId).isFile(true).typeId(0).build(); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + FileFighterDataException ex1 = assertThrows(FileFighterDataException.class, () -> + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FileType was wrong. " + foundEntity, ex1.getMessage()); + + long folderContentId = 13287132; + FileSystemEntity folderContentEntity = FileSystemEntity.builder().createdByUserId(userId).isFile(true).typeId(0).build(); + when(fileSystemRepositoryMock.findByFileSystemId(folderContentId)).thenReturn(folderContentEntity); + foundEntity = FileSystemEntity.builder().typeId(0).isFile(false).createdByUserId(userId).itemIds(new long[]{folderContentId}).build(); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + ex1 = assertThrows(FileFighterDataException.class, () -> + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser)); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " FileType was wrong. " + folderContentEntity, ex1.getMessage()); + } + + @Test + void deleteFileSystemItemByIdWorksWithFile() { + long fsItemId = 12332123; + long userId = 243724328; + User authenticatedUser = User.builder().userId(userId).build(); + FileSystemEntity foundEntity = FileSystemEntity.builder().fileSystemId(fsItemId).typeId(1).isFile(true).createdByUserId(userId).build(); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); + + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(fsItemId); + } + + @Test + void deleteFileSystemItemByIdWorksWithFolder() { + long fsItemId = 12332123; + long userId = 243724328; + User authenticatedUser = User.builder().userId(userId).build(); + FileSystemEntity foundEntity = FileSystemEntity.builder().fileSystemId(fsItemId).typeId(0).isFile(false).createdByUserId(userId).build(); + + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + 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); + } + + @Test + void deleteFileSystemItemByIdWorksWithFolderWhenAllItemsCanBeDeleted() { + long fsItemId = 12332123; + long userId = 243724328; + User authenticatedUser = User.builder().userId(userId).build(); + long itemId0 = 1233212; + long itemId1 = 9872317; + long itemId2 = 1923847; + FileSystemEntity fileSystemEntity0 = FileSystemEntity.builder().isFile(false).typeId(0).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(); + + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(fileSystemEntity0); + when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(fileSystemEntity1); + when(fileSystemRepositoryMock.findByFileSystemId(itemId2)).thenReturn(fileSystemEntity2); + + when(fileSystemRepositoryMock.deleteByFileSystemId(fsItemId)).thenReturn(1L); + when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); + when(fileSystemRepositoryMock.deleteByFileSystemId(itemId1)).thenReturn(1L); + when(fileSystemRepositoryMock.deleteByFileSystemId(itemId2)).thenReturn(1L); + + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); + + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(fsItemId); + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId0); // empty folder + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId1); + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId2); + } + + @Test + void deleteFileSystemItemByIdWorksWithFolderWhenSomeItemsCannotBeDeleted() { + long fsItemId = 12332123; + long userId = 243724328; + long itemId0 = 1233212; + long itemId1 = 9872317; + long itemId2 = 1923847; + long itemId3 = 9817232; + User authenticatedUser = User.builder().userId(userId).build(); + FileSystemEntity 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 invisibleFile = FileSystemEntity.builder().fileSystemId(itemId1).isFile(true).build(); + FileSystemEntity visibleNonEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).visibleForUserIds(new long[]{userId}).isFile(true).build(); + FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId3).createdByUserId(userId).isFile(true).build(); + + when(fileSystemRepositoryMock.findByFileSystemId(fsItemId)).thenReturn(foundEntity); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(0)).thenReturn(FileSystemType.FOLDER); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(-1)).thenReturn(FileSystemType.UNDEFINED); + when(fileSystemRepositoryMock.findByFileSystemId(itemId0)).thenReturn(visibleEditableEmptyFolder); + when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(invisibleFile); + when(fileSystemRepositoryMock.findByFileSystemId(itemId2)).thenReturn(visibleNonEditableFile); + when(fileSystemRepositoryMock.findByFileSystemId(itemId3)).thenReturn(visibleEditableFile); + when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); + when(fileSystemRepositoryMock.deleteByFileSystemId(itemId3)).thenReturn(1L); + + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); + + // verify deleted entities. + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId0); + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId3); + + ArgumentCaptor updateArgumentCaptor = ArgumentCaptor.forClass(Update.class); + verify(mongoTemplateMock, times(1)).findAndModify(any(), updateArgumentCaptor.capture(), any()); + assertEquals("{ \"$set\" : { \"itemIds\" : [ " + itemId1 + ", " + itemId2 + " ] } }", updateArgumentCaptor.getValue().toString()); // no better way to assert requested changes. + } + + @Test + void deleteFileSystemItemByIdWorksWithFolderOnlyInvisible() { + long fsItemId = 12332123; + long userId = 243724328; User authenticatedUser = User.builder().userId(userId).build(); - FileSystemEntity foundFolder = FileSystemEntity.builder().itemIds(new long[]{0, 1, 2, 3, 4}).build(); - ArrayList arrayList = new ArrayList<>(); - arrayList.add(foundFolder); - - FileSystemEntity dummyEntity = FileSystemEntity.builder().createdByUserId(userId).build(); - when(fileSystemRepositoryMock.findByFileSystemId(0)).thenReturn(dummyEntity); - when(fileSystemRepositoryMock.findByFileSystemId(1)).thenReturn(dummyEntity); - when(fileSystemRepositoryMock.findByFileSystemId(2)).thenReturn(dummyEntity); - when(fileSystemRepositoryMock.findByFileSystemId(3)).thenReturn(dummyEntity); - when(fileSystemRepositoryMock.findByFileSystemId(4)).thenReturn(FileSystemEntity.builder().createdByUserId(userId + 1).build()); - when(userBusinessServiceMock.getUserById(userId)).thenReturn(User.builder().userId(userId).build()); - - ArrayList actual = (ArrayList) fileSystemBusinessService.getFolderContentsOfEntities(arrayList, authenticatedUser, "/"); - assertEquals(4, actual.size()); + 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 invisibleFile = FileSystemEntity.builder().fileSystemId(itemId1).isFile(true).visibleForUserIds(new long[]{userId - 1}).build(); + FileSystemEntity visibleEditableFile = FileSystemEntity.builder().fileSystemId(itemId2).createdByUserId(userId).isFile(true).build(); + + 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); + when(fileSystemRepositoryMock.findByFileSystemId(itemId1)).thenReturn(invisibleFile); + when(fileSystemRepositoryMock.findByFileSystemId(itemId2)).thenReturn(visibleEditableFile); + when(fileSystemRepositoryMock.deleteByFileSystemId(itemId0)).thenReturn(1L); + when(fileSystemRepositoryMock.deleteByFileSystemId(itemId2)).thenReturn(1L); + + fileSystemBusinessService.deleteFileSystemItemById(fsItemId, authenticatedUser); + + // verify deleted entities. + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId0); + verify(fileSystemRepositoryMock, times(1)).deleteByFileSystemId(itemId2); + + 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. } @Test @@ -128,12 +371,12 @@ void getFileSystemItemInfoThrows() { when(fileSystemRepositoryMock.findByFileSystemId(id)).thenReturn(null); FileSystemItemNotFoundException ex = assertThrows(FileSystemItemNotFoundException.class, () -> fileSystemBusinessService.getFileSystemItemInfo(id, dummyUser)); - assertEquals("FileSystemItem with id " + id + " could not be found or you are not allowed to view it.", ex.getMessage()); + assertEquals(FileSystemItemNotFoundException.getErrorMessagePrefix() + " FileSystemId was " + id, ex.getMessage()); when(fileSystemRepositoryMock.findByFileSystemId(id)).thenReturn(FileSystemEntity.builder().build()); ex = assertThrows(FileSystemItemNotFoundException.class, () -> fileSystemBusinessService.getFileSystemItemInfo(id, dummyUser)); - assertEquals("FileSystemItem with id " + id + " could not be found or you are not allowed to view it.", ex.getMessage()); + assertEquals(FileSystemItemNotFoundException.getErrorMessagePrefix() + " FileSystemId was " + id, ex.getMessage()); } @Test @@ -148,12 +391,11 @@ void getFileSystemItemInfoWorks() { when(fileSystemRepositoryMock.findByFileSystemId(id)).thenReturn(entity); FileSystemItem fileSystemItem = fileSystemBusinessService.getFileSystemItemInfo(id, dummyUser); assertEquals(name, fileSystemItem.getName()); - assertEquals(userId, fileSystemItem.getCreatedByUserId()); + assertEquals(userId, fileSystemItem.getCreatedByUser().getUserId()); assertNull(fileSystemItem.getPath()); assertFalse(fileSystemItem.isShared()); } - @Test void removeTrailingWhiteSpaces() { String doesNotRemove0 = "/"; @@ -191,8 +433,8 @@ void userIsAllowedToSeeFileSystemEntity() { assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); //user is in group - user = User.builder().groups(new Groups[]{Groups.ADMIN}).build(); - fileSystemEntity = FileSystemEntity.builder().visibleForGroupIds(new long[]{1}).build(); + user = User.builder().userId(123897123).groups(new Groups[]{Groups.ADMIN}).build(); + fileSystemEntity = FileSystemEntity.builder().fileSystemId(9872347).visibleForGroupIds(new long[]{1}).build(); assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); // user is not allowed. @@ -201,6 +443,51 @@ void userIsAllowedToSeeFileSystemEntity() { 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 Groups[]{Groups.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 Groups[]{Groups.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; @@ -229,11 +516,11 @@ void createDTOWorks() { .build(); when(userBusinessServiceMock.getUserById(createdByUserId)).thenReturn(userThatCreatedFile); - when(fileSystemTypeRepository.findFileSystemTypeById(typeId)).thenReturn(FileSystemType.UNDEFINED); + when(fileSystemTypeRepositoryMock.findFileSystemTypeById(typeId)).thenReturn(FileSystemType.UNDEFINED); FileSystemItem actual = fileSystemBusinessService.createDTO(fileSystemEntity, authenticatedUser, basePath); - assertEquals(createdByUserId, actual.getCreatedByUserId()); + assertEquals(createdByUserId, actual.getCreatedByUser().getUserId()); assertEquals(fileSystemId, actual.getFileSystemId()); assertEquals(lastUpdated, actual.getLastUpdated()); assertEquals(name, actual.getName()); @@ -247,7 +534,7 @@ void createDTOWorks() { void getTotalFileSizeThrows() { when(fileSystemRepositoryMock.findByPath("/")).thenReturn(null); FileFighterDataException ex = assertThrows(FileFighterDataException.class, fileSystemBusinessService::getTotalFileSize); - assertEquals("Internal Error occurred. Couldn't find any Home directories!", ex.getMessage()); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " Couldn't find any Home directories!", ex.getMessage()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java index 1086bc3e..cd496223 100644 --- a/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenBusinessServiceUnitTest.java @@ -1,11 +1,11 @@ package de.filefighter.rest.domain.token.business; +import de.filefighter.rest.domain.common.exceptions.FileFighterDataException; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.token.data.persistence.AccessTokenEntity; import de.filefighter.rest.domain.token.data.persistence.AccessTokenRepository; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException; -import de.filefighter.rest.rest.exceptions.FileFighterDataException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -97,7 +97,7 @@ void getValidAccessTokenForUserWhenTokenDeletionFails() { FileFighterDataException ex = assertThrows(FileFighterDataException.class, () -> accessTokenBusinessService.getValidAccessTokenForUser(dummyUser)); - assertEquals("Internal Error occurred. AccessToken for userId " + dummyId + " could not be deleted.", ex.getMessage()); + assertEquals(FileFighterDataException.getErrorMessagePrefix() + " AccessToken for userId " + dummyId + " could not be deleted.", ex.getMessage()); } @Test @@ -110,7 +110,7 @@ void findAccessTokenByValueAndUserIdWithTokenNotFound() { UserNotAuthenticatedException ex = assertThrows(UserNotAuthenticatedException.class, () -> accessTokenBusinessService.findAccessTokenByValueAndUserId(tokenValue, userId) ); - assertEquals("User with the id " + userId + " could not be authenticated.", ex.getMessage()); + assertEquals(UserNotAuthenticatedException.getErrorMessagePrefix() + " UserId was " + userId, ex.getMessage()); } @Test @@ -137,7 +137,7 @@ void findAccessTokenByValueThrowsException() { UserNotAuthenticatedException ex = assertThrows(UserNotAuthenticatedException.class, () -> accessTokenBusinessService.findAccessTokenByValue(validFormat) ); - assertEquals("User could not be authenticated. AccessToken not found.", ex.getMessage()); + assertEquals(UserNotAuthenticatedException.getErrorMessagePrefix()+" AccessToken not found.", ex.getMessage()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenDtoServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenDtoServiceUnitTest.java index 5e886136..bf919335 100644 --- a/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenDtoServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/token/business/AccessTokenDtoServiceUnitTest.java @@ -48,7 +48,7 @@ void findEntityNotSuccessfully() { AccessTokenNotFoundException ex = assertThrows(AccessTokenNotFoundException.class, () -> accessTokenDtoService.findEntity(dummyToken) ); - assertEquals("AccessTokenEntity does not exist for AccessToken with userId "+userId+".", ex.getMessage()); + assertEquals(AccessTokenNotFoundException.getErrorMessagePrefix() + " UserId was " + userId, ex.getMessage()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java index 39ff9032..2d594c14 100644 --- a/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/user/business/UserAuthorizationServiceUnitTest.java @@ -1,12 +1,12 @@ package de.filefighter.rest.domain.user.business; +import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.data.persistence.UserEntity; import de.filefighter.rest.domain.user.data.persistence.UserRepository; import de.filefighter.rest.domain.user.exceptions.UserNotAuthenticatedException; import de.filefighter.rest.domain.user.group.Groups; -import de.filefighter.rest.rest.exceptions.RequestDidntMeetFormalRequirementsException; import org.junit.jupiter.api.Test; import static de.filefighter.rest.configuration.RestConfiguration.AUTHORIZATION_BEARER_PREFIX; @@ -30,17 +30,17 @@ void authenticateUserWithUsernameAndPasswordThrows() { RuntimeException ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> userAuthorizationService.authenticateUserWithUsernameAndPassword(matchesButIsNotSupportedEncoding)); - assertEquals("Request didnt meet formal requirements. Found unsupported character in header.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Found unsupported character in header.", ex.getMessage()); ex = assertThrows(RequestDidntMeetFormalRequirementsException.class, () -> userAuthorizationService.authenticateUserWithUsernameAndPassword(onlyContainsUsername)); - assertEquals("Request didnt meet formal requirements. Credentials didnt meet formal requirements.", ex.getMessage()); + assertEquals(RequestDidntMeetFormalRequirementsException.getErrorMessagePrefix() + " Credentials didnt meet formal requirements.", ex.getMessage()); when(userRepositoryMock.findByLowercaseUsernameAndPassword("user", "password")).thenReturn(null); ex = assertThrows(UserNotAuthenticatedException.class, () -> userAuthorizationService.authenticateUserWithUsernameAndPassword(matchesButUserWasNotFound)); - assertEquals("User could not be authenticated. No User found with this username and password.", ex.getMessage()); + assertEquals(UserNotAuthenticatedException.getErrorMessagePrefix() + " No User found with this username and password.", ex.getMessage()); } @Test @@ -65,7 +65,7 @@ void authenticateUserWithRefreshTokenThrowsExceptions() { UserNotAuthenticatedException ex = assertThrows(UserNotAuthenticatedException.class, () -> userAuthorizationService.authenticateUserWithRefreshToken(authString)); - assertEquals("User could not be authenticated. No user found for this Refresh Token.", ex.getMessage()); + assertEquals(UserNotAuthenticatedException.getErrorMessagePrefix() + " No user found for this Refresh Token.", ex.getMessage()); } @Test @@ -91,7 +91,7 @@ void authenticateUserWithAccessTokenThrows() { UserNotAuthenticatedException ex = assertThrows(UserNotAuthenticatedException.class, () -> userAuthorizationService.authenticateUserWithAccessToken(accessToken)); - assertEquals("User with the id " + userId + " could not be authenticated.", ex.getMessage()); + assertEquals(UserNotAuthenticatedException.getErrorMessagePrefix() + " UserId was " + userId, ex.getMessage()); } @Test @@ -114,13 +114,13 @@ void authenticateUserWithAccessTokenAndGroupThrows() { UserNotAuthenticatedException ex = assertThrows(UserNotAuthenticatedException.class, () -> userAuthorizationService.authenticateUserWithAccessTokenAndGroup(accessToken, Groups.ADMIN)); - assertEquals("User with the id " + userId + " could not be authenticated.", ex.getMessage()); + assertEquals(UserNotAuthenticatedException.getErrorMessagePrefix() + " UserId was " + userId, ex.getMessage()); when(userRepositoryMock.findByUserId(userId)).thenReturn(UserEntity.builder().groupIds(new long[]{0}).build()); ex = assertThrows(UserNotAuthenticatedException.class, () -> userAuthorizationService.authenticateUserWithAccessTokenAndGroup(accessToken, Groups.ADMIN)); - assertEquals("User could not be authenticated. Not in necessary group.", ex.getMessage()); + assertEquals(UserNotAuthenticatedException.getErrorMessagePrefix()+" Not in necessary group.", ex.getMessage()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java index 067d6662..948e5e93 100644 --- a/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/user/business/UserBusinessServiceUnitTest.java @@ -65,7 +65,7 @@ void getRefreshTokenForUserWithoutUser() { UserNotFoundException ex = assertThrows(UserNotFoundException.class, () -> userBusinessService.getRefreshTokenForUser(dummyUser) ); - assertEquals("Could not find user with userId " + userId + ".", ex.getMessage()); + assertEquals(UserNotFoundException.getErrorMessagePrefix() + " UserId was " + userId, ex.getMessage()); } @Test @@ -109,7 +109,7 @@ void getUserByIdThrowsExceptions() { UserNotFoundException ex = assertThrows(UserNotFoundException.class, () -> userBusinessService.getUserById(id)); - assertEquals("Could not find user with userId " + id + ".", ex.getMessage()); + assertEquals(UserNotFoundException.getErrorMessagePrefix() + " UserId was " + id, ex.getMessage()); } @Test @@ -134,7 +134,7 @@ void findUserByUsernameThrowsExceptions() { UserNotFoundException exception = assertThrows(UserNotFoundException.class, () -> userBusinessService.findUserByUsername(validFormat) ); - assertEquals("User with username '" + validFormat + "' not found.", exception.getMessage()); + assertEquals(UserNotFoundException.getErrorMessagePrefix() + " Username was " + validFormat, exception.getMessage()); } @Test @@ -195,7 +195,7 @@ void registerNewUserThrows() { userRegisterForm.setUsername(notValidUsername); UserNotRegisteredException ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. Username was not valid.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix() + " Username was not valid.", ex.getMessage()); // username taken userRegisterForm.setUsername(username); @@ -204,7 +204,7 @@ void registerNewUserThrows() { ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. Username already taken.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix() + " Username already taken.", ex.getMessage()); //passwords empty when(userRepositoryMock.findByLowercaseUsername(username.toLowerCase())).thenReturn(null); @@ -212,27 +212,27 @@ void registerNewUserThrows() { userRegisterForm.setPassword(""); ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. Wanted to change password, but password was not valid.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix() + " Wanted to change password, but password was not valid.", ex.getMessage()); userRegisterForm.setPassword("somepassword"); userRegisterForm.setConfirmationPassword(""); ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. Wanted to change password, but password was not valid.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix() + " Wanted to change password, but password was not valid.", ex.getMessage()); //Passwords not valid userRegisterForm.setConfirmationPassword(notValidPassword); userRegisterForm.setPassword(notValidPassword); ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix() + " Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number.", ex.getMessage()); //Passwords do not match. userRegisterForm.setPassword(password); ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. Passwords do not match.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix()+" Passwords do not match.", ex.getMessage()); //Username exists in password. userRegisterForm.setUsername("Password123"); @@ -240,7 +240,7 @@ void registerNewUserThrows() { ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. Username must not appear in password.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix()+" Username must not appear in password.", ex.getMessage()); // group does not exist userRegisterForm.setUsername(username); @@ -249,12 +249,12 @@ void registerNewUserThrows() { ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. One or more groups do not exist.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix()+" One or more groups do not exist.", ex.getMessage()); userRegisterForm.setGroupIds(new long[]{Groups.SYSTEM.getGroupId()}); ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); - assertEquals("User could not be registered. New users cannot be in group '" + Groups.SYSTEM.getDisplayName() + "'.", ex.getMessage()); + assertEquals(UserNotRegisteredException.getErrorMessagePrefix()+" New users cannot be in group '" + Groups.SYSTEM.getDisplayName() + "'.", ex.getMessage()); } @Test @@ -285,34 +285,34 @@ void updateUserThrows() { UserNotUpdatedException ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. No updates specified.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" No updates specified.", ex.getMessage()); UserRegisterForm userRegisterForm1 = UserRegisterForm.builder().build(); User authenticatedUser1 = User.builder().groups(null).build(); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm1, authenticatedUser1)); - assertEquals("User could not get updated. Authenticated User is not allowed.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Authenticated User is not allowed.", ex.getMessage()); authenticatedUser.setGroups(new Groups[]{Groups.UNDEFINED}); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm1, authenticatedUser)); - assertEquals("User could not get updated. Only Admins are allowed to update other users.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Only Admins are allowed to update other users.", ex.getMessage()); //user not found with id. authenticatedUser.setGroups(new Groups[]{Groups.ADMIN}); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm1, authenticatedUser)); - assertEquals("User could not get updated. User does not exist, use register endpoint.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" User does not exist, use register endpoint.", ex.getMessage()); when(userRepositoryMock.findByUserId(userId)).thenReturn(UserEntity.builder().groupIds(new long[]{Groups.SYSTEM.getGroupId()}).build()); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm1, authenticatedUser)); - assertEquals("User could not get updated. Runtime users cannot be modified.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Runtime users cannot be modified.", ex.getMessage()); when(userRepositoryMock.findByUserId(userId)).thenReturn(userEntityMock); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm1, authenticatedUser)); - assertEquals("User could not get updated. No changes were made.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" No changes were made.", ex.getMessage()); } @Test @@ -327,7 +327,7 @@ void updateUserNameThrows() { userRegisterForm.setUsername(""); UserNotUpdatedException ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. Wanted to change username, but username was not valid.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Wanted to change username, but username was not valid.", ex.getMessage()); String validUserName = "ValidUserNameButExists."; userRegisterForm.setUsername(validUserName); @@ -335,7 +335,7 @@ void updateUserNameThrows() { when(userDtoServiceMock.createDto(dummyEntity)).thenReturn(User.builder().build()); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. Username already taken.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Username already taken.", ex.getMessage()); } @Test @@ -361,25 +361,25 @@ void updatePasswordThrows() { userRegisterForm.setPassword(""); UserNotUpdatedException ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. Wanted to change password, but password was not valid.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Wanted to change password, but password was not valid.", ex.getMessage()); userRegisterForm.setPassword("somepw"); userRegisterForm.setConfirmationPassword(""); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. Wanted to change password, but password was not valid.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Wanted to change password, but password was not valid.", ex.getMessage()); userRegisterForm.setPassword("somepw"); userRegisterForm.setConfirmationPassword("somepw"); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser), "Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number."); - assertEquals("User could not get updated. Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Password needs to be at least 8 characters long and, contains at least one uppercase and lowercase letter and a number.", ex.getMessage()); userRegisterForm.setPassword("Somepw12345"); userRegisterForm.setConfirmationPassword("Somepw1234"); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser), "Passwords do not match."); - assertEquals("User could not get updated. Passwords do not match.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Passwords do not match.", ex.getMessage()); String validPassword = "ValidPassword1234!="; userRegisterForm.setPassword(validPassword); @@ -387,7 +387,7 @@ void updatePasswordThrows() { when(userRepositoryMock.findByUserId(userId)).thenReturn(dummyEntity); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser), "Username must not appear in password."); - assertEquals("User could not get updated. Username must not appear in password.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Username must not appear in password.", ex.getMessage()); } @Test @@ -415,7 +415,7 @@ void updateGroupsThrows() { when(groupRepositoryMock.getGroupsByIds(groups)).thenReturn(new Groups[]{Groups.ADMIN}); UserNotUpdatedException ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. Only admins can add users to group Admin.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Only admins can add users to group Admin.", ex.getMessage()); groups = new long[]{123032, 1230213}; userRegisterForm.setGroupIds(groups); @@ -423,14 +423,14 @@ void updateGroupsThrows() { when(groupRepositoryMock.getGroupsByIds(groups)).thenThrow(new IllegalArgumentException("id doesnt belong to a group")); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. One or more groups do not exist.", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" One or more groups do not exist.", ex.getMessage()); long[] systemUser = new long[]{Groups.SYSTEM.getGroupId()}; userRegisterForm.setGroupIds(systemUser); when(groupRepositoryMock.getGroupsByIds(systemUser)).thenReturn(new Groups[]{Groups.SYSTEM}); ex = assertThrows(UserNotUpdatedException.class, () -> userBusinessService.updateUser(userId, userRegisterForm, authenticatedUser)); - assertEquals("User could not get updated. Users cannot be added to the '" + Groups.SYSTEM.getDisplayName() + "' Group", ex.getMessage()); + assertEquals(UserNotUpdatedException.getErrorMessagePrefix()+" Users cannot be added to the '" + Groups.SYSTEM.getDisplayName() + "' Group", ex.getMessage()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/user/business/UserDtoServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/business/UserDtoServiceUnitTest.java index e5f19975..f4e9ca34 100644 --- a/src/test/java/de/filefighter/rest/domain/user/business/UserDtoServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/user/business/UserDtoServiceUnitTest.java @@ -50,7 +50,7 @@ void findEntityThrowsException() { UserNotFoundException ex = assertThrows(UserNotFoundException.class, () -> userDtoService.findEntity(user)); - assertEquals("Could not find user with userId 0.", ex.getMessage()); + assertEquals(UserNotFoundException.getErrorMessagePrefix()+" UserId was " + userId, ex.getMessage()); } @Test diff --git a/src/test/java/de/filefighter/rest/domain/user/group/GroupRepositoryUnitTest.java b/src/test/java/de/filefighter/rest/domain/user/group/GroupRepositoryUnitTest.java index c97c406d..e5babd7d 100644 --- a/src/test/java/de/filefighter/rest/domain/user/group/GroupRepositoryUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/user/group/GroupRepositoryUnitTest.java @@ -16,7 +16,7 @@ void getGroupByIdThrows() { long id = 900; IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> groupRepository.getGroupById(id)); - assertEquals("id " + id + " doesnt belong to a group.", ex.getMessage()); + assertEquals("GroupId " + id + " doesnt belong to a group.", ex.getMessage()); } @Test diff --git a/src/test/resources/FindUser.feature b/src/test/resources/FindUser.feature index f0d416e2..b9ebba8c 100644 --- a/src/test/resources/FindUser.feature +++ b/src/test/resources/FindUser.feature @@ -27,12 +27,12 @@ Feature: Find User with Username Scenario: Failed to find another user because username has spelling errors When user with accessToken "accessToken1" searches user with search-value "benguin" Then response status code is 404 - And response contains key "message" and value "User with username 'benguin' not found." + And response contains key "message" and value "User not found. Username was benguin" And response contains key "status" and value "Not Found" #kinda same but still Scenario: Failed to find another user because username does not exist When user with accessToken "accessToken1" searches user with search-value "bielefeld" Then response status code is 404 - And response contains key "message" and value "User with username 'bielefeld' not found." + And response contains key "message" and value "User not found. Username was bielefeld" And response contains key "status" and value "Not Found" \ No newline at end of file diff --git a/src/test/resources/ViewFolderContents.feature b/src/test/resources/ViewFolderContents.feature index 9dbe5956..aec46df7 100644 --- a/src/test/resources/ViewFolderContents.feature +++ b/src/test/resources/ViewFolderContents.feature @@ -7,7 +7,7 @@ Feature: View Folder And user 1234 exists And user 420 exists And accessToken with value "900000" exists for user 1234 - And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 420 and has the path "/bla" + And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 420 has the path "/bla" and name "bla" And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 420 and has the name "wow.txt" And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 @@ -27,6 +27,8 @@ Feature: View Folder Scenario: insufficient authorization Given user 9877 exists And accessToken with value "2345678" exists for user 9877 + When user with token "2345678" wants to see the content of folder with path "/bla/fasel" + Then response status code is 400 And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." Scenario: shared folder (user) @@ -66,8 +68,9 @@ Feature: View Folder And the response contains the file with fileSystemId 72 and name "wow.txt" Scenario: empty directory - Given fileSystemItem with the fileSystemId 44 exists, was created by user with userId 420 and has the path "/empty" + Given fileSystemItem with the fileSystemId 44 exists, was created by user with userId 420 has the path "/empty" and name "empty" + And fileSystemItem with the fileSystemId 44 is a folder And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 44 When user with token "900000" wants to see the content of folder with path "/empty" Then response status code is 200 - And the response contains an empty list for files and folders \ No newline at end of file + And the response contains an empty list for files and folders diff --git a/src/test/resources/crudFileSystem.feature b/src/test/resources/crudFileSystem.feature index 682a71bf..9e165156 100644 --- a/src/test/resources/crudFileSystem.feature +++ b/src/test/resources/crudFileSystem.feature @@ -17,11 +17,11 @@ Feature: FileSystem CRUD When user requests fileSystemInfo with fileSystemId 1234 and accessTokenValue "900000" Then response status code is 400 And response contains key "status" and value "Bad Request" - And response contains key "message" and value "FileSystemItem with id 1234 could not be found or you are not allowed to view it." + And response contains key "message" and value "FileSystemItem could not be found or you are not allowed to view it. FileSystemId was 1234" Scenario: Get FileSystemItem does not work, because user is not allowed Given fileSystemItem with the fileSystemId 1234 exists, was created by user with userId 9999999 and has the name "dummyFile.pdf" When user requests fileSystemInfo with fileSystemId 1234 and accessTokenValue "900000" Then response status code is 400 And response contains key "status" and value "Bad Request" - And response contains key "message" and value "FileSystemItem with id 1234 could not be found or you are not allowed to view it." + And response contains key "message" and value "FileSystemItem could not be found or you are not allowed to view it. FileSystemId was 1234" diff --git a/src/test/resources/crudPermissions.feature b/src/test/resources/crudPermissions.feature index 3b48d945..11920215 100644 --- a/src/test/resources/crudPermissions.feature +++ b/src/test/resources/crudPermissions.feature @@ -1,4 +1,4 @@ -#Feature: CRUD Permissions +Feature: CRUD Permissions # As a user and owner a file # I want want to be able to give or revoke other users permissions to either see or see and edit certain files or folders, so they can work together on the same files # @@ -94,4 +94,31 @@ # And user 1234 is owner of file or folder with id 111 # When user with token "900000" wants to give "edit" permission for "file" with id 111 to user 1234 # Then response status code is 405 -# And response contains key "message" and value "User with id 1234 is already owner of file with id 111." \ No newline at end of file +# And response contains key "message" and value "User with id 1234 is already owner of file with id 111." + + +# Scenario: Recursion (Should be discussed, maybe a flag for setting the permission recursive???) +# Given fileSystemItem with the fileSystemId 1 exists, was created by user with userId 1234 and has the path "/r" +# And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 +# And fileSystemItem with the fileSystemId 3 exists, was created by user with userId 1234 and has the path "/r/ProgrammerHumor" +# And fileSystemItem with the fileSystemId 2 is a folder and contains the fileSystemId 3 +# And fileSystemItem with the fileSystemId 3 exists, was created by user with userId 1234 and has the name "JonnysFavourites.zip" +# When user with token "900000" wants to give VIEW permission for fileSystemItem with id 1 to user 9877 +# Then response status code is 200 +# When user with token "2345678" wants to see the content of folder with path "/r/ProgrammerHumor" +# Then response status code is 200 +# And the response contains the file with fileSystemId 3 and name "JonnysFavourites.zip" +# When user with token "2345678" wants to delete the fileSystemItem with the fileSystemId 2 +# Then response status code is 400 +# And response contains key "message" and value "Folder does not exist, or you are not allowed to edit the folder." +# When user with token "2345678" wants to remove VIEW permission for fileSystemItem with id 3 for user 9877 +# Then response status code is 200 +# When user with token "2345678" wants to see the content of folder with path "/r/ProgrammerHumor" +# Then response status code is 200 +# And the response contains an empty list for files and folders +# When user with token "900000" wants to give EDIT permission for fileSystemItem with id 1 to user 9877 +# Then response status code is 200 + + + + diff --git a/src/test/resources/deleteFileSystemItems.feature b/src/test/resources/deleteFileSystemItems.feature new file mode 100644 index 00000000..99225531 --- /dev/null +++ b/src/test/resources/deleteFileSystemItems.feature @@ -0,0 +1,147 @@ +Feature: FileSystem Delete + As a user i want to delete FileSystemItems. + + Background: + Given database is empty + And user 1234 exists + And user 420 exists + And accessToken with value "900000" exists for user 1234 + And fileSystemItem with the fileSystemId 42 exists, was created by user with userId 420 has the path "/bla" and name "bla" + And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 72 + And fileSystemItem with the fileSystemId 72 exists, was created by user with userId 420 and has the name "wow.txt" + + Scenario: File Deletion + Given user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 72 + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "900000" wants to see the content of folder with path "/bla" + Then response status code is 200 + And the response contains the file with fileSystemId 72 and name "wow.txt" + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 72 + Then response status code is 200 + And response contains key "message" and value "Successfully deleted all requested FileSystemItems." + When user with token "900000" wants to see the content of folder with path "/bla" + And the response contains an empty list for files and folders + And response status code is 200 + + Scenario: Folder and content Deletion + Given user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 42 + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + And user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 72 + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 + Then response status code is 200 + When user with token "900000" wants to see the content of folder with path "/bla" + Then response status code is 400 + And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + + Scenario: Folder and content Deletion with remaining content + Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + And user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 42 + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 + And user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 72 + And fileSystemItem with the fileSystemId 1080 exists, was created by user with userId 420 and has the name "IwillStay.txt" + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 1080 + And fileSystemItem with the fileSystemId 42 is a folder and contains the fileSystemId 1080 + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 + Then response status code is 200 + And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." + When user with token "900000" wants to see the content of folder with path "/bla" + And the response does not contains the file with fileSystemId 72 and name "wow.txt" + And the response contains the file with fileSystemId 1080 and name "IwillStay.txt" + + Scenario: Folder and content Deletion with remaining content (invisible) + And accessToken with value "2000000" exists for user 420 + Given user with the userId 1234 is allowed to EDIT the fileSystemItem with the fileSystemId 42 + Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 + Then response status code is 200 + # This sucks, because for the user everything got deleted. But the message doesnt say that because "NOT EVERYTHING GOT DELETED". + And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." + When user with token "900000" wants to see the content of folder with path "/bla" + Then response status code is 400 + And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + When user with token "2000000" wants to see the content of folder with path "/bla" + Then response status code is 200 + And the response contains the file with fileSystemId 72 and name "wow.txt" + + Scenario: recursion + Given fileSystemItem with the fileSystemId 0 exists, was created by user with userId 1234 has the path "/foo" and name "foo" + And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 + And fileSystemItem with the fileSystemId 1 exists, was created by user with userId 1234 has the path "/foo/bar" and name "bar" + And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 + And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 1234 and has the name "git.exe" + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 0 + Then response status code is 200 + And response contains key "message" and value "Successfully deleted all requested FileSystemItems." + When user with token "900000" wants to see the content of folder with path "/foo/bar" + Then response status code is 400 + And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + When user with token "900000" wants to see the content of folder with path "/foo" + Then response status code is 400 + And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + + Scenario: recursion with remaining file + Given fileSystemItem with the fileSystemId 0 exists, was created by user with userId 1234 has the path "/foo" and name "foo" + And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 + And fileSystemItem with the fileSystemId 1 exists, was created by user with userId 1234 has the path "/foo/bar" and name "bar" + And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 + And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 3 + And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 1234 and has the name "git.exe" + And fileSystemItem with the fileSystemId 3 exists, was created by user with userId 420 and has the name "subversion.exe" + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 3 + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 0 + Then response status code is 200 + And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." + When user with token "900000" wants to see the content of folder with path "/foo/bar" + Then response status code is 200 + And the response contains the file with fileSystemId 3 and name "subversion.exe" + When user with token "900000" wants to see the content of folder with path "/foo" + Then response status code is 200 + And the response contains the folder with fileSystemId 1 and name "bar" + And the response does not contains the file with fileSystemId 2 and name "git.exe" + + Scenario: insufficient authorization + Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42 + Then response status code is 400 + And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 42" + + Scenario: insufficient permission + Given user 9877 exists + And accessToken with value "2345678" exists for user 9877 + When user with token "2345678" wants to delete the fileSystemItem with the fileSystemId 42 + Then response status code is 400 + And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 42" + + Scenario: Folder does not exist + When user with token "900000" wants to delete the fileSystemItem with the fileSystemId 42432567 + Then response status code is 400 + And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 42432567" + + Scenario: Folder was created by runtime user. + Given database is empty + # If this fails check the runtime user id. + And fileSystemItem with the fileSystemId 0 exists, was created by user with userId 0 has the path "/" and name "HOME_kevin" + And user with userId 123123123 exists and has username "kevin", password "securePassword123" + And user with the userId 123123123 is allowed to VIEW the fileSystemItem with the fileSystemId 0 + And user with the userId 123123123 is allowed to EDIT the fileSystemItem with the fileSystemId 0 + And accessToken with value "token" exists for user 123123123 + When user with token "token" wants to delete the fileSystemItem with the fileSystemId 0 + Then response status code is 400 + And response contains key "message" and value "FileSystemEntity could not be deleted. FileSystemId was 0" + + Scenario: File was created by runtime user. + Given database is empty + And user with userId 123123123 exists and has username "kevin", password "securePassword123" + And user with the userId 123123123 is allowed to VIEW the fileSystemItem with the fileSystemId 2 + And user with the userId 123123123 is allowed to EDIT the fileSystemItem with the fileSystemId 2 + And accessToken with value "token" exists for user 123123123 + And fileSystemItem with the fileSystemId 0 exists, was created by user with userId 123123123 has the path "/foo" and name "foo" + And fileSystemItem with the fileSystemId 0 is a folder and contains the fileSystemId 1 + And fileSystemItem with the fileSystemId 1 exists, was created by user with userId 123123123 has the path "/foo/bar" and name "bar" + And fileSystemItem with the fileSystemId 1 is a folder and contains the fileSystemId 2 + And fileSystemItem with the fileSystemId 2 exists, was created by user with userId 0 and has the name "veryImportantDocumentDon'tDeleteMePls.exe" + When user with token "token" wants to delete the fileSystemItem with the fileSystemId 0 + Then response status code is 200 + And response contains key "message" and value "Not everything got deleted, because you are not allowed to edit some files." \ No newline at end of file