Skip to content
This repository has been archived by the owner on Apr 5, 2024. It is now read-only.

Commit

Permalink
FF-295 - Upload Endpoint (#100)
Browse files Browse the repository at this point in the history
* added mvn dep, idk why

* add login step to user edit

* add feature files for upload and upload preflight

* Added function skeleton

* wip for preflight

* Fixed responses

* Added FileHandling

* Finished writing logic.

* kinda working steps

* Fixed preflight integration tests

* Made preflight integration tests better

* Kinda working upload

* removed todos, added recursive updating of timestamps

* add basic upload step

* Added todos.

* make findAllByFileSystemIdInAndName case insensitive for name

* Fixed one bug

* Upload endpoint now returns correct values

* adapted tests.

* Bumped Version to v0.0.8

* fixed tests, fixed workflows

* fixed another bug

* made file system contents request case insensitive

* made file system contents request case insensitive (2)

* Implemented Current Id as header for the content api

* added tests for response headers

* Added one missing unit test.

* small refactoring and added more integration tests.

* fixed filesystemid bug, added different db port on dev and debug

* fix merge

Co-authored-by: open-schnick <[email protected]>
Co-authored-by: Open Schnick <[email protected]>
  • Loading branch information
3 people authored May 13, 2021
1 parent a1431ad commit cdccd96
Show file tree
Hide file tree
Showing 42 changed files with 1,450 additions and 148 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/featureRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,4 @@ jobs:
IMAGE_ID=$(docker images rest -q)
VERSION=feature
docker tag $IMAGE_ID filefighter/rest:$VERSION
docker tag $IMAGE_ID filefighter/rest:stable
docker push filefighter/rest:$VERSION
docker push filefighter/rest:stable
2 changes: 2 additions & 0 deletions .github/workflows/stableRelease.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ jobs:
IMAGE_ID=$(docker images rest -q)
VERSION=${{ steps.vars.outputs.tag }}
docker tag $IMAGE_ID filefighter/rest:$VERSION
docker tag $IMAGE_ID filefighter/rest:stable
docker push filefighter/rest:$VERSION
docker push filefighter/rest:stable
1 change: 1 addition & 0 deletions .run/JUnit Tests.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Unit Tests" type="JUnit" factoryName="JUnit">
<module name="RestApi"/>
<useClassPathOnly />
<option name="ALTERNATIVE_JRE_PATH" value="11" />
<option name="PACKAGE_NAME" value="" />
Expand Down
11 changes: 8 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>
<groupId>de.filefighter</groupId>
<artifactId>rest</artifactId>
<version>0.0.7</version>
<version>0.0.8</version>
<name>RestApi</name>
<description>RestApi for FileFighter</description>

Expand Down Expand Up @@ -122,6 +122,11 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.4.4</version>
</dependency>
<!-- TESTING -->

</dependencies>
Expand Down Expand Up @@ -208,14 +213,14 @@
</includes>
<excludes>
<!-- NOT IMPLEMENTED YET -->
<exclude>*FileSystemRestService</exclude>
<exclude>*PermissionRestService</exclude>
<exclude>*FileSystemRestService</exclude>
</excludes>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>95%</minimum>
<minimum>85%</minimum>
</limit>
</limits>
</rule>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class PrepareDataBase {
String date;

@Bean
@Profile({"dev", "prod, stage", "debug"})
@Profile({"dev", "prod", "stage", "debug"})
@Autowired
CommandLineRunner veryImportantFileFighterStartScript(Environment environment) {
return args -> {
Expand Down Expand Up @@ -74,7 +74,7 @@ CommandLineRunner veryImportantFileFighterStartScript(Environment environment) {
}

@Bean
@Profile("prod")
@Profile({"prod", "stage"})
CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {
return args -> {
ArrayList<UserEntity> foundUsers = (ArrayList<UserEntity>) userRepository.findAll();
Expand All @@ -101,7 +101,8 @@ CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepo
fileSystemRepository.save(FileSystemEntity.builder()
.lastUpdatedBy(RUNTIME_USER_ID)
.lastUpdated(Instant.now().getEpochSecond())
.ownerId(1).fileSystemId(1)
.ownerId(1)
.fileSystemId(1)
.isFile(true)
.name("dummyFile.txt")
.size(420)
Expand Down Expand Up @@ -179,38 +180,6 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo
};
}

@Bean
@Profile("stage")
CommandLineRunner initDataBaseStage(UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {
return args -> {
ArrayList<UserEntity> foundUsers = (ArrayList<UserEntity>) userRepository.findAll();
ArrayList<UserEntity> foundFileSystemEntities = (ArrayList<UserEntity>) userRepository.findAll();
accessTokenRepository.deleteAll(); // Cleanup purposes.

if (foundUsers.isEmpty() && foundFileSystemEntities.isEmpty()) {
addDevUsers(userRepository);
addTestingFileSystemItems(fileSystemRepository);

if (userRepository.findAll().size() == 2) {
log.info("Inserting Users " + MESSAGE_ON_SUCCESS);
} else {
log.error("Inserting Users " + MESSAGE_ON_FAILURE);
}

if (fileSystemRepository.findAll().size() == 6) {
log.info("Inserting FileSystemEntities " + MESSAGE_ON_SUCCESS);
} else {
log.error("Inserting FileSystemEntities " + MESSAGE_ON_FAILURE);
}
} else if (foundUsers.isEmpty() ^ foundFileSystemEntities.isEmpty()) {
// Exclusive "or".
throw new FileFighterDataException("The Database failed the sanity check, contact the developers or reinstall FileFighter.");
} else {
log.info("Checked Database, found Entities, didn't change anything.");
}
};
}

private void addDevUsers(UserRepository userRepository) {
log.info("Inserting system runtime user. {}", userRepository.save(UserEntity
.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ public class RestConfiguration {
public static final String AUTHORIZATION_BEARER_PREFIX = "Bearer ";
public static final String FS_BASE_URI = "/filesystem/";
public static final String FS_PATH_HEADER = "X-FF-PATH";
public static final String FS_CURRENT_ID_HEADER = "X-FF-CURRENT";
public static final String USER_BASE_URI = "/users/";
public static final String DEFAULT_ERROR_URI = "/error";
public static final long RUNTIME_USER_ID = 0;

private RestConfiguration(){
private RestConfiguration() {
// Cannot be instantiated.
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.filefighter.rest.domain.common;

import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException;
import de.filefighter.rest.domain.filesystem.data.dto.upload.FileSystemUpload;
import org.springframework.stereotype.Service;

import java.util.regex.Matcher;
Expand Down Expand Up @@ -33,6 +34,13 @@ public String sanitizePath(String path) {
return sanitizeString(path);
}

// TODO assure that the path and name are valid
public FileSystemUpload sanitizeUpload(FileSystemUpload fileSystemUpload) {
fileSystemUpload.setPath(sanitizePath(fileSystemUpload.getPath()));
fileSystemUpload.setName(sanitizeString(fileSystemUpload.getName()));
return fileSystemUpload;
}

public String sanitizeRequestHeader(String header, String testString) {
if (!(stringIsValid(testString) && stringIsValid(header)))
throw new RequestDidntMeetFormalRequirementsException("Header does not contain a valid String.");
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/de/filefighter/rest/domain/common/Pair.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.filefighter.rest.domain.common;

import lombok.Data;

@Data
public class Pair<F, S> {
private final F first;
private final S second;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.filefighter.rest.domain.filesystem.business;

import de.filefighter.rest.domain.common.Pair;
import de.filefighter.rest.domain.common.exceptions.FileFighterDataException;
import de.filefighter.rest.domain.filesystem.data.InteractionType;
import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem;
Expand Down Expand Up @@ -39,12 +40,15 @@ public FileSystemBusinessService(FileSystemRepository fileSystemRepository, File
}

@SuppressWarnings("java:S3776")
public List<FileSystemItem> getFolderContentsByPath(String path, User authenticatedUser) {
public Pair<List<FileSystemItem>, Long> getFolderContentsByPath(String path, User authenticatedUser) {
String[] pathWithoutSlashes = path.split("/");

String pathToFind;
User ownerOfRequestedFolder = null;

// make path case insensitive
path = path.toLowerCase();

if (path.equals("/")) {
pathToFind = "/";
} else {
Expand All @@ -57,7 +61,7 @@ public List<FileSystemItem> getFolderContentsByPath(String path, User authentica
// the first path must be the the username.
try {
ownerOfRequestedFolder = userBusinessService.findUserByUsername(pathWithoutSlashes[1]);
String[] fileSystemPath = path.split(ownerOfRequestedFolder.getUsername());
String[] fileSystemPath = path.split(ownerOfRequestedFolder.getUsername().toLowerCase());
if (fileSystemPath.length == 1) {
if (!fileSystemPath[0].equals("/"))
throw new FileSystemContentsNotAccessibleException();
Expand All @@ -74,7 +78,7 @@ public List<FileSystemItem> getFolderContentsByPath(String path, User authentica
pathToFind = fileSystemHelperService.removeTrailingBackSlashes(pathToFind).toLowerCase();

// find the folder with matching path.
ArrayList<FileSystemEntity> listOfPossibleDirectories = fileSystemRepository.findByPath(pathToFind);
List<FileSystemEntity> listOfPossibleDirectories = fileSystemRepository.findByPath(pathToFind);
if (null == listOfPossibleDirectories) // does return null and not a empty collection.
throw new FileSystemContentsNotAccessibleException();

Expand All @@ -91,7 +95,7 @@ public List<FileSystemItem> getFolderContentsByPath(String path, User authentica
fileSystemItems.add(fileSystemHelperService.createDTO(folder, authenticatedUser, "/"));
}

return fileSystemItems;
return new Pair<>(fileSystemItems, -1L);
} else {
User finalOwnerOfRequestedFolder = ownerOfRequestedFolder;
listOfPossibleDirectories.removeIf(entity -> (entity.isFile() || entity.getTypeId() != FileSystemType.FOLDER.getId() || entity.getOwnerId() != finalOwnerOfRequestedFolder.getUserId()));
Expand All @@ -104,18 +108,24 @@ public List<FileSystemItem> getFolderContentsByPath(String path, User authentica
throw new FileFighterDataException("Found more than one folder with the path " + pathToFind);

// check if the autheticatedUser can access this.
if (!fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(listOfPossibleDirectories.get(0), authenticatedUser, InteractionType.READ))
FileSystemEntity parentFolder = listOfPossibleDirectories.get(0);
if (!fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(parentFolder, authenticatedUser, InteractionType.READ))
throw new FileSystemContentsNotAccessibleException();

ArrayList<FileSystemItem> fileSystemItems = new ArrayList<>();
List<FileSystemEntity> folderContents =
fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfPossibleDirectories.get(0), authenticatedUser, true, false);
fileSystemHelperService.getFolderContentsOfEntityAndPermissions(parentFolder, authenticatedUser, true, false);

for (FileSystemEntity fileSystemEntityInFolder : folderContents) {
fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, "/" + ownerOfRequestedFolder.getUsername() + pathToFind));
String absolutePathToEntity = "/" + ownerOfRequestedFolder.getUsername() + pathToFind;
if (!pathToFind.equals("/")) {
absolutePathToEntity = absolutePathToEntity + "/";
}
absolutePathToEntity = absolutePathToEntity + fileSystemEntityInFolder.getName();
fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, absolutePathToEntity));
}

return fileSystemItems;
return new Pair<>(fileSystemItems, parentFolder.getFileSystemId());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.filefighter.rest.domain.filesystem.business;

import de.filefighter.rest.configuration.RestConfiguration;
import de.filefighter.rest.domain.common.InputSanitizerService;
import de.filefighter.rest.domain.common.exceptions.FileFighterDataException;
import de.filefighter.rest.domain.filesystem.data.InteractionType;
import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem;
Expand Down Expand Up @@ -51,10 +52,10 @@ public FileSystemEntity sumUpAllPermissionsOfFileSystemEntities(FileSystemEntity
addPermissionsToSets(visibleForUserIds, visibleForGroupIds, editableForUserIds, editableGroupIds, entity);
}

parentFileSystemEntity.setVisibleForUserIds(Arrays.stream(visibleForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
parentFileSystemEntity.setVisibleForGroupIds(Arrays.stream(visibleForGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
parentFileSystemEntity.setEditableForUserIds(Arrays.stream(editableForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
parentFileSystemEntity.setEditableFoGroupIds(Arrays.stream(editableGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
parentFileSystemEntity.setVisibleForUserIds(this.transformLongCollectionTolongArray(visibleForUserIds));
parentFileSystemEntity.setVisibleForGroupIds(this.transformLongCollectionTolongArray(visibleForGroupIds));
parentFileSystemEntity.setEditableForUserIds(this.transformLongCollectionTolongArray(editableForUserIds));
parentFileSystemEntity.setEditableFoGroupIds(this.transformLongCollectionTolongArray(editableGroupIds));
return parentFileSystemEntity;
}

Expand Down Expand Up @@ -199,10 +200,10 @@ public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenti

if (absolutePathWithUsername != null) {
if (absolutePathWithUsername.equals("/")) {
absolutePathWithUsername = absolutePathWithUsername + ownerOfFileSystemItem.getUsername(); // this is only for the case of the path = "/"
absolutePathWithUsername = (absolutePathWithUsername + ownerOfFileSystemItem.getUsername()).toLowerCase(); // this is only for the case of the path = "/"
entityName = ownerOfFileSystemItem.getUsername();
} else {
absolutePathWithUsername = this.removeTrailingBackSlashes(absolutePathWithUsername) + "/" + fileSystemEntity.getName();
absolutePathWithUsername = this.removeTrailingBackSlashes(absolutePathWithUsername).toLowerCase();
}
}

Expand Down Expand Up @@ -282,8 +283,43 @@ public void recursivlyUpdateTimeStamps(FileSystemEntity currentEntity, User auth
}
}

public String[] splitPathIntoEnitityPaths(String path, String basePath) {
Object[] paths = Arrays.stream(path.split("/")).filter(s -> !s.isEmpty()).toArray();
String[] returnString = new String[paths.length];

// if the path is empty or null make it look like its a "/"
if (null == basePath || basePath.isEmpty() || basePath.isBlank()) {
basePath = "/";
}
StringBuilder pathStringBuilder = new StringBuilder(basePath);
for (int i = 0; i < paths.length; i++) {
if (pathStringBuilder.toString().charAt(pathStringBuilder.toString().length() - 1) != '/') {
pathStringBuilder.append("/");
}
pathStringBuilder.append(paths[i]);
returnString[i] = pathStringBuilder.toString();
}
return returnString;
}

public String getEntityNameFromPath(String path) {
String[] splittedPath = path.split("/");
try {
return splittedPath[splittedPath.length - 1];
} catch (ArrayIndexOutOfBoundsException ex) {
log.debug("path was {}.", path);
throw new FileFighterDataException("Path to check was not valid");
}
}

public String getParentPathFromPath(String path) {
String entityName = getEntityNameFromPath(path);
String parent = path.substring(0, path.length() - entityName.length() - 1);
return parent.equals("") ? "/" : parent;
}

public double getTotalFileSize() {
ArrayList<FileSystemEntity> entities = fileSystemRepository.findByPath("/");
List<FileSystemEntity> entities = fileSystemRepository.findByPath("/");
if (null == entities)
throw new FileFighterDataException("Couldn't find any Home directories!");

Expand All @@ -294,6 +330,37 @@ public double getTotalFileSize() {
return size;
}

public long[] addLongToLongArray(long[] array, long newLong) {
long[] newArray = new long[array.length + 1];
System.arraycopy(array, 0, newArray, 0, array.length);
newArray[array.length] = newLong;
return newArray;
}

public Long[] transformlongArrayToLong(long[] arrayToTransform) {
Long[] longArgument = new Long[arrayToTransform.length];
int i = 0;

for (long temp : arrayToTransform) {
longArgument[i++] = temp;
}
return longArgument;
}

public String removeLeadingSlash(String path) {
if (!InputSanitizerService.stringIsValid(path))
throw new IllegalArgumentException("Couldn't remove leading slash because the path was not a valid String.");

if (path.startsWith("/")) {
path = path.substring(1);
}
return path;
}

public long[] transformLongCollectionTolongArray(Collection<Long> collectionToTransform) {
return Arrays.stream(collectionToTransform.toArray(new Long[0])).mapToLong(Long::longValue).toArray();
}

public long getFileSystemEntityCount() {
return fileSystemRepository.count();
}
Expand Down
Loading

0 comments on commit cdccd96

Please sign in to comment.