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

Commit cdccd96

Browse files
FF-295 - Upload Endpoint (#100)
* 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]>
1 parent a1431ad commit cdccd96

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1450
-148
lines changed

.github/workflows/featureRelease.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,4 @@ jobs:
3636
IMAGE_ID=$(docker images rest -q)
3737
VERSION=feature
3838
docker tag $IMAGE_ID filefighter/rest:$VERSION
39-
docker tag $IMAGE_ID filefighter/rest:stable
4039
docker push filefighter/rest:$VERSION
41-
docker push filefighter/rest:stable

.github/workflows/stableRelease.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ jobs:
3535
IMAGE_ID=$(docker images rest -q)
3636
VERSION=${{ steps.vars.outputs.tag }}
3737
docker tag $IMAGE_ID filefighter/rest:$VERSION
38+
docker tag $IMAGE_ID filefighter/rest:stable
3839
docker push filefighter/rest:$VERSION
40+
docker push filefighter/rest:stable

.run/JUnit Tests.run.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<component name="ProjectRunConfigurationManager">
22
<configuration default="false" name="Run Unit Tests" type="JUnit" factoryName="JUnit">
3+
<module name="RestApi"/>
34
<useClassPathOnly />
45
<option name="ALTERNATIVE_JRE_PATH" value="11" />
56
<option name="PACKAGE_NAME" value="" />

pom.xml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111
<groupId>de.filefighter</groupId>
1212
<artifactId>rest</artifactId>
13-
<version>0.0.7</version>
13+
<version>0.0.8</version>
1414
<name>RestApi</name>
1515
<description>RestApi for FileFighter</description>
1616

@@ -122,6 +122,11 @@
122122
</exclusion>
123123
</exclusions>
124124
</dependency>
125+
<dependency>
126+
<groupId>org.springframework.boot</groupId>
127+
<artifactId>spring-boot</artifactId>
128+
<version>2.4.4</version>
129+
</dependency>
125130
<!-- TESTING -->
126131

127132
</dependencies>
@@ -208,14 +213,14 @@
208213
</includes>
209214
<excludes>
210215
<!-- NOT IMPLEMENTED YET -->
211-
<exclude>*FileSystemRestService</exclude>
212216
<exclude>*PermissionRestService</exclude>
217+
<exclude>*FileSystemRestService</exclude>
213218
</excludes>
214219
<limits>
215220
<limit>
216221
<counter>LINE</counter>
217222
<value>COVEREDRATIO</value>
218-
<minimum>95%</minimum>
223+
<minimum>85%</minimum>
219224
</limit>
220225
</limits>
221226
</rule>

src/main/java/de/filefighter/rest/configuration/PrepareDataBase.java

Lines changed: 4 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class PrepareDataBase {
4545
String date;
4646

4747
@Bean
48-
@Profile({"dev", "prod, stage", "debug"})
48+
@Profile({"dev", "prod", "stage", "debug"})
4949
@Autowired
5050
CommandLineRunner veryImportantFileFighterStartScript(Environment environment) {
5151
return args -> {
@@ -74,7 +74,7 @@ CommandLineRunner veryImportantFileFighterStartScript(Environment environment) {
7474
}
7575

7676
@Bean
77-
@Profile("prod")
77+
@Profile({"prod", "stage"})
7878
CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {
7979
return args -> {
8080
ArrayList<UserEntity> foundUsers = (ArrayList<UserEntity>) userRepository.findAll();
@@ -101,7 +101,8 @@ CommandLineRunner initDataBaseProd(UserRepository userRepository, FileSystemRepo
101101
fileSystemRepository.save(FileSystemEntity.builder()
102102
.lastUpdatedBy(RUNTIME_USER_ID)
103103
.lastUpdated(Instant.now().getEpochSecond())
104-
.ownerId(1).fileSystemId(1)
104+
.ownerId(1)
105+
.fileSystemId(1)
105106
.isFile(true)
106107
.name("dummyFile.txt")
107108
.size(420)
@@ -179,38 +180,6 @@ CommandLineRunner initDataBaseDev(UserRepository userRepository, AccessTokenRepo
179180
};
180181
}
181182

182-
@Bean
183-
@Profile("stage")
184-
CommandLineRunner initDataBaseStage(UserRepository userRepository, FileSystemRepository fileSystemRepository, AccessTokenRepository accessTokenRepository) {
185-
return args -> {
186-
ArrayList<UserEntity> foundUsers = (ArrayList<UserEntity>) userRepository.findAll();
187-
ArrayList<UserEntity> foundFileSystemEntities = (ArrayList<UserEntity>) userRepository.findAll();
188-
accessTokenRepository.deleteAll(); // Cleanup purposes.
189-
190-
if (foundUsers.isEmpty() && foundFileSystemEntities.isEmpty()) {
191-
addDevUsers(userRepository);
192-
addTestingFileSystemItems(fileSystemRepository);
193-
194-
if (userRepository.findAll().size() == 2) {
195-
log.info("Inserting Users " + MESSAGE_ON_SUCCESS);
196-
} else {
197-
log.error("Inserting Users " + MESSAGE_ON_FAILURE);
198-
}
199-
200-
if (fileSystemRepository.findAll().size() == 6) {
201-
log.info("Inserting FileSystemEntities " + MESSAGE_ON_SUCCESS);
202-
} else {
203-
log.error("Inserting FileSystemEntities " + MESSAGE_ON_FAILURE);
204-
}
205-
} else if (foundUsers.isEmpty() ^ foundFileSystemEntities.isEmpty()) {
206-
// Exclusive "or".
207-
throw new FileFighterDataException("The Database failed the sanity check, contact the developers or reinstall FileFighter.");
208-
} else {
209-
log.info("Checked Database, found Entities, didn't change anything.");
210-
}
211-
};
212-
}
213-
214183
private void addDevUsers(UserRepository userRepository) {
215184
log.info("Inserting system runtime user. {}", userRepository.save(UserEntity
216185
.builder()

src/main/java/de/filefighter/rest/configuration/RestConfiguration.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ public class RestConfiguration {
88
public static final String AUTHORIZATION_BEARER_PREFIX = "Bearer ";
99
public static final String FS_BASE_URI = "/filesystem/";
1010
public static final String FS_PATH_HEADER = "X-FF-PATH";
11+
public static final String FS_CURRENT_ID_HEADER = "X-FF-CURRENT";
1112
public static final String USER_BASE_URI = "/users/";
1213
public static final String DEFAULT_ERROR_URI = "/error";
1314
public static final long RUNTIME_USER_ID = 0;
1415

15-
private RestConfiguration(){
16+
private RestConfiguration() {
1617
// Cannot be instantiated.
1718
}
1819
}

src/main/java/de/filefighter/rest/domain/common/InputSanitizerService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package de.filefighter.rest.domain.common;
22

33
import de.filefighter.rest.domain.common.exceptions.RequestDidntMeetFormalRequirementsException;
4+
import de.filefighter.rest.domain.filesystem.data.dto.upload.FileSystemUpload;
45
import org.springframework.stereotype.Service;
56

67
import java.util.regex.Matcher;
@@ -33,6 +34,13 @@ public String sanitizePath(String path) {
3334
return sanitizeString(path);
3435
}
3536

37+
// TODO assure that the path and name are valid
38+
public FileSystemUpload sanitizeUpload(FileSystemUpload fileSystemUpload) {
39+
fileSystemUpload.setPath(sanitizePath(fileSystemUpload.getPath()));
40+
fileSystemUpload.setName(sanitizeString(fileSystemUpload.getName()));
41+
return fileSystemUpload;
42+
}
43+
3644
public String sanitizeRequestHeader(String header, String testString) {
3745
if (!(stringIsValid(testString) && stringIsValid(header)))
3846
throw new RequestDidntMeetFormalRequirementsException("Header does not contain a valid String.");
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package de.filefighter.rest.domain.common;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class Pair<F, S> {
7+
private final F first;
8+
private final S second;
9+
}

src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemBusinessService.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package de.filefighter.rest.domain.filesystem.business;
22

3+
import de.filefighter.rest.domain.common.Pair;
34
import de.filefighter.rest.domain.common.exceptions.FileFighterDataException;
45
import de.filefighter.rest.domain.filesystem.data.InteractionType;
56
import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem;
@@ -39,12 +40,15 @@ public FileSystemBusinessService(FileSystemRepository fileSystemRepository, File
3940
}
4041

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

4546
String pathToFind;
4647
User ownerOfRequestedFolder = null;
4748

49+
// make path case insensitive
50+
path = path.toLowerCase();
51+
4852
if (path.equals("/")) {
4953
pathToFind = "/";
5054
} else {
@@ -57,7 +61,7 @@ public List<FileSystemItem> getFolderContentsByPath(String path, User authentica
5761
// the first path must be the the username.
5862
try {
5963
ownerOfRequestedFolder = userBusinessService.findUserByUsername(pathWithoutSlashes[1]);
60-
String[] fileSystemPath = path.split(ownerOfRequestedFolder.getUsername());
64+
String[] fileSystemPath = path.split(ownerOfRequestedFolder.getUsername().toLowerCase());
6165
if (fileSystemPath.length == 1) {
6266
if (!fileSystemPath[0].equals("/"))
6367
throw new FileSystemContentsNotAccessibleException();
@@ -74,7 +78,7 @@ public List<FileSystemItem> getFolderContentsByPath(String path, User authentica
7478
pathToFind = fileSystemHelperService.removeTrailingBackSlashes(pathToFind).toLowerCase();
7579

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

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

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

106110
// check if the autheticatedUser can access this.
107-
if (!fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(listOfPossibleDirectories.get(0), authenticatedUser, InteractionType.READ))
111+
FileSystemEntity parentFolder = listOfPossibleDirectories.get(0);
112+
if (!fileSystemHelperService.userIsAllowedToInteractWithFileSystemEntity(parentFolder, authenticatedUser, InteractionType.READ))
108113
throw new FileSystemContentsNotAccessibleException();
109114

110115
ArrayList<FileSystemItem> fileSystemItems = new ArrayList<>();
111116
List<FileSystemEntity> folderContents =
112-
fileSystemHelperService.getFolderContentsOfEntityAndPermissions(listOfPossibleDirectories.get(0), authenticatedUser, true, false);
117+
fileSystemHelperService.getFolderContentsOfEntityAndPermissions(parentFolder, authenticatedUser, true, false);
113118

114119
for (FileSystemEntity fileSystemEntityInFolder : folderContents) {
115-
fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, "/" + ownerOfRequestedFolder.getUsername() + pathToFind));
120+
String absolutePathToEntity = "/" + ownerOfRequestedFolder.getUsername() + pathToFind;
121+
if (!pathToFind.equals("/")) {
122+
absolutePathToEntity = absolutePathToEntity + "/";
123+
}
124+
absolutePathToEntity = absolutePathToEntity + fileSystemEntityInFolder.getName();
125+
fileSystemItems.add(fileSystemHelperService.createDTO(fileSystemEntityInFolder, authenticatedUser, absolutePathToEntity));
116126
}
117127

118-
return fileSystemItems;
128+
return new Pair<>(fileSystemItems, parentFolder.getFileSystemId());
119129
}
120130
}
121131

src/main/java/de/filefighter/rest/domain/filesystem/business/FileSystemHelperService.java

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package de.filefighter.rest.domain.filesystem.business;
22

33
import de.filefighter.rest.configuration.RestConfiguration;
4+
import de.filefighter.rest.domain.common.InputSanitizerService;
45
import de.filefighter.rest.domain.common.exceptions.FileFighterDataException;
56
import de.filefighter.rest.domain.filesystem.data.InteractionType;
67
import de.filefighter.rest.domain.filesystem.data.dto.FileSystemItem;
@@ -51,10 +52,10 @@ public FileSystemEntity sumUpAllPermissionsOfFileSystemEntities(FileSystemEntity
5152
addPermissionsToSets(visibleForUserIds, visibleForGroupIds, editableForUserIds, editableGroupIds, entity);
5253
}
5354

54-
parentFileSystemEntity.setVisibleForUserIds(Arrays.stream(visibleForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
55-
parentFileSystemEntity.setVisibleForGroupIds(Arrays.stream(visibleForGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
56-
parentFileSystemEntity.setEditableForUserIds(Arrays.stream(editableForUserIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
57-
parentFileSystemEntity.setEditableFoGroupIds(Arrays.stream(editableGroupIds.toArray(new Long[0])).mapToLong(Long::longValue).toArray());
55+
parentFileSystemEntity.setVisibleForUserIds(this.transformLongCollectionTolongArray(visibleForUserIds));
56+
parentFileSystemEntity.setVisibleForGroupIds(this.transformLongCollectionTolongArray(visibleForGroupIds));
57+
parentFileSystemEntity.setEditableForUserIds(this.transformLongCollectionTolongArray(editableForUserIds));
58+
parentFileSystemEntity.setEditableFoGroupIds(this.transformLongCollectionTolongArray(editableGroupIds));
5859
return parentFileSystemEntity;
5960
}
6061

@@ -199,10 +200,10 @@ public FileSystemItem createDTO(FileSystemEntity fileSystemEntity, User authenti
199200

200201
if (absolutePathWithUsername != null) {
201202
if (absolutePathWithUsername.equals("/")) {
202-
absolutePathWithUsername = absolutePathWithUsername + ownerOfFileSystemItem.getUsername(); // this is only for the case of the path = "/"
203+
absolutePathWithUsername = (absolutePathWithUsername + ownerOfFileSystemItem.getUsername()).toLowerCase(); // this is only for the case of the path = "/"
203204
entityName = ownerOfFileSystemItem.getUsername();
204205
} else {
205-
absolutePathWithUsername = this.removeTrailingBackSlashes(absolutePathWithUsername) + "/" + fileSystemEntity.getName();
206+
absolutePathWithUsername = this.removeTrailingBackSlashes(absolutePathWithUsername).toLowerCase();
206207
}
207208
}
208209

@@ -282,8 +283,43 @@ public void recursivlyUpdateTimeStamps(FileSystemEntity currentEntity, User auth
282283
}
283284
}
284285

286+
public String[] splitPathIntoEnitityPaths(String path, String basePath) {
287+
Object[] paths = Arrays.stream(path.split("/")).filter(s -> !s.isEmpty()).toArray();
288+
String[] returnString = new String[paths.length];
289+
290+
// if the path is empty or null make it look like its a "/"
291+
if (null == basePath || basePath.isEmpty() || basePath.isBlank()) {
292+
basePath = "/";
293+
}
294+
StringBuilder pathStringBuilder = new StringBuilder(basePath);
295+
for (int i = 0; i < paths.length; i++) {
296+
if (pathStringBuilder.toString().charAt(pathStringBuilder.toString().length() - 1) != '/') {
297+
pathStringBuilder.append("/");
298+
}
299+
pathStringBuilder.append(paths[i]);
300+
returnString[i] = pathStringBuilder.toString();
301+
}
302+
return returnString;
303+
}
304+
305+
public String getEntityNameFromPath(String path) {
306+
String[] splittedPath = path.split("/");
307+
try {
308+
return splittedPath[splittedPath.length - 1];
309+
} catch (ArrayIndexOutOfBoundsException ex) {
310+
log.debug("path was {}.", path);
311+
throw new FileFighterDataException("Path to check was not valid");
312+
}
313+
}
314+
315+
public String getParentPathFromPath(String path) {
316+
String entityName = getEntityNameFromPath(path);
317+
String parent = path.substring(0, path.length() - entityName.length() - 1);
318+
return parent.equals("") ? "/" : parent;
319+
}
320+
285321
public double getTotalFileSize() {
286-
ArrayList<FileSystemEntity> entities = fileSystemRepository.findByPath("/");
322+
List<FileSystemEntity> entities = fileSystemRepository.findByPath("/");
287323
if (null == entities)
288324
throw new FileFighterDataException("Couldn't find any Home directories!");
289325

@@ -294,6 +330,37 @@ public double getTotalFileSize() {
294330
return size;
295331
}
296332

333+
public long[] addLongToLongArray(long[] array, long newLong) {
334+
long[] newArray = new long[array.length + 1];
335+
System.arraycopy(array, 0, newArray, 0, array.length);
336+
newArray[array.length] = newLong;
337+
return newArray;
338+
}
339+
340+
public Long[] transformlongArrayToLong(long[] arrayToTransform) {
341+
Long[] longArgument = new Long[arrayToTransform.length];
342+
int i = 0;
343+
344+
for (long temp : arrayToTransform) {
345+
longArgument[i++] = temp;
346+
}
347+
return longArgument;
348+
}
349+
350+
public String removeLeadingSlash(String path) {
351+
if (!InputSanitizerService.stringIsValid(path))
352+
throw new IllegalArgumentException("Couldn't remove leading slash because the path was not a valid String.");
353+
354+
if (path.startsWith("/")) {
355+
path = path.substring(1);
356+
}
357+
return path;
358+
}
359+
360+
public long[] transformLongCollectionTolongArray(Collection<Long> collectionToTransform) {
361+
return Arrays.stream(collectionToTransform.toArray(new Long[0])).mapToLong(Long::longValue).toArray();
362+
}
363+
297364
public long getFileSystemEntityCount() {
298365
return fileSystemRepository.count();
299366
}

0 commit comments

Comments
 (0)