diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 19168685..0850ea6d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,6 +6,7 @@ on: paths: - 'src/**' - 'pom.xml' + - '.github/workflows/tests.yml' jobs: Run_all_tests: @@ -25,8 +26,13 @@ jobs: docker create -p 27017:27017 --name FileFighterDB mongo:latest docker start FileFighterDB - - name: Run Tests and update Sonar - run: mvn clean verify sonar:sonar -s ./settings.xml + name: Run Tests and update Sonar (import cert first) + run: | + echo "${{ secrets.SSL_CERT }}" > filefighter.de_ssl_certificate.cer + yes yes | keytool -import -alias filefighterde -file filefighter.de_ssl_certificate.cer -storetype JKS -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit + mvn clean verify sonar:sonar -s ./settings.xml + rm filefighter.de_ssl_certificate.cer + keytool -delete -alias filefighterde -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit env: SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }} SONAR_PASSWORD: ${{ secrets.SONAR_PASSWORD }} diff --git a/.gitignore b/.gitignore index 549e00a2..5eac309e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,4 @@ build/ !**/src/test/**/build/ ### VS Code ### -.vscode/ +.vscode/ \ No newline at end of file diff --git a/README.md b/README.md index 69d11308..93cd6a58 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # RestApi -Backend REST API for FileFighter
+Backend REST API for FileFighter ![Docker Release](https://img.shields.io/github/v/release/filefighter/restapi?color=dark-green&label=Stable%20Version&logo=docker&style=for-the-badge) -![Docker Pulls](https://img.shields.io/docker/pulls/filefighter/rest?logo=docker&style=for-the-badge)
-[![Quality Gate Status](http://filefighter.ddns.net:9000/api/project_badges/measure?project=de.filefighter%3Arest&metric=alert_status)](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter%3Arest) -[![Coverage](http://filefighter.ddns.net:9000/api/project_badges/measure?project=de.filefighter%3Arest&metric=coverage)](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter%3Arest) -[![Lines of Code](http://filefighter.ddns.net:9000/api/project_badges/measure?project=de.filefighter%3Arest&metric=ncloc)](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter%3Arest) -[![Security Rating](http://filefighter.ddns.net:9000/api/project_badges/measure?project=de.filefighter%3Arest&metric=security_rating)](http://filefighter.ddns.net:9000/dashboard?id=de.filefighter%3Arest)
+![Docker Pulls](https://img.shields.io/docker/pulls/filefighter/rest?logo=docker&style=for-the-badge) +[![Quality Gate Status](http://sonar.filefighter.de/api/project_badges/measure?project=de.filefighter%3Arest&metric=alert_status)](https://sonar.filefighter.de/dashboard?id=de.filefighter%3Arest) +[![Coverage](http://sonar.filefighter.de/api/project_badges/measure?project=de.filefighter%3Arest&metric=coverage)](https://sonar.filefighter.de/dashboard?id=de.filefighter%3Arest) +[![Lines of Code](http://sonar.filefighter.de/api/project_badges/measure?project=de.filefighter%3Arest&metric=ncloc)](https://sonar.filefighter.de/dashboard?id=de.filefighter%3Arest) +[![Security Rating](http://sonar.filefighter.de/api/project_badges/measure?project=de.filefighter%3Arest&metric=security_rating)](https://sonar.filefighter.de/dashboard?id=de.filefighter%3Arest) ![Latest Release](https://github.com/FileFighter/RestApi/workflows/Latest%20Release/badge.svg) ![Stable Release](https://github.com/FileFighter/RestApi/workflows/Stable%20Release/badge.svg) ![Tests](https://github.com/FileFighter/RestApi/workflows/Tests/badge.svg) diff --git a/pom.xml b/pom.xml index ad458098..a6b32ea8 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ de.filefighter rest - 0.0.5 + 0.0.6 RestApi RestApi for FileFighter @@ -180,10 +180,8 @@ - *FileSystemRestService *PermissionRestService - *FileSystemBusinessService diff --git a/settings.xml b/settings.xml index 9ee4fb86..c23661b4 100644 --- a/settings.xml +++ b/settings.xml @@ -10,7 +10,7 @@ - http://filefighter.ddns.net:9000 + https://sonar.filefighter.de ${env.SONAR_LOGIN} ${env.SONAR_PASSWORD} diff --git a/src/main/java/de/filefighter/rest/configuration/CorsConfig.java b/src/main/java/de/filefighter/rest/configuration/CorsConfig.java new file mode 100644 index 00000000..7b79d99e --- /dev/null +++ b/src/main/java/de/filefighter/rest/configuration/CorsConfig.java @@ -0,0 +1,36 @@ +package de.filefighter.rest.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import java.util.ArrayList; + +@Configuration +public class CorsConfig { + + @Bean + @Profile({"dev","stage"}) + public CorsFilter corsFilter() { + final CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues(); + ArrayList allowedOrigins = new ArrayList<>(); + allowedOrigins.add("*"); + config.setAllowedOrigins(allowedOrigins); + + ArrayList allowedMethods = new ArrayList<>(); + allowedMethods.add("HEAD"); + allowedMethods.add("GET"); + allowedMethods.add("POST"); + allowedMethods.add("PUT"); + allowedMethods.add("DELETE"); + allowedMethods.add("OPTIONS"); + config.setAllowedMethods(allowedMethods); + + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } +} diff --git a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java index 0c1452de..d1b83ee3 100644 --- a/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java +++ b/src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java @@ -21,8 +21,8 @@ @Configuration public class PrepareDataBase { - private static final String MESSAGE_ON_SUCCESS = " was successful."; - private static final String MESSAGE_ON_FAILURE = " failed."; + private static final String MESSAGE_ON_SUCCESS = "was successful."; + private static final String MESSAGE_ON_FAILURE = "failed."; @Value("${server.port}") int serverPort; @@ -32,7 +32,8 @@ public class PrepareDataBase { @Value("${filefighter.date}") String date; - + + @SuppressWarnings("squid:S106") @Bean @Profile({"dev", "prod"}) CommandLineRunner veryImportantFileFighterStartScript() { @@ -40,17 +41,17 @@ CommandLineRunner veryImportantFileFighterStartScript() { System.out.println(); System.out.println("-------------------------------< REST API >-------------------------------"); System.out.println(); - System.out.println(" _____ _ _ _____ _ _ _ "); - System.out.println(" | ___| (_) | | ___ | ___| (_) __ _ | |__ | |_ ___ _ __ "); + System.out.println(" _____ _ _ _____ _ _ _"); + System.out.println(" | ___| (_) | | ___ | ___| (_) __ _ | |__ | |_ ___ _ __"); System.out.println(" | |_ | | | | / _ \\ | |_ | | / _ | | '_ \\ | __| / _ \\ | '__|"); - System.out.println(" | _| | | | | | __/ | _| | | | (_| | | | | | | |_ | __/ | | "); - System.out.println(" |_| |_| |_| \\___| |_| |_| \\__, | |_| |_| \\__| \\___| |_| "); - System.out.println(" |___/ "); - System.out.println(" Version v" + version + " Last updated at " + date + " "); - System.out.println(" Developed by Gimleux, Valentin, Open-Schnick. "); - System.out.println(" Development Blog: https://filefighter.github.io "); - System.out.println(" The code can be found at: https://www.github.com/filefighter "); - System.out.println(" Running on http://localhost:" + serverPort); + System.out.println(" | _| | | | | | __/ | _| | | | (_| | | | | | | |_ | __/ | |"); + System.out.println(" |_| |_| |_| \\___| |_| |_| \\__, | |_| |_| \\__| \\___| |_|"); + System.out.println(" |___/"); + System.out.println(" Version v" + version + " Last updated at " + date + ""); + System.out.println(" Developed by Gimleux, Valentin, Open-Schnick."); + System.out.println(" Development Blog: https://blog.filefighter.de"); + System.out.println(" The code can be found at: https://www.github.com/filefighter"); + System.out.println(" Running on http://localhost:" + serverPort); System.out.println(); System.out.println("-------------------------------< REST API >-------------------------------"); System.out.println(); @@ -83,19 +84,31 @@ CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepo .groupIds(new long[]{0, 1}) .build())); - log.info("Preloading default fsStructure: {}.", fileSystemRepository.save(FileSystemEntity - .builder() - .createdByUserId(0) - .fileSystemId(0) - .isFile(false) - .path("/") - .itemIds(new long[0]) - .lastUpdated(Instant.now().getEpochSecond()) - .name("root") - .size(0) - .typeId(FileSystemType.FOLDER.getId()) - .visibleForGroupIds(new long[]{-1, 0, 1}) - .build())); + log.info("Preloading default fsStructure: {} {}.", fileSystemRepository.save(FileSystemEntity + .builder() + .createdByUserId(0) + .fileSystemId(0) + .isFile(false) + .path("/") + .itemIds(new long[0]) + .lastUpdated(Instant.now().getEpochSecond()) + .name("root") + .size(0) + .typeId(FileSystemType.FOLDER.getId()) + .visibleForGroupIds(new long[]{-1, 0, 1}) + .itemIds(new long[]{1}) + .build()), + fileSystemRepository.save(FileSystemEntity.builder() + .createdByUserId(0) + .fileSystemId(1) + .isFile(true) + .lastUpdated(Instant.now().getEpochSecond()) + .name("dummyFile.txt") + .size(420) + .typeId(FileSystemType.TEXT.getId()) + .editableFoGroupIds(new long[]{0}) + .visibleForGroupIds(new long[]{0}) + .build())); log.info("Inserting Users {}", (userRepository.findAll().size() == 1 ? MESSAGE_ON_SUCCESS : MESSAGE_ON_FAILURE)); log.info("Inserting fsItems {}", (fileSystemRepository.findAll().size() == 1 ? MESSAGE_ON_SUCCESS : MESSAGE_ON_FAILURE)); @@ -123,7 +136,7 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo .lowercaseUsername("user1") .password("12345") .refreshToken("rft") - .groupIds(new long[]{-1}) + .groupIds(new long[]{0}) .build())); log.info("Preloading default tokens: {} {}", @@ -140,22 +153,33 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo .validUntil(Instant.now().getEpochSecond() + AccessTokenBusinessService.ACCESS_TOKEN_DURATION_IN_SECONDS) .build())); - log.info("Preloading default fsItems: {} {}.", + log.info("Preloading default fsItems: {} {} {}.", fileSystemRepository.save(FileSystemEntity.builder() .createdByUserId(0) .fileSystemId(0) .isFile(false) .path("/") - .itemIds(new long[]{1}) + .itemIds(new long[]{2}) .lastUpdated(Instant.now().getEpochSecond()) - .name("root") + .name("HOME_User") + .size(420) + .typeId(FileSystemType.FOLDER.getId()) + .visibleForGroupIds(new long[]{0, 1}) + .build()), + fileSystemRepository.save(FileSystemEntity.builder() + .createdByUserId(1) + .fileSystemId(1) + .isFile(false) + .path("/") + .lastUpdated(Instant.now().getEpochSecond()) + .name("HOME_User1") .size(420) .typeId(FileSystemType.FOLDER.getId()) .visibleForGroupIds(new long[]{-1, 0, 1}) .build()), fileSystemRepository.save(FileSystemEntity.builder() .createdByUserId(0) - .fileSystemId(1) + .fileSystemId(2) .isFile(true) .lastUpdated(Instant.now().getEpochSecond()) .name("dummyFile.txt") @@ -165,7 +189,7 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo .visibleForGroupIds(new long[]{0}) .build())); - log.info("Inserting FileSystemItems {}", (fileSystemRepository.findAll().size() == 2 ? MESSAGE_ON_SUCCESS : MESSAGE_ON_FAILURE)); + log.info("Inserting FileSystemItems {}", (fileSystemRepository.findAll().size() == 3 ? MESSAGE_ON_SUCCESS : MESSAGE_ON_FAILURE)); log.info("Inserting token {}", (accessTokenRepository.findAll().size() == 2 ? MESSAGE_ON_SUCCESS : MESSAGE_ON_FAILURE)); log.info("Inserting Users {}", (userRepository.findAll().size() == 2 ? MESSAGE_ON_SUCCESS : MESSAGE_ON_FAILURE)); }; diff --git a/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java b/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java index 31a5096f..eb239a69 100644 --- a/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java +++ b/src/main/java/de/filefighter/rest/configuration/RestConfiguration.java @@ -12,6 +12,6 @@ public class RestConfiguration { public static final String DEFAULT_ERROR_URI = "/error"; private RestConfiguration(){ - // Cannot be inst + // Cannot be instantiated. } } \ No newline at end of file diff --git a/src/main/java/de/filefighter/rest/domain/common/DtoServiceInterface.java b/src/main/java/de/filefighter/rest/domain/common/DTOServiceInterface.java similarity index 69% rename from src/main/java/de/filefighter/rest/domain/common/DtoServiceInterface.java rename to src/main/java/de/filefighter/rest/domain/common/DTOServiceInterface.java index 06605dbb..0896db98 100644 --- a/src/main/java/de/filefighter/rest/domain/common/DtoServiceInterface.java +++ b/src/main/java/de/filefighter/rest/domain/common/DTOServiceInterface.java @@ -1,6 +1,6 @@ package de.filefighter.rest.domain.common; -public interface DtoServiceInterface { +public interface DTOServiceInterface { D createDto(E entity); E findEntity(D dto); } 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 4793c57e..cf8fc3c7 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,84 +1,173 @@ package de.filefighter.rest.domain.filesystem.business; -import de.filefighter.rest.domain.filesystem.data.dto.File; -import de.filefighter.rest.domain.filesystem.data.dto.Folder; -import de.filefighter.rest.domain.filesystem.data.dto.FolderContents; +import de.filefighter.rest.domain.common.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.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.group.Groups; +import de.filefighter.rest.rest.exceptions.FileFighterDataException; +import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +@Log4j2 @Service public class FileSystemBusinessService { - public FileSystemBusinessService() { + private final FileSystemRepository fileSystemRepository; + private final UserBusinessService userBusinessService; + private final FileSystemTypeRepository fileSystemTypeRepository; + + public FileSystemBusinessService(FileSystemRepository fileSystemRepository, UserBusinessService userBusinessService, FileSystemTypeRepository fileSystemTypeRepository) { + this.fileSystemRepository = fileSystemRepository; + this.userBusinessService = userBusinessService; + this.fileSystemTypeRepository = fileSystemTypeRepository; + } + + public List getFolderContentsByPath(String path, User authenticatedUser) { + if (!InputSanitizerService.stringIsValid(path)) + throw new FileSystemContentsNotAccessibleException("Path was not valid."); + + String[] pathWithoutSlashes = path.split("/"); + + if (!path.equals("/") && pathWithoutSlashes.length < 2) + throw new FileSystemContentsNotAccessibleException("Path was in wrong format."); + + if (!path.equals("/") && !"".equals(pathWithoutSlashes[0])) + throw new FileSystemContentsNotAccessibleException("Path was in wrong format. Use a leading backslash."); + + String pathToFind = removeTrailingBackSlashes(path); + + // find the folder with matching path. + ArrayList listOfFileSystemEntities = fileSystemRepository.findByPath(pathToFind); + if (null == listOfFileSystemEntities) // does return null and not a empty collection. + throw new FileSystemContentsNotAccessibleException(); + + // remove all not accessible items. + listOfFileSystemEntities.removeIf(entity -> entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || !userIsAllowedToSeeFileSystemEntity(entity, authenticatedUser)); + + if (listOfFileSystemEntities.isEmpty()) + throw new FileSystemContentsNotAccessibleException(); + + // now only own or shared folders are left. + return getFolderContentsOfEntities(listOfFileSystemEntities, authenticatedUser, pathToFind); } - public static FolderContents getContentsOfFolder(String path, User authenticatedUser) { - FolderContents folderContents; - switch (path) { - case "/": - folderContents = FolderContents.builder() - .files(new File[]{new File(0, "Passwords.crypt", 420, 0, 1897550098, FileSystemType.TEXT, null)}) - .folders(new Folder[]{ - new Folder(1, "/dhbw", "DHBW", 87568438, 0, 1589998868, null), - new Folder(2, "/homework", "Homework", 1897557698, 0, 1577836800, null) - }) - .build(); - break; - case "/dhbw": - folderContents = FolderContents.builder() - .folders(new Folder[]{ - new Folder(3, "/dhbw/se", "SE", 18975576, 0, 1601148846, null), - new Folder(4, "/dhbw/ti-3", "TI-3", 69, 0, 1599936800, null) - }) - .files(new File[]{ - new File(4, "WhatIsThis", 42, 0, 153354, FileSystemType.UNDEFINED, null), - new File(5, "HerrMeyerSieWissenDochImmerAlles.mp3", 27565846, 0, 1599147368, FileSystemType.AUDIO, null), - new File(6, "cucumberTestsWorkProve.mp4", 224850446, 0, 1602047368, FileSystemType.VIDEO, null), - new File(7, "WeirdScreenshot.jpg", 4866848, 0, 1599949968, FileSystemType.PICTURE, null), - new File(8, "ILikeThisFileType.md", 96643, 0, 1598888868, FileSystemType.TEXT, null), - new File(9, "MyFirstWebsite.html", 861858, 0, 1601584968, FileSystemType.TEXT, null), - new File(10, "JavaScriptFTW.js", 176643, 0, 1597388868, FileSystemType.TEXT, null), - new File(11, "TheyWillNeverKnow.crypt", 75896643, 0, 1600188868, FileSystemType.UNDEFINED, null), - new File(12, "Opportunismus und Repression.pdf", 4826643, 0, 1589998868, FileSystemType.PDF, null), - new File(13, "ProfsINeedToBribeOrCharm.txt", 153, 0, 1589998868, FileSystemType.TEXT, null), - new File(14, "FinishedFileFighterBE.java", 846846643, 0, 1624752000, FileSystemType.TEXT, null), - }) - .build(); - break; - case "/dhbw/se": - folderContents = FolderContents.builder() - .files(new File[]{ - new File(18, "FullyAutomatedDocumentationScript.py", 42042, 0, 1589998868, FileSystemType.UNDEFINED, null) - }).build(); - break; - case "/dhbw/ti-3": - folderContents = FolderContents.builder() - .files(new File[]{ - new File(19, "Braun verstehen in 3 Schritten - Das Buch.pdf", 42042, 0, 1589998868, FileSystemType.PDF, null) - }).build(); - break; - case "/homework": - folderContents = FolderContents.builder() - .files(new File[]{new File(15, "homeworks.zip", 420, 0, Instant.now().getEpochSecond(), FileSystemType.UNDEFINED, null)}) - .folders(new Folder[]{new Folder(16, "/homework/jonnywishesforasecretchamber", "JonnyWishesForASecretChamber", 2, 0, 1589998868, null)}) - .build(); - break; - case "/homework/jonnywishesforasecretchamber": - folderContents = FolderContents.builder() - .folders(new Folder[]{new Folder(17, "/homework/johnwishesforasecretchamber/emptyfolder", "EmptyFolder", 0, 0, 1589998868, null)}) - .build(); - break; - case "/homework/jonnywishesforasecretchamber/emptyfolder": - folderContents = FolderContents.builder().build(); - break; - default: - throw new FileSystemContentsNotAccessibleException(); + 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)); + } + } + } + + return fileSystemItems; + } + 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 folderContents; + return pathToFind; + } + + public boolean userIsAllowedToSeeFileSystemEntity(FileSystemEntity fileSystemEntity, User authenticatedUser) { + // user created the item + if (fileSystemEntity.getCreatedByUserId() == authenticatedUser.getUserId()) + return true; + + // user got the item shared. + for (long userId : fileSystemEntity.getVisibleForUserIds()) { + if (userId == authenticatedUser.getUserId()) + return true; + } + + // user is in group that got the item shared. + long[] fileIsSharedToGroups = fileSystemEntity.getVisibleForGroupIds(); + for (Groups group : authenticatedUser.getGroups()) { + for (long groupId : fileIsSharedToGroups) { + if (groupId == group.getGroupId()) + return true; + + } + } + return false; + } + + public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenticatedUser, String basePath) { + User ownerOfFileSystemItem = userBusinessService.getUserById(fileSystemEntity.getCreatedByUserId()); + + 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()) + .fileSystemId(fileSystemEntity.getFileSystemId()) + .lastUpdated(fileSystemEntity.getLastUpdated()) + .name(fileSystemEntity.getName()) + .size(fileSystemEntity.getSize()) + .type(isAFolder ? FileSystemType.FOLDER : type) + .path(basePath + fileSystemEntity.getName()) + .isShared(isShared) + .build(); + } + + public void createBasicFilesForNewUser(UserEntity registeredUserEntity) { + fileSystemRepository.save(FileSystemEntity + .builder() + .createdByUserId(registeredUserEntity.getUserId()) + .typeId(0) + .isFile(false) + .name("HOME_" + registeredUserEntity.getUsername()) + .path("/") + .lastUpdated(Instant.now().getEpochSecond()) + .fileSystemId(generateNextFileSystemId()) + .build()); + } + + public double getTotalFileSize() { + ArrayList entities = fileSystemRepository.findByPath("/"); + if (null == entities) + throw new FileFighterDataException("Couldn't find any Home directories!"); + + double size = 0; + for (FileSystemEntity entity : entities) { + size += entity.getSize(); + } + return size; + } + + public long getFileSystemEntityCount() { + return fileSystemRepository.count(); + } + + public long generateNextFileSystemId() { + return getFileSystemEntityCount() + 1; } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/File.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/File.java deleted file mode 100644 index d4b5183c..00000000 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/File.java +++ /dev/null @@ -1,13 +0,0 @@ -package de.filefighter.rest.domain.filesystem.data.dto; - -import de.filefighter.rest.domain.filesystem.type.FileSystemType; -import de.filefighter.rest.domain.permission.data.dto.PermissionSet; - -public class File extends FileSystemItem{ - public File() { - } - - public File(long fileSystemId, String name, double size, long createdByUserId, long lastUpdated, FileSystemType type, PermissionSet permissionSet) { - super(fileSystemId, name, size, createdByUserId, lastUpdated, type, permissionSet); - } -} \ No newline at end of file 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 43452a08..c0b9f015 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,31 +1,21 @@ package de.filefighter.rest.domain.filesystem.data.dto; import de.filefighter.rest.domain.filesystem.type.FileSystemType; -import de.filefighter.rest.domain.permission.data.dto.PermissionSet; -import lombok.Getter; -import lombok.Setter; +import lombok.Builder; +import lombok.Data; -@Getter -@Setter +@Builder +@Data public class FileSystemItem { - private long fileSystemId; + + @Builder.Default + private long fileSystemId = -1; + private String path; private String name; + private boolean isShared; private double size; private long createdByUserId; //uploadedBy private long lastUpdated; private FileSystemType type; - private PermissionSet permissionSet; - - protected FileSystemItem() { - } - public FileSystemItem(long fileSystemId, String name, double size, long createdByUserId, long lastUpdated, FileSystemType type, PermissionSet permissionSet) { - this.fileSystemId = fileSystemId; - this.name = name; - this.size = size; - this.createdByUserId = createdByUserId; - this.lastUpdated = lastUpdated; - this.type = type; - this.permissionSet = permissionSet; - } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/Folder.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/Folder.java deleted file mode 100644 index af47726d..00000000 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/Folder.java +++ /dev/null @@ -1,24 +0,0 @@ -package de.filefighter.rest.domain.filesystem.data.dto; - -import de.filefighter.rest.domain.filesystem.type.FileSystemType; -import de.filefighter.rest.domain.permission.data.dto.PermissionSet; - -public class Folder extends FileSystemItem { - private String path; - - public Folder() { - } - - public Folder(long id, String path, String name, double size, long createdByUserId, long lastUpdated, PermissionSet permissionSet) { - super(id, name, size, createdByUserId, lastUpdated, FileSystemType.FOLDER, permissionSet); - this.path = path; - } - - public String getPath() { - return path; - } - - public void setPath(String path) { - this.path = path; - } -} diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java b/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java deleted file mode 100644 index 153821da..00000000 --- a/src/main/java/de/filefighter/rest/domain/filesystem/data/dto/FolderContents.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.filefighter.rest.domain.filesystem.data.dto; - -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class FolderContents { - private final Folder[] folders; - private final File[] files; -} 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 6062c591..2449e812 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 @@ -12,18 +12,25 @@ public class FileSystemEntity { @MongoId private String mongoId; - private long fileSystemId; + @Builder.Default + private long fileSystemId = -1; private String name; private String path; private long typeId; private double size; private boolean isFile; - private long createdByUserId; //uploadedBy + @Builder.Default + private long createdByUserId = -1; //uploadedBy private long lastUpdated; - private long[] visibleForGroupIds; - private long[] editableFoGroupIds; - private long[] visibleForUserIds; - private long[] editableForUserIds; - private long[] itemIds; + @Builder.Default + private long[] visibleForGroupIds = new long[0]; + @Builder.Default + private long[] editableFoGroupIds = new long[0]; + @Builder.Default + private long[] visibleForUserIds = new long[0]; + @Builder.Default + private long[] editableForUserIds = new long[0]; + @Builder.Default + private long[] itemIds = 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 ce341af1..e73415c4 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 @@ -3,7 +3,10 @@ import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.stereotype.Service; +import java.util.ArrayList; + @Service public interface FileSystemRepository extends MongoRepository { FileSystemEntity findByFileSystemId(long fileSystemId); + ArrayList findByPath(String path); } 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 389e6e95..a7d17554 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 @@ -5,4 +5,8 @@ public class FileSystemContentsNotAccessibleException extends RuntimeException { public FileSystemContentsNotAccessibleException() { super("Folder does not exist, or you are not allowed to see the folder."); } + + public FileSystemContentsNotAccessibleException(String reason) { + super("Folder contents could not be displayed. "+reason); + } } diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java index 7cf24d4c..a02eb750 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestController.java @@ -2,13 +2,14 @@ import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; -import de.filefighter.rest.domain.filesystem.data.dto.FolderContents; import de.filefighter.rest.rest.ServerResponse; import io.swagger.annotations.Api; import lombok.extern.log4j.Log4j2; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; + import static de.filefighter.rest.configuration.RestConfiguration.*; @Log4j2 @@ -24,7 +25,7 @@ public FileSystemRestController(FileSystemRestServiceInterface fileSystemRestSer } @GetMapping(FS_BASE_URI + "contents") - public ResponseEntity getContentsOfFolder( + public ResponseEntity> getContentsOfFolder( @RequestHeader(value = FS_PATH_HEADER, defaultValue = "/") String path, @RequestHeader(value = "Authorization", defaultValue = AUTHORIZATION_BEARER_PREFIX + "token") String accessToken ) { diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestService.java index f544df5d..2c17a50e 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 @@ -5,7 +5,6 @@ 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; -import de.filefighter.rest.domain.filesystem.data.dto.FolderContents; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; import de.filefighter.rest.domain.token.data.dto.AccessToken; import de.filefighter.rest.domain.user.business.UserAuthorizationService; @@ -15,6 +14,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import java.util.ArrayList; + @Service public class FileSystemRestService implements FileSystemRestServiceInterface { @@ -31,14 +32,15 @@ public FileSystemRestService(UserAuthorizationService userAuthorizationService, } @Override - public ResponseEntity getContentsOfFolderByPathAndAccessToken(String path, String accessTokenValue) { + public ResponseEntity> getContentsOfFolderByPathAndAccessToken(String path, String accessTokenValue) { String cleanHeader = inputSanitizerService.sanitizeRequestHeader(RestConfiguration.AUTHORIZATION_BEARER_PREFIX, accessTokenValue); String cleanValue = inputSanitizerService.sanitizeTokenValue(cleanHeader); AccessToken accessToken = accessTokenBusinessService.findAccessTokenByValue(cleanValue); User authenticatedUser = userAuthorizationService.authenticateUserWithAccessToken(accessToken); + String cleanPathString = InputSanitizerService.sanitizeString(path); - FolderContents folderContents = FileSystemBusinessService.getContentsOfFolder(path, authenticatedUser); - return new ResponseEntity<>(folderContents, HttpStatus.OK); + ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(cleanPathString, authenticatedUser); + return new ResponseEntity<>(fileSystemItems, HttpStatus.OK); } @Override diff --git a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java index 0dc3345f..b868aa7e 100644 --- a/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java +++ b/src/main/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestServiceInterface.java @@ -2,12 +2,13 @@ import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; -import de.filefighter.rest.domain.filesystem.data.dto.FolderContents; import de.filefighter.rest.rest.ServerResponse; import org.springframework.http.ResponseEntity; +import java.util.ArrayList; + public interface FileSystemRestServiceInterface { - ResponseEntity getContentsOfFolderByPathAndAccessToken(String path, String accessToken); + ResponseEntity> getContentsOfFolderByPathAndAccessToken(String path, String accessToken); ResponseEntity getInfoAboutFileOrFolderByIdAndAccessToken(long fsItemId, String accessToken); ResponseEntity findFileOrFolderByNameAndAccessToken(String name, String accessToken); ResponseEntity uploadFileSystemItemWithAccessToken(FileSystemItemUpdate fileSystemItemUpdate, String accessToken); diff --git a/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java b/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java index 0674fea6..3fbe96e4 100644 --- a/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java +++ b/src/main/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessService.java @@ -1,5 +1,6 @@ package de.filefighter.rest.domain.health.business; +import de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService; import de.filefighter.rest.domain.health.data.SystemHealth; import de.filefighter.rest.domain.health.data.SystemHealth.DataIntegrity; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; @@ -14,25 +15,28 @@ public class SystemHealthBusinessService { private final UserBusinessService userBusinessService; private final AccessTokenBusinessService accessTokenBusinessService; + private final FileSystemBusinessService fileSystemBusinessService; private final long serverStartedAt; private DataIntegrity cachedIntegrity = DataIntegrity.STABLE; @Value("${filefighter.version}") String version; - public SystemHealthBusinessService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService) { + public SystemHealthBusinessService(UserBusinessService userBusinessService, AccessTokenBusinessService accessTokenBusinessService, FileSystemBusinessService fileSystemBusinessService) { this.userBusinessService = userBusinessService; this.accessTokenBusinessService = accessTokenBusinessService; + this.fileSystemBusinessService = fileSystemBusinessService; this.serverStartedAt = this.getCurrentEpochSeconds(); } - public SystemHealth getCurrentSystemHealthInfo(){ + public SystemHealth getCurrentSystemHealthInfo() { long currentEpoch = getCurrentEpochSeconds(); return SystemHealth.builder() .uptimeInSeconds(currentEpoch - serverStartedAt) .userCount(userBusinessService.getUserCount()) + .usedStorageInMb(fileSystemBusinessService.getTotalFileSize()) .dataIntegrity(calculateDataIntegrity()) - .version("v"+this.version) + .version("v" + this.version) .build(); } @@ -41,19 +45,19 @@ private DataIntegrity calculateDataIntegrity() { long accessTokenCount = accessTokenBusinessService.getAccessTokenCount(); // Risk / Unstable Cases. - if(userCount < accessTokenCount){ + if (userCount < accessTokenCount) { this.triggerIntegrityChange(DataIntegrity.POSSIBLE_RISK); } return cachedIntegrity; } - public long getCurrentEpochSeconds(){ + public long getCurrentEpochSeconds() { return Instant.now().getEpochSecond(); } public void triggerIntegrityChange(DataIntegrity integrity) { - if(cachedIntegrity.getCode() < integrity.getCode()){ + if (cachedIntegrity.getCode() < integrity.getCode()) { this.cachedIntegrity = integrity; } } diff --git a/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java b/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java index 2a6b21fa..23af01a7 100644 --- a/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java +++ b/src/main/java/de/filefighter/rest/domain/health/data/SystemHealth.java @@ -1,17 +1,18 @@ package de.filefighter.rest.domain.health.data; import lombok.Builder; -import lombok.Getter; +import lombok.Data; /** * This class is a representation of the json model. */ -@Getter +@Data @Builder public class SystemHealth { private final long uptimeInSeconds; private final long userCount; + private final double usedStorageInMb; private final DataIntegrity dataIntegrity; private final String version; diff --git a/src/main/java/de/filefighter/rest/domain/permission/data/dto/request/PermissionRecipient.java b/src/main/java/de/filefighter/rest/domain/permission/data/dto/request/PermissionRecipient.java index a0ed4055..de1c6377 100644 --- a/src/main/java/de/filefighter/rest/domain/permission/data/dto/request/PermissionRecipient.java +++ b/src/main/java/de/filefighter/rest/domain/permission/data/dto/request/PermissionRecipient.java @@ -5,12 +5,9 @@ @Getter @ToString -public class PermissionRecipient{ - private final PermissionRecipientType permissionRecipientType; - private final long userOrGroupId; +public class PermissionRecipient { + + private PermissionRecipientType permissionRecipientType; + private long userOrGroupId; - private PermissionRecipient(PermissionRecipientType permissionRecipientType, long userOrGroupId) { - this.permissionRecipientType = permissionRecipientType; - this.userOrGroupId = userOrGroupId; - } } \ No newline at end of file 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 eb9511a7..73e1bfd1 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 @@ -17,12 +17,12 @@ public class AccessTokenBusinessService { private final AccessTokenRepository accessTokenRepository; - private final AccessTokenDtoService accessTokenDtoService; + private final AccessTokenDTOService accessTokenDtoService; public static final long ACCESS_TOKEN_DURATION_IN_SECONDS = 3600L; public static final long ACCESS_TOKEN_SAFETY_MARGIN = 5L; - public AccessTokenBusinessService(AccessTokenRepository accessTokenRepository, AccessTokenDtoService accessTokenDtoService) { + public AccessTokenBusinessService(AccessTokenRepository accessTokenRepository, AccessTokenDTOService accessTokenDtoService) { this.accessTokenRepository = accessTokenRepository; this.accessTokenDtoService = accessTokenDtoService; } 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 similarity index 87% rename from src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDtoService.java rename to src/main/java/de/filefighter/rest/domain/token/business/AccessTokenDTOService.java index 79e7a386..12f7ba23 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 @@ -1,6 +1,6 @@ package de.filefighter.rest.domain.token.business; -import de.filefighter.rest.domain.common.DtoServiceInterface; +import de.filefighter.rest.domain.common.DTOServiceInterface; 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; @@ -8,11 +8,11 @@ import org.springframework.stereotype.Service; @Service -public class AccessTokenDtoService implements DtoServiceInterface { +public class AccessTokenDTOService implements DTOServiceInterface { private final AccessTokenRepository accessTokenRepository; - public AccessTokenDtoService(AccessTokenRepository accessTokenRepository) { + public AccessTokenDTOService(AccessTokenRepository accessTokenRepository) { this.accessTokenRepository = accessTokenRepository; } diff --git a/src/main/java/de/filefighter/rest/domain/token/data/dto/AccessToken.java b/src/main/java/de/filefighter/rest/domain/token/data/dto/AccessToken.java index 8e20d3ad..55798453 100644 --- a/src/main/java/de/filefighter/rest/domain/token/data/dto/AccessToken.java +++ b/src/main/java/de/filefighter/rest/domain/token/data/dto/AccessToken.java @@ -7,6 +7,7 @@ @Builder public class AccessToken { private String tokenValue; - private long userId; + @Builder.Default + private long userId = -1; private long validUntil; } diff --git a/src/main/java/de/filefighter/rest/domain/token/data/persistence/AccessTokenEntity.java b/src/main/java/de/filefighter/rest/domain/token/data/persistence/AccessTokenEntity.java index c306adcf..c5626519 100644 --- a/src/main/java/de/filefighter/rest/domain/token/data/persistence/AccessTokenEntity.java +++ b/src/main/java/de/filefighter/rest/domain/token/data/persistence/AccessTokenEntity.java @@ -13,7 +13,8 @@ public class AccessTokenEntity { @MongoId private String mongoId; private String value; - private long userId; + @Builder.Default + private long userId = -1; private long validUntil; } \ No newline at end of file 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 f76733c5..75580651 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 @@ -19,9 +19,9 @@ public class UserAuthorizationService { private final UserRepository userRepository; - private final UserDtoService userDtoService; + private final UserDTOService userDtoService; - public UserAuthorizationService(UserRepository userRepository, UserDtoService userDtoService) { + public UserAuthorizationService(UserRepository userRepository, UserDTOService userDtoService) { this.userRepository = userRepository; this.userDtoService = userDtoService; } 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 f94f4dfd..73155222 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 @@ -11,7 +11,6 @@ import de.filefighter.rest.domain.user.exceptions.UserNotUpdatedException; import de.filefighter.rest.domain.user.group.GroupRepository; import de.filefighter.rest.domain.user.group.Groups; -import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; @@ -25,22 +24,20 @@ import static de.filefighter.rest.domain.common.InputSanitizerService.stringIsValid; -@Log4j2 @Service public class UserBusinessService { private final UserRepository userRepository; - private final UserDtoService userDtoService; + private final UserDTOService userDtoService; private final GroupRepository groupRepository; private final MongoTemplate mongoTemplate; public static final int USER_ID_MAX = 99999999; - @Value("${filefighter.disable-password-check}") public boolean passwordCheckDisabled; - public UserBusinessService(UserRepository userRepository, UserDtoService userDtoService, GroupRepository groupRepository, MongoTemplate mongoTemplate) { + public UserBusinessService(UserRepository userRepository, UserDTOService userDtoService, GroupRepository groupRepository, MongoTemplate mongoTemplate) { this.userRepository = userRepository; this.userDtoService = userDtoService; this.groupRepository = groupRepository; @@ -78,27 +75,20 @@ public RefreshToken getRefreshTokenForUser(User user) { } public User findUserByUsername(String username) { - String lowercaseUsername = username.toLowerCase(); - - UserEntity entity = userRepository.findByLowercaseUsername(lowercaseUsername); + UserEntity entity = getUserWithUsername(username); if (null == entity) throw new UserNotFoundException("User with username '" + username + "' not found."); return userDtoService.createDto(entity); } - public void registerNewUser(UserRegisterForm newUser) { - // check username + public UserEntity registerNewUser(UserRegisterForm newUser) { String username = newUser.getUsername(); - User user = null; - try { - user = this.findUserByUsername(newUser.getUsername()); - } catch (UserNotFoundException ignored) { - log.info("Username '{}' is free to use.", username); - } + if (!stringIsValid(username)) + throw new UserNotRegisteredException("Username was not valid."); - if (null != user) + if (null != this.getUserWithUsername(username)) throw new UserNotRegisteredException("Username already taken."); // check pws. @@ -131,7 +121,7 @@ public void registerNewUser(UserRegisterForm newUser) { } //create new user. - userRepository.save(UserEntity.builder() + return userRepository.save(UserEntity.builder() .lowercaseUsername(username.toLowerCase()) .username(username) .password(password) @@ -148,6 +138,15 @@ public boolean passwordIsValid(String password) { return pattern.matcher(password).matches(); } + /** + * @param username username to find. + * @return null or the found user. + */ + public UserEntity getUserWithUsername(String username) { + String lowercaseUsername = username.toLowerCase(); + return userRepository.findByLowercaseUsername(lowercaseUsername); + } + public void updateUser(long userId, UserRegisterForm userToUpdate, User authenticatedUser) { if (null == userToUpdate) throw new UserNotUpdatedException("No updates specified."); @@ -184,7 +183,7 @@ public void updateUser(long userId, UserRegisterForm userToUpdate, User authenti } private boolean updateGroups(Update newUpdate, long[] groupIds, boolean authenticatedUserIsAdmin) { - if (null != groupIds) { + if (null != groupIds && groupIds.length != 0) { try { for (Groups group : groupRepository.getGroupsByIds(groupIds)) { if (group == Groups.ADMIN && !authenticatedUserIsAdmin) @@ -230,14 +229,7 @@ private boolean updateUserName(Update update, String username) { if (!stringIsValid(username)) throw new UserNotUpdatedException("Wanted to change username, but username was not valid."); - User user = null; - try { - user = this.findUserByUsername(username); - } catch (UserNotFoundException ignored) { - log.info("Username '{}' is free to use.", username); - } - - if (null != user) + if (null != getUserWithUsername(username)) throw new UserNotUpdatedException("Username already taken."); update.set("username", username); diff --git a/src/main/java/de/filefighter/rest/domain/user/business/UserDtoService.java b/src/main/java/de/filefighter/rest/domain/user/business/UserDTOService.java similarity index 87% rename from src/main/java/de/filefighter/rest/domain/user/business/UserDtoService.java rename to src/main/java/de/filefighter/rest/domain/user/business/UserDTOService.java index 45ec6276..865727e7 100644 --- a/src/main/java/de/filefighter/rest/domain/user/business/UserDtoService.java +++ b/src/main/java/de/filefighter/rest/domain/user/business/UserDTOService.java @@ -1,6 +1,6 @@ package de.filefighter.rest.domain.user.business; -import de.filefighter.rest.domain.common.DtoServiceInterface; +import de.filefighter.rest.domain.common.DTOServiceInterface; 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; @@ -9,12 +9,12 @@ import org.springframework.stereotype.Service; @Service -public class UserDtoService implements DtoServiceInterface { +public class UserDTOService implements DTOServiceInterface { private final GroupRepository groupRepository; private final UserRepository userRepository; - public UserDtoService(GroupRepository groupRepository, UserRepository userRepository) { + public UserDTOService(GroupRepository groupRepository, UserRepository userRepository) { this.groupRepository = groupRepository; this.userRepository = userRepository; } diff --git a/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java b/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java index 18c421ea..891d7e06 100644 --- a/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java +++ b/src/main/java/de/filefighter/rest/domain/user/data/dto/User.java @@ -1,4 +1,5 @@ package de.filefighter.rest.domain.user.data.dto; + import de.filefighter.rest.domain.user.group.Groups; import lombok.Builder; import lombok.Data; @@ -7,9 +8,11 @@ @Data @Builder public class User { - private long userId; + @Builder.Default + private long userId = -1; private String username; - private Groups[] groups; + @Builder.Default + private Groups[] groups = new Groups[0]; public User(long userId, String username, Groups... groups) { this.userId = userId; diff --git a/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java b/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java index 713e83b8..622594bf 100644 --- a/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java +++ b/src/main/java/de/filefighter/rest/domain/user/data/dto/UserRegisterForm.java @@ -11,7 +11,8 @@ public class UserRegisterForm { private String username; private String password; private String confirmationPassword; - private long[] groupIds; + @Builder.Default + private long[] groupIds = new long[0]; @Override public String toString() { diff --git a/src/main/java/de/filefighter/rest/domain/user/data/persistence/UserEntity.java b/src/main/java/de/filefighter/rest/domain/user/data/persistence/UserEntity.java index 363b6e66..572e53ff 100644 --- a/src/main/java/de/filefighter/rest/domain/user/data/persistence/UserEntity.java +++ b/src/main/java/de/filefighter/rest/domain/user/data/persistence/UserEntity.java @@ -1,17 +1,13 @@ package de.filefighter.rest.domain.user.data.persistence; import lombok.Builder; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; +import lombok.Data; import org.springframework.data.mongodb.core.mapping.Document; import org.springframework.data.mongodb.core.mapping.MongoId; @Document(collection = "user") -@Getter -@ToString +@Data @Builder -@Setter public class UserEntity { @MongoId @@ -21,6 +17,7 @@ public class UserEntity { private String lowercaseUsername; // Redundancy for performance tradeoff. private String password; private String refreshToken; - private long[] groupIds; + @Builder.Default + private long[] groupIds = new long[0]; } 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 12b5d663..50dde960 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,7 @@ package de.filefighter.rest.domain.user.rest; import de.filefighter.rest.domain.common.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; import de.filefighter.rest.domain.token.data.dto.RefreshToken; @@ -8,6 +9,7 @@ import de.filefighter.rest.domain.user.business.UserBusinessService; import de.filefighter.rest.domain.user.data.dto.User; import de.filefighter.rest.domain.user.data.dto.UserRegisterForm; +import de.filefighter.rest.domain.user.data.persistence.UserEntity; import de.filefighter.rest.rest.ServerResponse; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -25,12 +27,14 @@ public class UserRestService implements UserRestServiceInterface { private final UserAuthorizationService userAuthorizationService; private final AccessTokenBusinessService accessTokenBusinessService; private final InputSanitizerService inputSanitizerService; + private final FileSystemBusinessService fileSystemBusinessService; - public UserRestService(UserBusinessService userBusinessService, UserAuthorizationService userAuthorizationService, AccessTokenBusinessService accessTokenBusinessService, InputSanitizerService inputSanitizerService) { + public UserRestService(UserBusinessService userBusinessService, UserAuthorizationService userAuthorizationService, AccessTokenBusinessService accessTokenBusinessService, InputSanitizerService inputSanitizerService, FileSystemBusinessService fileSystemBusinessService) { this.userBusinessService = userBusinessService; this.userAuthorizationService = userAuthorizationService; this.accessTokenBusinessService = accessTokenBusinessService; this.inputSanitizerService = inputSanitizerService; + this.fileSystemBusinessService = fileSystemBusinessService; } @Override @@ -82,7 +86,8 @@ public ResponseEntity registerNewUserWithAccessToken(UserRegiste AccessToken validAccessToken = accessTokenBusinessService.findAccessTokenByValue(sanitizedTokenString); userAuthorizationService.authenticateUserWithAccessTokenAndGroup(validAccessToken, ADMIN); - userBusinessService.registerNewUser(newUser); + UserEntity registeredUserEntity = userBusinessService.registerNewUser(newUser); + fileSystemBusinessService.createBasicFilesForNewUser(registeredUserEntity); return new ResponseEntity<>(new ServerResponse(HttpStatus.CREATED, "User successfully created."), HttpStatus.CREATED); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 0621d1b6..3ba536ef 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.5 -filefighter.date=21.11.2020 +filefighter.version=0.0.6 +filefighter.date=20.12.2020 filefighter.disable-password-check=false diff --git a/src/test/java/de/filefighter/rest/RestApplicationIntegrationTest.java b/src/test/java/de/filefighter/rest/RestApplicationIntegrationTest.java index ba17cd09..36d3778a 100644 --- a/src/test/java/de/filefighter/rest/RestApplicationIntegrationTest.java +++ b/src/test/java/de/filefighter/rest/RestApplicationIntegrationTest.java @@ -24,7 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat; -@SuppressWarnings("SameParameterValue") +@SuppressWarnings({"SameParameterValue", "squid:S5786"}) // public on test class. @ActiveProfiles("test") @SpringBootTest(classes = RestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class RestApplicationIntegrationTest { diff --git a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java index 575268c0..78583eb8 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CommonCucumberSteps.java @@ -20,7 +20,6 @@ import org.springframework.data.mongodb.core.query.Update; import java.io.IOException; -import java.util.Arrays; import static org.junit.jupiter.api.Assertions.*; @@ -32,6 +31,9 @@ public class CommonCucumberSteps extends RestApplicationIntegrationTest { private final FileSystemRepository fileSystemRepository; private final ObjectMapper objectMapper; + @Autowired + MongoTemplate mongoTemplate; + @Autowired public CommonCucumberSteps(UserRepository userRepository, AccessTokenRepository accessTokenRepository, FileSystemRepository fileSystemRepository) { this.userRepository = userRepository; @@ -78,9 +80,6 @@ public void userWithIdExistsAndHasUsernamePassword(long userId, String username, .build())); } - @Autowired - MongoTemplate mongoTemplate; - @And("user with userId {long} is in group with groupId {long}") public void userWithIdIsInGroupWithId(long userId, long groupId) { Query query = new Query(); @@ -90,60 +89,34 @@ public void userWithIdIsInGroupWithId(long userId, long groupId) { mongoTemplate.findAndModify(query, newUpdate, UserEntity.class); } - // This step almost needs a unit test. - @Given("{string} exists with fileSystemId {long} and path {string}") - public void fileOrFolderExistsWithIdAndPath(String fileOrFolder, long fsItemId, String path) { - String[] names = path.split("/"); - StringBuilder completeFilePath = new StringBuilder("/"); - - System.out.println(Arrays.toString(names)); + @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) { + fileSystemRepository.save(FileSystemEntity.builder() + .path(path) + .createdByUserId(userId) + .fileSystemId(fileSystemId) + .build()); + } - // build root dir. - fileSystemRepository.save(FileSystemEntity - .builder() - .isFile(false) - .path(completeFilePath.toString()) + @And("fileSystemItem with the fileSystemId {long} exists, was created by user with userId {long} and has the name {string}") + public void fileSystemItemWithTheFileSystemIdExistsAndHasTheName(long fileSystemId, long userId, String name) { + fileSystemRepository.save(FileSystemEntity.builder() + .name(name) + .createdByUserId(userId) + .fileSystemId(fileSystemId) .build()); + } + @And("fileSystemItem with the fileSystemId {long} is a folder and contains the fileSystemId {long}") + public void fileSystemItemWithTheFileSystemIdIsAFolderAndContainsTheFileSystemId(long fileSystemIdFolder, long fileSystemId) { + Query query = new Query(); + Update newUpdate = new Update().set("itemIds", new long[]{fileSystemId}); + query.addCriteria(Criteria.where("fileSystemId").is(fileSystemIdFolder)); - // build all files and folders. - for (int i = 0; i < names.length; i++) { - if (!names[i].isEmpty() && !names[i].isBlank()) { - boolean isLastOne = i == names.length - 1; - if (!isLastOne) { - //is obviously a folder. - completeFilePath.append(names[i]).append("/"); - fileSystemRepository.save(FileSystemEntity - .builder() - .isFile(false) - .path(completeFilePath.toString()) - .build()); - System.out.println("folder: " + completeFilePath.toString()); - } else { - System.out.println("last one: " + names[i]); - if (fileOrFolder.equals("file")) { - fileSystemRepository.save(FileSystemEntity - .builder() - .isFile(true) - .fileSystemId(fsItemId) - .build()); - } else if (fileOrFolder.equals("folder")) { - completeFilePath.append(names[i]).append("/"); - fileSystemRepository.save(FileSystemEntity - .builder() - .isFile(false) - .fileSystemId(fsItemId) - .path(completeFilePath.toString()) - .build()); - } else { - throw new IllegalArgumentException("Found not valid string for FileOrFolder in Steps file."); - } - } - } - } + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } - @And("user {long} is owner of file or folder with fileSystemId {long}") + @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); @@ -188,4 +161,5 @@ public void responseContainsKeyAndADifferentValueThan(String key, String differe assertNotEquals(differentValue, actualValue); } + } diff --git a/src/test/java/de/filefighter/rest/cucumber/CrudPermissionSteps.java b/src/test/java/de/filefighter/rest/cucumber/CrudPermissionSteps.java index d8bc96c8..9dafbdce 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CrudPermissionSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/CrudPermissionSteps.java @@ -1,33 +1,52 @@ package de.filefighter.rest.cucumber; import de.filefighter.rest.RestApplicationIntegrationTest; +import de.filefighter.rest.domain.filesystem.data.persistence.FileSystemEntity; import io.cucumber.java.en.And; -import io.cucumber.java.en.When; +import org.springframework.beans.factory.annotation.Autowired; +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; public class CrudPermissionSteps extends RestApplicationIntegrationTest { - @And("user {long} has permission of {string} for {string} with id {long}") - public void userHasPermissionOfForWithIdId(long userId, String readOrWrite, String fileOrFolder, long fsItemId) { - } + @Autowired + MongoTemplate mongoTemplate; - @When("user with token {string} wants to change permissions of {string} with id {long} for user with id {long} to {string}") - public void userWithTokenWantsToChangePermissionsOfWithIdIdForUserWithIdTo(String accessTokenValue, String fileOrFolder, long fsItemId, long userId, String newPermission) { - } + @And("group with the groupId {long} is allowed to VIEW the fileSystemItem with the fileSystemId {long}") + public void groupWithTheGroupIdIsAllowedToViewTheFileSystemItemWithTheFileSystemId(long groupId, long fileSystemId) { + Query query = new Query(); + Update newUpdate = new Update().set("visibleForGroupIds", new long[]{groupId}); + query.addCriteria(Criteria.where("fileSystemId").is(fileSystemId)); - @When("user with token {string} wants to remove permissions of {string} with id {long} for user {long}") - public void userWithTokenWantsToRemovePermissionsOfWithIdIdForUser(String accessTokenValue, String fileOrFolder, long fsItemId, long userId) { + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } - @And("user with id {long} has no permission for {string} with id {long}") - public void userWithIdHasNoPermissionForWithIdId(long userId, String fileOrFolder, long fsItemId) { - } + @And("group with the groupId {long} is allowed to EDIT the fileSystemItem with the fileSystemId {long}") + public void groupWithTheGroupIdIsAllowedToEditTheFileSystemItemWithTheFileSystemId(long groupId, long fileSystemId) { + Query query = new Query(); + Update newUpdate = new Update().set("editableForGroupIds", new long[]{groupId}); + query.addCriteria(Criteria.where("fileSystemId").is(fileSystemId)); - @And("user {long} has no permission for {string} with id {long}") - public void userHasNoPermissionForWithId(long userId, String fileOrFolder, long fsItemId) { + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } - @When("user with token {string} wants to give {string} permission for {string} with id {long} to user {long}") - public void userWithTokenWantsToAddPermissionsOfWithIdForUserFor(String accessTokenValue, String permission, String fileOrFolder, long fsItemId, long userId) { + @And("user with the userId {long} is allowed to VIEW the fileSystemItem with the fileSystemId {long}") + public void userWithTheUserIdIsAllowedToViewTheFileSystemItemWithTheFileSystemId(long userId, long fileSystemId) { + Query query = new Query(); + Update newUpdate = new Update().set("visibleForUserIds", new long[]{userId}); + query.addCriteria(Criteria.where("fileSystemId").is(fileSystemId)); + + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); } + @And("user with the userId {long} is allowed to EDIT the fileSystemItem with the fileSystemId {long}") + public void userWithTheUserIdIsAllowedToEditTheFileSystemItemWithTheFileSystemId(long userId, long fileSystemId) { + Query query = new Query(); + Update newUpdate = new Update().set("editableForUserIds", new long[]{userId}); + query.addCriteria(Criteria.where("fileSystemId").is(fileSystemId)); + + mongoTemplate.findAndModify(query, newUpdate, FileSystemEntity.class); + } } diff --git a/src/test/java/de/filefighter/rest/cucumber/CucumberIntegrationTest.java b/src/test/java/de/filefighter/rest/cucumber/CucumberIntegrationTest.java index 63b94ed5..2b215509 100644 --- a/src/test/java/de/filefighter/rest/cucumber/CucumberIntegrationTest.java +++ b/src/test/java/de/filefighter/rest/cucumber/CucumberIntegrationTest.java @@ -1,16 +1,16 @@ package de.filefighter.rest.cucumber; -import de.filefighter.rest.RestApplicationIntegrationTest; import io.cucumber.junit.Cucumber; import io.cucumber.junit.CucumberOptions; import io.cucumber.spring.CucumberContextConfiguration; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; - +import org.springframework.test.context.ActiveProfiles; @RunWith(Cucumber.class) @CucumberOptions(features = "src/test/resources") @CucumberContextConfiguration +@ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class CucumberIntegrationTest { } \ No newline at end of file diff --git a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java index decd45d2..6d24c1e6 100644 --- a/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java +++ b/src/test/java/de/filefighter/rest/cucumber/ViewFolderContentsSteps.java @@ -1,20 +1,63 @@ package de.filefighter.rest.cucumber; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import de.filefighter.rest.RestApplicationIntegrationTest; import io.cucumber.java.en.And; import io.cucumber.java.en.When; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; + +import java.util.HashMap; + +import static de.filefighter.rest.configuration.RestConfiguration.*; +import static org.junit.Assert.assertTrue; public class ViewFolderContentsSteps extends RestApplicationIntegrationTest { + private final ObjectMapper objectMapper; + + @Autowired + public ViewFolderContentsSteps(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + @When("user with token {string} wants to see the content of folder with path {string}") public void userWithTokenWantsToSeeTheContentOfFolderWithPath(String accessTokenValue, String path) { + String authHeaderString = AUTHORIZATION_BEARER_PREFIX + accessTokenValue; + String url = BASE_API_URI + FS_BASE_URI + "contents"; + + HashMap header = new HashMap<>(); + header.put("Authorization", authHeaderString); + header.put(FS_PATH_HEADER, path); + + executeRestApiCall(HttpMethod.GET, url, header); } @And("the response contains the file with fileSystemId {long} and name {string}") - public void theResponseContainsTheFileWithIdAndName(long fsItemId , String name) { + public void theResponseContainsTheFileWithIdAndName(long fsItemId, 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() == fsItemId && + node.get("name").asText().equals(name) && + node.get("type").asText().equals("FOLDER")) + found = true; + } + assertTrue(found); } @And("the response contains an empty list for files and folders") - public void theResponseContainsAnEmptyListForFilesAndFolders() { + public void theResponseContainsAnEmptyListForFilesAndFolders() throws JsonProcessingException { + ArrayNode rootNode = (ArrayNode) objectMapper.readTree(latestResponse.getBody()); + if (!rootNode.isContainerNode()) + throw new AssertionError("Response was not an Array or empty."); + + assertTrue(rootNode.isEmpty()); } } 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 new file mode 100644 index 00000000..665347ab --- /dev/null +++ b/src/test/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessServiceUnitTest.java @@ -0,0 +1,226 @@ +package de.filefighter.rest.domain.filesystem.business; + +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.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.group.Groups; +import de.filefighter.rest.rest.exceptions.FileFighterDataException; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class FileSystemBusinessServiceUnitTest { + + private final FileSystemRepository fileSystemRepositoryMock = mock(FileSystemRepository.class); + private final UserBusinessService userBusinessService = mock(UserBusinessService.class); + private final FileSystemTypeRepository fileSystemTypeRepository = mock(FileSystemTypeRepository.class); + private final FileSystemBusinessService fileSystemBusinessService = new FileSystemBusinessService(fileSystemRepositoryMock, userBusinessService, fileSystemTypeRepository); + + @Test + void getFolderContentsByPathThrows() { + String notValid = ""; + String wrongFormat = "asd"; + String wrongFormat1 = "as/d"; + String validPath = "/uga/uga/as/sasda/sassasd"; + + User dummyUser = User.builder().userId(0).build(); + + FileSystemContentsNotAccessibleException ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> + fileSystemBusinessService.getFolderContentsByPath(notValid, dummyUser)); + assertEquals("Folder contents could not be displayed. 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()); + + 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()); + + 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()); + + ArrayList fileSystemEntityArrayList = new ArrayList<>(); + fileSystemEntityArrayList.add(FileSystemEntity.builder().isFile(true).build()); + fileSystemEntityArrayList.add(FileSystemEntity.builder().isFile(false).typeId(-1).build()); + fileSystemEntityArrayList.add(FileSystemEntity.builder().createdByUserId(420).build()); + + when(fileSystemRepositoryMock.findByPath(validPath)).thenReturn(fileSystemEntityArrayList); + + ex = assertThrows(FileSystemContentsNotAccessibleException.class, () -> + fileSystemBusinessService.getFolderContentsByPath(validPath, dummyUser)); + assertEquals("Folder does not exist, or you are not allowed to see the folder.", ex.getMessage()); + } + + @Test + void getFolderContentsByPathWorks() { + String path = "/uga/buga/buga"; + String pathToRequest = path + "/"; + long userId = 420; + long fileIdInFolder = 123; + User user = User.builder().userId(userId).build(); + FileSystemEntity foundFolder = FileSystemEntity.builder().createdByUserId(userId).itemIds(new long[]{fileIdInFolder}).build(); + ArrayList entities = new ArrayList<>(); + entities.add(foundFolder); + + when(fileSystemRepositoryMock.findByPath(path)).thenReturn(entities); + when(fileSystemRepositoryMock.findByFileSystemId(fileIdInFolder)).thenReturn(FileSystemEntity.builder().createdByUserId(userId).build()); + when(userBusinessService.getUserById(userId)).thenReturn(User.builder().build()); + + ArrayList fileSystemItems = (ArrayList) fileSystemBusinessService.getFolderContentsByPath(pathToRequest, user); + assertEquals(1, fileSystemItems.size()); + } + + @Test + void getFolderContentsOfEntityThrows() { + long fileSystemId = 420; + + User authenticatedUser = User.builder().build(); + FileSystemEntity foundFolder = FileSystemEntity.builder().itemIds(new long[]{fileSystemId}).build(); + ArrayList arrayList = new ArrayList<>(); + arrayList.add(foundFolder); + + when(fileSystemRepositoryMock.findByFileSystemId(fileSystemId)).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()); + } + + @Test + void getFolderContentsOfEntityWorks() { + long userId = 420; + 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(userBusinessService.getUserById(userId)).thenReturn(User.builder().userId(userId).build()); + + ArrayList actual = (ArrayList) fileSystemBusinessService.getFolderContentsOfEntities(arrayList, authenticatedUser, "/"); + assertEquals(4, actual.size()); + } + + @Test + void removeTrailingWhiteSpaces() { + String doesNotRemove0 = "/"; + String doesNotRemove1 = "/ugabuga"; + String doesRemove = "/uga/"; + String removed = "/uga"; + + + String actual0 = fileSystemBusinessService.removeTrailingBackSlashes(doesNotRemove0); + assertEquals(doesNotRemove0, actual0); + + String actual1 = fileSystemBusinessService.removeTrailingBackSlashes(doesNotRemove1); + assertEquals(doesNotRemove1, actual1); + + String actual2 = fileSystemBusinessService.removeTrailingBackSlashes(doesRemove); + assertEquals(removed, actual2); + } + + @Test + void userIsAllowedToSeeFileSystemEntity() { + long userId = 1232783672; + User user = User.builder().userId(userId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity.builder().createdByUserId(userId).build(); + + // user created fileSystemItem + assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); + + // user got it shared. + fileSystemEntity = FileSystemEntity.builder().visibleForUserIds(new long[]{userId}).build(); + 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(); + assertTrue(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); + + // user is not allowed. + user = User.builder().userId(123).groups(new Groups[]{Groups.UNDEFINED}).build(); + fileSystemEntity = FileSystemEntity.builder().createdByUserId(321).visibleForGroupIds(new long[]{1}).build(); + assertFalse(fileSystemBusinessService.userIsAllowedToSeeFileSystemEntity(fileSystemEntity, user)); + } + + @Test + void createDTOWorks() { + long createdByUserId = 420L; + String basePath = "/someTHING/somethingElse/"; + long[] items = new long[]{1, 2, 3}; + long fileSystemId = 123123; + boolean isFile = true; + long lastUpdated = 123123; + String name = "SomeText.txt"; + double size = 123321; + long typeId = -1; + + User authenticatedUser = User.builder().userId(createdByUserId - 1).build(); + User userThatCreatedFile = User.builder().userId(createdByUserId).build(); + FileSystemEntity fileSystemEntity = FileSystemEntity + .builder() + .createdByUserId(createdByUserId) + .itemIds(items) + .fileSystemId(fileSystemId) + .isFile(isFile) + .lastUpdated(lastUpdated) + .name(name) + .path("") // is empty because its a file. + .size(size) + .typeId(typeId) + .build(); + + when(userBusinessService.getUserById(createdByUserId)).thenReturn(userThatCreatedFile); + when(fileSystemTypeRepository.findFileSystemTypeById(typeId)).thenReturn(FileSystemType.UNDEFINED); + + FileSystemItem actual = fileSystemBusinessService.createDTO(fileSystemEntity, authenticatedUser, basePath); + + assertEquals(createdByUserId, actual.getCreatedByUserId()); + assertEquals(fileSystemId, actual.getFileSystemId()); + assertEquals(lastUpdated, actual.getLastUpdated()); + assertEquals(name, actual.getName()); + assertEquals(size, actual.getSize()); + assertEquals(FileSystemType.UNDEFINED, actual.getType()); + assertEquals(basePath + name, actual.getPath()); + assertTrue(actual.isShared()); + } + + @Test + void getTotalFileSizeThrows() { + when(fileSystemRepositoryMock.findByPath("/")).thenReturn(null); + FileFighterDataException ex = assertThrows(FileFighterDataException.class, fileSystemBusinessService::getTotalFileSize); + assertEquals("Internal Error occurred. Couldn't find any Home directories!", ex.getMessage()); + } + + @Test + void getTotalFileSizeWorks() { + double size0 = 1.3; + double size1 = 2.4; + ArrayList entities = new ArrayList<>(); + entities.add(FileSystemEntity.builder().size(size0).build()); + entities.add(FileSystemEntity.builder().size(size1).build()); + + when(fileSystemRepositoryMock.findByPath("/")).thenReturn(entities); + + double actualSize = fileSystemBusinessService.getTotalFileSize(); + assertEquals(size0 + size1, actualSize); + } +} \ No newline at end of file diff --git a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java index cd28e3e8..b6ac4584 100644 --- a/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/filesystem/rest/FileSystemRestControllerUnitTest.java @@ -1,11 +1,15 @@ package de.filefighter.rest.domain.filesystem.rest; -import de.filefighter.rest.domain.filesystem.data.dto.*; +import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem; +import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItemUpdate; import de.filefighter.rest.rest.ServerResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import java.util.ArrayList; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -24,24 +28,22 @@ void setUp() { @Test void getContentsOfFolder() { - Folder dummyFolder = new Folder(); - File dummyFile = new File(); - ResponseEntity expectedModel = new ResponseEntity<>(FolderContents.builder() - .files(new File[]{dummyFile}) - .folders(new Folder[]{dummyFolder}).build(), OK); + ArrayList itemArrayList = new ArrayList<>(); + itemArrayList.add(FileSystemItem.builder().build()); - String path= "/root/data.txt"; + ResponseEntity> expectedModel = new ResponseEntity<>(itemArrayList, HttpStatus.OK); + String path = "/username/data.txt"; String token = "token"; when(fileSystemRestServiceMock.getContentsOfFolderByPathAndAccessToken(path, token)).thenReturn(expectedModel); - ResponseEntity actualModel = fileSystemRestController.getContentsOfFolder(path, token); - assertEquals(expectedModel, actualModel); + ResponseEntity> actualModel = fileSystemRestController.getContentsOfFolder(path, token); + assertEquals(itemArrayList, actualModel.getBody()); } @Test void getFileOrFolderInfo() { - File file = new File(); + FileSystemItem file = FileSystemItem.builder().build(); ResponseEntity expectedModel = new ResponseEntity<>(file, OK); long id = 420; @@ -55,7 +57,7 @@ void getFileOrFolderInfo() { @Test void searchFileOrFolderByName() { - File file = new File(); + FileSystemItem file = FileSystemItem.builder().build(); ResponseEntity expectedModel = new ResponseEntity<>(file, OK); String name = "randomFile.exe"; @@ -69,7 +71,7 @@ void searchFileOrFolderByName() { @Test void uploadFileOrFolder() { - File file = new File(); + FileSystemItem file = FileSystemItem.builder().build(); ResponseEntity expectedModel = new ResponseEntity<>(file, OK); FileSystemItemUpdate fileSystemItemUpdate = FileSystemItemUpdate.builder().name("ugabuga").build(); @@ -83,7 +85,7 @@ void uploadFileOrFolder() { @Test void updateExistingFileOrFolder() { - File file = new File(); + FileSystemItem file = FileSystemItem.builder().build(); ResponseEntity expectedModel = new ResponseEntity<>(file, OK); long id = 420L; diff --git a/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java b/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java index 0a4b6835..8e5d346c 100644 --- a/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java +++ b/src/test/java/de/filefighter/rest/domain/health/business/SystemHealthBusinessServiceUnitTest.java @@ -1,5 +1,6 @@ package de.filefighter.rest.domain.health.business; +import de.filefighter.rest.domain.filesystem.business.FileSystemBusinessService; import de.filefighter.rest.domain.health.data.SystemHealth; import de.filefighter.rest.domain.health.data.SystemHealth.DataIntegrity; import de.filefighter.rest.domain.token.business.AccessTokenBusinessService; @@ -18,22 +19,26 @@ class SystemHealthBusinessServiceUnitTest { private final UserBusinessService userBusinessServiceMock = mock(UserBusinessService.class); private final AccessTokenBusinessService accessTokenBusinessServiceMock = mock(AccessTokenBusinessService.class); + private final FileSystemBusinessService fileSystemBusinessService = mock(FileSystemBusinessService.class); private SystemHealthBusinessService systemHealthBusinessService; @BeforeEach void setUp() { - systemHealthBusinessService = new SystemHealthBusinessService(userBusinessServiceMock, accessTokenBusinessServiceMock); + systemHealthBusinessService = new SystemHealthBusinessService(userBusinessServiceMock, accessTokenBusinessServiceMock, fileSystemBusinessService); } @Test void getCurrentSystemHealthInfo() { long expectedUserCount = 420; + double expectedSize = 1234.532; when(userBusinessServiceMock.getUserCount()).thenReturn(expectedUserCount); + when(fileSystemBusinessService.getTotalFileSize()).thenReturn(expectedSize); SystemHealth systemHealth = systemHealthBusinessService.getCurrentSystemHealthInfo(); assertTrue(systemHealth.getUptimeInSeconds() >= 0); + assertEquals(expectedSize, systemHealth.getUsedStorageInMb()); assertEquals(expectedUserCount, systemHealth.getUserCount()); } 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 fb26a4e5..1086bc3e 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 @@ -19,7 +19,7 @@ class AccessTokenBusinessServiceUnitTest { private final AccessTokenRepository accessTokenRepositoryMock = mock(AccessTokenRepository.class); - private final AccessTokenDtoService accessTokenDtoServiceMock = mock(AccessTokenDtoService.class); + private final AccessTokenDTOService accessTokenDtoServiceMock = mock(AccessTokenDTOService.class); private AccessTokenBusinessService accessTokenBusinessService; @BeforeEach 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 b61f5eb1..5e886136 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 @@ -15,11 +15,11 @@ class AccessTokenDtoServiceUnitTest { private final AccessTokenRepository accessTokenRepository = mock(AccessTokenRepository.class); - private AccessTokenDtoService accessTokenDtoService; + private AccessTokenDTOService accessTokenDtoService; @BeforeEach void setUp() { - accessTokenDtoService = new AccessTokenDtoService(accessTokenRepository); + accessTokenDtoService = new AccessTokenDTOService(accessTokenRepository); } @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 61c87a9e..39ff9032 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 @@ -17,7 +17,7 @@ class UserAuthorizationServiceUnitTest { private final UserRepository userRepositoryMock = mock(UserRepository.class); - private final UserDtoService userDtoServiceMock = mock(UserDtoService.class); + private final UserDTOService userDtoServiceMock = mock(UserDTOService.class); private final UserAuthorizationService userAuthorizationService = new UserAuthorizationService( userRepositoryMock, userDtoServiceMock); 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 a5f9e20f..414a8f94 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 @@ -22,7 +22,7 @@ class UserBusinessServiceUnitTest { private final UserRepository userRepositoryMock = mock(UserRepository.class); - private final UserDtoService userDtoServiceMock = mock(UserDtoService.class); + private final UserDTOService userDtoServiceMock = mock(UserDTOService.class); private final GroupRepository groupRepositoryMock = mock(GroupRepository.class); private final MongoTemplate mongoTemplateMock = mock(MongoTemplate.class); private UserBusinessService userBusinessService; @@ -177,6 +177,7 @@ void passwordIsValidWorks() { @Test void registerNewUserThrows() { + String notValidUsername = null; String username = "ValidUserName"; String notValidPassword = "password"; String password = "validPassword1234"; @@ -190,11 +191,18 @@ void registerNewUserThrows() { .groupIds(groups) .build(); + // not valid. + userRegisterForm.setUsername(notValidUsername); + UserNotRegisteredException ex = assertThrows(UserNotRegisteredException.class, () -> + userBusinessService.registerNewUser(userRegisterForm)); + assertEquals("User could not be registered. Username was not valid.", ex.getMessage()); + // username taken + userRegisterForm.setUsername(username); when(userRepositoryMock.findByLowercaseUsername(username.toLowerCase())).thenReturn(UserEntity.builder().build()); when(userDtoServiceMock.createDto(any())).thenReturn(User.builder().build()); - UserNotRegisteredException ex = assertThrows(UserNotRegisteredException.class, () -> + ex = assertThrows(UserNotRegisteredException.class, () -> userBusinessService.registerNewUser(userRegisterForm)); assertEquals("User could not be registered. Username already taken.", ex.getMessage()); @@ -275,8 +283,9 @@ void updateUserThrows() { assertEquals("User could not get updated. 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, authenticatedUser)); + userBusinessService.updateUser(userId, userRegisterForm1, authenticatedUser1)); assertEquals("User could not get updated. Authenticated User is not allowed.", ex.getMessage()); authenticatedUser.setGroups(new Groups[]{Groups.UNDEFINED}); 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 2f7bc031..e5f19975 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 @@ -18,11 +18,11 @@ class UserDtoServiceUnitTest { private final GroupRepository groupRepositoryMock = mock(GroupRepository.class); private final UserRepository userRepositoryMock = mock(UserRepository.class); - private UserDtoService userDtoService; + private UserDTOService userDtoService; @BeforeEach void setUp() { - userDtoService = new UserDtoService(groupRepositoryMock, userRepositoryMock); + userDtoService = new UserDTOService(groupRepositoryMock, userRepositoryMock); } @Test diff --git a/src/test/resources/ViewFolderContents.feature b/src/test/resources/ViewFolderContents.feature index 0feefe0a..9dbe5956 100644 --- a/src/test/resources/ViewFolderContents.feature +++ b/src/test/resources/ViewFolderContents.feature @@ -1,53 +1,73 @@ -#Feature: View Folder -# As a user -# I want to see the content of folders and navigate in them, so they can see and interact with their uploaded and shared files. -# -#Background: -# Given database is empty -# And user 1234 exists -# And user 1234 has access token "900000" -# And "folder" exists with id 42 and path "bla" -# And "file" exists with id 72 and path "bla/wow.txt" -# -# -#Scenario: Successful interaction -# Given user 1234 has permission of "view" for "folder" with id 42 -# And user 1234 has permission of "view" for "file" with id 72 -# 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 id 72 and name "wow.txt" -# -# -#Scenario: Folder does not exist -# Given user 1234 has permission of "view" for "folder" with id 42 -# When user with token "900000" 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: insufficient authorization -# Given user 9877 exists -# And user 9877 has access token "2345678" -# When user with token "2345678" 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: shared file -# Given "folder" exists with id 43 and path "bla" -# And "file" exists with id 73 and path "bla/wow.txt" -# And user 1234 is owner of file or folder with id 42 -# And user 1234 is owner of file or folder with id 72 -# And user 1234 has permission of "view" for "folder" with id 43 -# And user 1234 has permission of "view" for "file" with id 73 -# 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 id 72 and name "wow.txt" -# And the response contains the file with id 73 and name "wow.txt" -# -#Scenario: empty directory -# Given "folder" exists with id 44 and path "empty" -# And user 1234 has permission of "view" for "folder" with id 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 +Feature: View Folder + As a user + I want to see the content of folders and navigate in them, so they can see and interact with their uploaded and shared files. + + 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 and has the path "/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 + + Scenario: Successful interaction + Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + And user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 72 + When user with token "900000" wants to see the content of folder with path "/bla" + Then response status code is 200 + And the response contains the file with fileSystemId 72 and name "wow.txt" + + Scenario: Folder does not exist + Given user with the userId 1234 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "900000" wants to see the content of folder with path "/bla/fasel" + Then response status code is 400 + And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + + Scenario: insufficient authorization + Given user 9877 exists + And accessToken with value "2345678" exists for user 9877 + And response contains key "message" and value "Folder does not exist, or you are not allowed to see the folder." + + Scenario: shared folder (user) + Given user 4321 exists + And accessToken with value "123321123" exists for user 4321 + And user with the userId 4321 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "123321123" wants to see the content of folder with path "/bla" + Then response status code is 200 + And the response contains an empty list for files and folders + + Scenario: shared folder and file (user) + Given user 4321 exists + And accessToken with value "123321123" exists for user 4321 + And user with the userId 4321 is allowed to VIEW the fileSystemItem with the fileSystemId 72 + And user with the userId 4321 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "123321123" wants to see the content of folder with path "/bla" + Then response status code is 200 + And the response contains the file with fileSystemId 72 and name "wow.txt" + + Scenario: shared folder (group) + Given user 4321 exists + And user with userId 4321 is in group with groupId 1 + And accessToken with value "123321123" exists for user 4321 + And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "123321123" wants to see the content of folder with path "/bla" + Then response status code is 200 + And the response contains an empty list for files and folders + + Scenario: shared folder and file (group) + Given user 4321 exists + And user with userId 4321 is in group with groupId 1 + And accessToken with value "123321123" exists for user 4321 + And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 72 + And group with the groupId 1 is allowed to VIEW the fileSystemItem with the fileSystemId 42 + When user with token "123321123" wants to see the content of folder with path "/bla" + Then response status code is 200 + And the response contains 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" + 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