Compare commits
2 Commits
c7ee90cbaa
...
a60df48774
| Author | SHA1 | Date | |
|---|---|---|---|
| a60df48774 | |||
| 23db8681d3 |
@@ -10,16 +10,28 @@ import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.advent.configuration.AdventConfiguration;
|
||||
import sh.rhiobet.lalafin.core.access.AccessService;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
|
||||
|
||||
@ApplicationScoped
|
||||
@Named("advent")
|
||||
@Named("advent/access")
|
||||
public class AdventAccessService implements AccessService {
|
||||
@Inject
|
||||
AdventConfiguration adventConfiguration;
|
||||
|
||||
@Inject
|
||||
@Named("file/resolver")
|
||||
PathURIResolver fileURIResolver;
|
||||
|
||||
@Override
|
||||
public boolean checkAccess(Path path) {
|
||||
String pathUri = path.getURI();
|
||||
Optional<String> pathUriOptional = this.fileURIResolver.resolve(path);
|
||||
|
||||
String pathUri;
|
||||
if (pathUriOptional.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
pathUri = pathUriOptional.get().replaceAll("^.file", "");
|
||||
}
|
||||
|
||||
Optional<AdventConfiguration.AdventEvent> matchingAdvent = adventConfiguration.events().stream()
|
||||
.filter(e -> pathUri.startsWith(e.path()))
|
||||
|
||||
@@ -1,43 +1,44 @@
|
||||
package sh.rhiobet.lalafin.advent.thumbnail;
|
||||
package sh.rhiobet.lalafin.advent.resolver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.annotation.Priority;
|
||||
import jakarta.decorator.Decorator;
|
||||
import jakarta.decorator.Delegate;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.advent.access.AdventAccessService;
|
||||
import sh.rhiobet.lalafin.api.configuration.FileApiConfiguration;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.model.PathAccessor;
|
||||
import sh.rhiobet.lalafin.core.path.plugin.PathPlugin;
|
||||
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
|
||||
@Decorator
|
||||
public class AdventThumbnailPathPlugin extends PathAccessor implements PathPlugin {
|
||||
@Priority(0)
|
||||
public class AdventThumbnailPathURIResolver extends PathAccessor implements PathURIResolver {
|
||||
@Inject
|
||||
FileApiConfiguration fileApiConfiguration;
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Inject
|
||||
@Named("file/thumbnail")
|
||||
@Named("file/resolver/thumbnail")
|
||||
@Delegate
|
||||
PathPlugin thumbnailPathPlugin;
|
||||
PathURIResolver thumbnailURIResolver;
|
||||
|
||||
@Inject
|
||||
AdventAccessService adventAccessService;
|
||||
|
||||
@Override
|
||||
public Optional<String> resolveURI(Path path) {
|
||||
public Optional<String> resolve(Path path) {
|
||||
if (this.adventAccessService.checkAccess(path)) {
|
||||
return this.thumbnailPathPlugin.resolveURI(path);
|
||||
return this.thumbnailURIResolver.resolve(path);
|
||||
} else {
|
||||
Optional<java.nio.file.Path> thumbnailAbsolutePath = getDefaultThumbnailPath(path);
|
||||
|
||||
if (thumbnailAbsolutePath.isPresent()) {
|
||||
java.nio.file.Path rootFolderPath = Paths.get(this.fileApiConfiguration.directory());
|
||||
java.nio.file.Path rootFolderPath = Paths.get(this.fileConfiguration.directory());
|
||||
return Optional.of(
|
||||
"/" + rootFolderPath.resolve("file").relativize(thumbnailAbsolutePath.get())
|
||||
.toString());
|
||||
@@ -47,15 +48,6 @@ public class AdventThumbnailPathPlugin extends PathAccessor implements PathPlugi
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream(Path path) throws IOException {
|
||||
if (this.adventAccessService.checkAccess(path)) {
|
||||
return this.thumbnailPathPlugin.getOutputStream(path);
|
||||
} else {
|
||||
throw new IOException("You don't yet have access to this resource.");
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<java.nio.file.Path> getDefaultThumbnailPath(Path path) {
|
||||
try {
|
||||
return Files.list(getAbsolutePath(path).getParent().resolve(".thumbnails"))
|
||||
@@ -9,8 +9,6 @@ import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.jboss.resteasy.reactive.common.util.Encode;
|
||||
|
||||
public final class FileSystemPath implements Path {
|
||||
private java.nio.file.Path rootFolderPath;
|
||||
|
||||
@@ -29,16 +27,6 @@ public final class FileSystemPath implements Path {
|
||||
this.absolutePath = getAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURI() {
|
||||
if (this.segments.isEmpty()) {
|
||||
return "/";
|
||||
}
|
||||
return this.segments.stream()
|
||||
.map(s -> "/" + Encode.encodePathSegment(s))
|
||||
.reduce("", String::concat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return this.segments.isEmpty() ? "/" : this.segments.getLast();
|
||||
|
||||
@@ -5,7 +5,6 @@ import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
sealed public interface Path permits FileSystemPath, ZipEntryPath {
|
||||
String getURI();
|
||||
String getFilename();
|
||||
long getSize();
|
||||
boolean exists();
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package sh.rhiobet.lalafin.core.path.model;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class PathAccessor {
|
||||
protected java.nio.file.Path getAbsolutePath(Path path) {
|
||||
switch (path) {
|
||||
@@ -10,4 +15,15 @@ public abstract class PathAccessor {
|
||||
return zep.zipFilePath.absolutePath;
|
||||
}
|
||||
}
|
||||
|
||||
protected List<String> getSegments(Path path) {
|
||||
switch (path) {
|
||||
case FileSystemPath fsp:
|
||||
return Collections.unmodifiableList(fsp.segments);
|
||||
|
||||
case ZipEntryPath zep:
|
||||
return Stream.concat(zep.zipFilePath.segments.stream(), zep.segments.stream())
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,21 @@
|
||||
package sh.rhiobet.lalafin.core.path.model;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.ws.rs.core.PathSegment;
|
||||
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
|
||||
import sh.rhiobet.lalafin.api.configuration.FileApiConfiguration;
|
||||
import sh.rhiobet.lalafin.core.path.exception.InvalidPathException;
|
||||
|
||||
@ApplicationScoped
|
||||
public class PathFactory {
|
||||
@Inject
|
||||
FileApiConfiguration fileApiConfiguration;
|
||||
|
||||
public Path toPath(List<PathSegment> names) throws InvalidPathException {
|
||||
public Path toPath(List<PathSegment> names, java.nio.file.Path rootFolderPath)
|
||||
throws InvalidPathException {
|
||||
if (hasEncodedPathSeparator(names)) {
|
||||
throw new InvalidPathException("Some path segments contain illegal characters.");
|
||||
} else {
|
||||
java.nio.file.Path rootFolderPath = Paths.get(this.fileApiConfiguration.directory());
|
||||
|
||||
int zipIndex = -1;
|
||||
for (int i = 0; i < names.size(); i++) {
|
||||
if (names.get(i).getPath().endsWith(".zip")) {
|
||||
|
||||
@@ -10,8 +10,6 @@ import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.jboss.resteasy.reactive.common.util.Encode;
|
||||
|
||||
public final class ZipEntryPath implements Path {
|
||||
private long size = 0;
|
||||
private boolean exists = false;
|
||||
@@ -32,13 +30,6 @@ public final class ZipEntryPath implements Path {
|
||||
this.entryName = entryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getURI() {
|
||||
return this.zipFilePath.getURI() + this.segments.stream()
|
||||
.map(s -> "/" + Encode.encodePathSegment(s))
|
||||
.reduce("", String::concat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return this.segments.getLast();
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package sh.rhiobet.lalafin.core.path.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Optional;
|
||||
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
|
||||
public interface PathPlugin {
|
||||
Optional<String> resolveURI(Path path);
|
||||
OutputStream getOutputStream(Path path) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package sh.rhiobet.lalafin.core.path.resolver;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
|
||||
public interface PathURIResolver {
|
||||
Optional<String> resolve(Path path);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package sh.rhiobet.lalafin.core.thumbnail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
|
||||
public interface ThumbnailGenerator {
|
||||
void generate(Path path) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package sh.rhiobet.lalafin.core.thumbnail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import sh.rhiobet.lalafin.core.path.model.FileSystemPath;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.model.PathAccessor;
|
||||
import sh.rhiobet.lalafin.core.path.model.ZipEntryPath;
|
||||
|
||||
public abstract class ThumbnailPathAccessor extends PathAccessor {
|
||||
@Override
|
||||
protected java.nio.file.Path getAbsolutePath(Path path) {
|
||||
try {
|
||||
switch (path) {
|
||||
case FileSystemPath fsp:
|
||||
java.nio.file.Path thumbnailsFolder =
|
||||
super.getAbsolutePath(path).getParent().resolve(".thumbnails");
|
||||
|
||||
Optional<java.nio.file.Path> foundPath = Optional.empty();
|
||||
if (Files.exists(thumbnailsFolder)) {
|
||||
foundPath = Files.list(thumbnailsFolder)
|
||||
.filter(f -> f.getFileName().toString()
|
||||
.matches("^" + Pattern.quote(path.getFilename()) + "(\\.[^.]+)*$"))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
return foundPath.isPresent() ?
|
||||
foundPath.get() :
|
||||
thumbnailsFolder.resolve(path.getFilename() + ".png");
|
||||
|
||||
case ZipEntryPath zep:
|
||||
return null;
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/main/java/sh/rhiobet/lalafin/core/util/MimeType.java
Normal file
42
src/main/java/sh/rhiobet/lalafin/core/util/MimeType.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package sh.rhiobet.lalafin.core.util;
|
||||
|
||||
public class MimeType {
|
||||
public static String getMimeType(String filename) {
|
||||
String extension = filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
|
||||
|
||||
switch (extension) {
|
||||
case "3gp":
|
||||
return "video/3gpp";
|
||||
case "avi":
|
||||
return "video/x-msvideo";
|
||||
case "flac":
|
||||
return "audio/x-flac";
|
||||
case "flv":
|
||||
return "video/x-flv";
|
||||
case "html":
|
||||
return "text/html";
|
||||
case "jpg":
|
||||
return "image/jpeg";
|
||||
case "mkv":
|
||||
return "video/x-matroska";
|
||||
case "mp3":
|
||||
return "audio/mp3";
|
||||
case "mp4":
|
||||
return "video/mp4";
|
||||
case "png":
|
||||
return "image/png";
|
||||
case "ts":
|
||||
return "video/MP2T";
|
||||
case "wav":
|
||||
return "audio/x-wav";
|
||||
case "webm":
|
||||
return "video/webm";
|
||||
case "wmv":
|
||||
return "video/x-ms-wmv";
|
||||
case "zip":
|
||||
return "application/zip";
|
||||
default:
|
||||
return "application/octet-stream";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package sh.rhiobet.lalafin.file.access;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.quarkus.security.identity.SecurityIdentity;
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
@@ -8,10 +9,11 @@ import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.core.access.AccessService;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
|
||||
@ApplicationScoped
|
||||
@Named("file/role")
|
||||
@Named("file/access/role")
|
||||
public class FileRoleAccessService implements AccessService {
|
||||
@Inject
|
||||
SecurityIdentity securityIdentity;
|
||||
@@ -19,13 +21,24 @@ public class FileRoleAccessService implements AccessService {
|
||||
@Inject
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Inject
|
||||
@Named("file/resolver")
|
||||
PathURIResolver fileURIResolver;
|
||||
|
||||
public boolean checkAccess(Path path) {
|
||||
String pathUri = path.getURI();
|
||||
Optional<String> pathUriOptional = this.fileURIResolver.resolve(path);
|
||||
|
||||
String pathUri;
|
||||
if (pathUriOptional.isEmpty()) {
|
||||
return false;
|
||||
} else {
|
||||
pathUri = pathUriOptional.get().replaceAll("^.file", "");
|
||||
}
|
||||
|
||||
List<FileConfiguration.Route> matchingRoutes = fileConfiguration.routes().stream()
|
||||
.filter(r -> pathUri.startsWith(r.path()))
|
||||
.toList();
|
||||
|
||||
|
||||
if (matchingRoutes.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.LalafinConfiguration;
|
||||
import sh.rhiobet.lalafin.api.internal.redis.FileTokenProvider;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.plugin.PathPlugin;
|
||||
import sh.rhiobet.lalafin.file.ThumbnailService;
|
||||
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
|
||||
import sh.rhiobet.lalafin.core.thumbnail.ThumbnailGenerator;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
|
||||
@ApplicationScoped
|
||||
@@ -21,21 +21,36 @@ public class FileMetadataService {
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Inject
|
||||
ThumbnailService thumbnailService;
|
||||
@Named("file/resolver")
|
||||
PathURIResolver fileURIResolver;
|
||||
|
||||
@Inject
|
||||
@Named("file/resolver/thumbnail")
|
||||
PathURIResolver fileThumbnailURIResolver;
|
||||
|
||||
@Inject
|
||||
@Named("file/thumbnail")
|
||||
PathPlugin thumbnailPathPlugin;
|
||||
ThumbnailGenerator fileThumbnailGenerator;
|
||||
|
||||
public FileInfoBase getInfo(Path filePath, FileTokenProvider fileTokenProvider) {
|
||||
if (filePath.exists()) {
|
||||
Optional<String> thumbUrl = this.thumbnailPathPlugin.resolveURI(filePath);
|
||||
Optional<String> fileUrl = this.fileURIResolver.resolve(filePath);
|
||||
Optional<String> thumbUrl = this.fileThumbnailURIResolver.resolve(filePath);
|
||||
|
||||
if (thumbUrl.isEmpty()) {
|
||||
try {
|
||||
this.fileThumbnailGenerator.generate(filePath);
|
||||
thumbUrl = this.fileThumbnailURIResolver.resolve(filePath);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (filePath.canHaveChildren()) {
|
||||
FolderInfo folderInfo = new FolderInfo(
|
||||
filePath.getFilename(),
|
||||
thumbUrl.isPresent() ? "/file" + thumbUrl.get() : "",
|
||||
"/file" + filePath.getURI(),
|
||||
thumbUrl.isPresent() ? thumbUrl.get() : "",
|
||||
fileUrl.isPresent() ? fileUrl.get() : "",
|
||||
""
|
||||
);
|
||||
|
||||
@@ -52,17 +67,29 @@ public class FileMetadataService {
|
||||
}
|
||||
}
|
||||
|
||||
Optional<String> childThumbUrl = this.thumbnailPathPlugin.resolveURI(child);
|
||||
Optional<String> childFileUrl = this.fileURIResolver.resolve(child);
|
||||
Optional<String> childThumbUrl = this.fileThumbnailURIResolver.resolve(child);
|
||||
|
||||
if (childThumbUrl.isEmpty()) {
|
||||
try {
|
||||
this.fileThumbnailGenerator.generate(child);
|
||||
childThumbUrl = this.fileThumbnailURIResolver.resolve(child);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
FileInfoBase contentInfo;
|
||||
if (child.canHaveChildren()) {
|
||||
contentInfo = new FolderInfo(child.getFilename(), "/file" + child.getURI());
|
||||
contentInfo = new FolderInfo(child.getFilename(),
|
||||
childFileUrl.isPresent() ? childFileUrl.get() : "");
|
||||
} else {
|
||||
contentInfo = new FileInfo(child.getFilename(), "/file" + child.getURI());
|
||||
contentInfo = new FileInfo(child.getFilename(),
|
||||
childFileUrl.isPresent() ? childFileUrl.get() : "");
|
||||
}
|
||||
|
||||
if (childThumbUrl.isPresent()) {
|
||||
contentInfo.thumbnailUrl = "/file" + childThumbUrl.get();
|
||||
contentInfo.thumbnailUrl = childThumbUrl.get();
|
||||
}
|
||||
|
||||
folderInfo.content.add(contentInfo);
|
||||
@@ -75,8 +102,8 @@ public class FileMetadataService {
|
||||
} else {
|
||||
FileInfo fileInfo = new FileInfo(
|
||||
filePath.getFilename(),
|
||||
thumbUrl.isPresent() ? "/file" + thumbUrl.get() : "",
|
||||
"/file" + filePath.getURI(),
|
||||
thumbUrl.isPresent() ? thumbUrl.get() : "",
|
||||
fileUrl.isPresent() ? fileUrl.get() : "",
|
||||
""
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package sh.rhiobet.lalafin.file.resolver;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jboss.resteasy.reactive.common.util.Encode;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.model.PathAccessor;
|
||||
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
|
||||
|
||||
@ApplicationScoped
|
||||
@Named("file/resolver")
|
||||
public class FilePathURIResolver extends PathAccessor implements PathURIResolver {
|
||||
@Inject
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Override
|
||||
public Optional<String> resolve(Path path) {
|
||||
List<String> segments = getSegments(path);
|
||||
|
||||
if (segments.isEmpty()) {
|
||||
return Optional.of("/file/");
|
||||
}
|
||||
|
||||
return Optional.of(segments.stream()
|
||||
.map(s -> "/" + Encode.encodePathSegment(s))
|
||||
.reduce("/file", String::concat));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package sh.rhiobet.lalafin.file.resolver;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
import sh.rhiobet.lalafin.core.path.model.FileSystemPath;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.model.ZipEntryPath;
|
||||
import sh.rhiobet.lalafin.core.path.resolver.PathURIResolver;
|
||||
import sh.rhiobet.lalafin.core.thumbnail.ThumbnailPathAccessor;
|
||||
|
||||
@ApplicationScoped
|
||||
@Named("file/resolver/thumbnail")
|
||||
public class FileThumbnailPathURIResolver extends ThumbnailPathAccessor implements PathURIResolver {
|
||||
@Inject
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Override
|
||||
public Optional<String> resolve(Path path) {
|
||||
switch (path) {
|
||||
case FileSystemPath fsp:
|
||||
java.nio.file.Path thumbnailAbsolutePath = getAbsolutePath(path);
|
||||
|
||||
if (thumbnailAbsolutePath != null && Files.exists(thumbnailAbsolutePath)) {
|
||||
java.nio.file.Path rootFolderPath = Paths.get(this.fileConfiguration.directory());
|
||||
return Optional.of(
|
||||
"/file/" + rootFolderPath.resolve("file").relativize(thumbnailAbsolutePath)
|
||||
.toString());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
case ZipEntryPath zep:
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package sh.rhiobet.lalafin.file.rest;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -15,12 +16,16 @@ import io.quarkus.security.Authenticated;
|
||||
import sh.rhiobet.lalafin.core.access.AccessService;
|
||||
import sh.rhiobet.lalafin.core.path.exception.InvalidPathException;
|
||||
import sh.rhiobet.lalafin.core.path.model.PathFactory;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
import sh.rhiobet.lalafin.file.model.FileInfoBase;
|
||||
import sh.rhiobet.lalafin.file.model.FileMetadataService;
|
||||
|
||||
@Authenticated
|
||||
@Path("/v1/api/private/file")
|
||||
public class FilePrivateAPI {
|
||||
@Inject
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Inject
|
||||
FileMetadataService fileMetadataService;
|
||||
|
||||
@@ -41,9 +46,11 @@ public class FilePrivateAPI {
|
||||
@Path("/{names: .+}")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getFileInfo(List<PathSegment> names) {
|
||||
java.nio.file.Path rootFolderPath = Paths.get(this.fileConfiguration.directory());
|
||||
|
||||
sh.rhiobet.lalafin.core.path.model.Path path;
|
||||
try {
|
||||
path = this.pathFactory.toPath(names);
|
||||
path = this.pathFactory.toPath(names, rootFolderPath);
|
||||
} catch (InvalidPathException ignored) {
|
||||
return Response.status(Response.Status.BAD_REQUEST).build();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package sh.rhiobet.lalafin.file.thumbnail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.im4java.core.ConvertCmd;
|
||||
import org.im4java.core.IM4JavaException;
|
||||
import org.im4java.core.IMOperation;
|
||||
import org.im4java.process.Pipe;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.thumbnail.ThumbnailGenerator;
|
||||
import sh.rhiobet.lalafin.core.thumbnail.ThumbnailPathAccessor;
|
||||
import sh.rhiobet.lalafin.core.util.MimeType;
|
||||
|
||||
@ApplicationScoped
|
||||
@Named("file/thumbnail")
|
||||
public class FileThumbnailGenerator extends ThumbnailPathAccessor implements ThumbnailGenerator {
|
||||
@Inject
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Override
|
||||
public void generate(Path path) throws IOException {
|
||||
java.nio.file.Path thumbnailAbsolutePath = getAbsolutePath(path);
|
||||
|
||||
if (!path.canHaveChildren() || thumbnailAbsolutePath == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Files.exists(thumbnailAbsolutePath)) {
|
||||
Files.delete(thumbnailAbsolutePath);
|
||||
}
|
||||
|
||||
Files.createDirectories(thumbnailAbsolutePath.getParent());
|
||||
|
||||
for (Path childPath : path.getChildren()) {
|
||||
String mimetype = MimeType.getMimeType(childPath.getFilename());
|
||||
|
||||
if (mimetype.startsWith("image/")) {
|
||||
String extension = childPath.getFilename()
|
||||
.substring(childPath.getFilename().lastIndexOf('.') + 1).toLowerCase();
|
||||
|
||||
ConvertCmd convert = new ConvertCmd();
|
||||
convert.getCommand().clear();
|
||||
convert.getCommand().push("magick");
|
||||
IMOperation op = new IMOperation();
|
||||
|
||||
try (InputStream pathInputStream = childPath.getInputStream()) {
|
||||
Pipe inputPipe = new Pipe(pathInputStream, null);
|
||||
op.addImage(extension + ":-");
|
||||
op.resize(200, null);
|
||||
op.addImage(thumbnailAbsolutePath.toString());
|
||||
convert.setInputProvider(inputPipe);
|
||||
convert.run(op);
|
||||
|
||||
return;
|
||||
} catch (InterruptedException | IM4JavaException e) {
|
||||
throw new IOException("Error when generating thumbnail with IM4J.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package sh.rhiobet.lalafin.file.thumbnail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import sh.rhiobet.lalafin.file.configuration.FileConfiguration;
|
||||
import sh.rhiobet.lalafin.core.path.model.FileSystemPath;
|
||||
import sh.rhiobet.lalafin.core.path.model.Path;
|
||||
import sh.rhiobet.lalafin.core.path.model.PathAccessor;
|
||||
import sh.rhiobet.lalafin.core.path.model.ZipEntryPath;
|
||||
import sh.rhiobet.lalafin.core.path.plugin.PathPlugin;
|
||||
|
||||
@ApplicationScoped
|
||||
@Named("file/thumbnail")
|
||||
public class FileThumbnailPathPlugin extends PathAccessor implements PathPlugin {
|
||||
@Inject
|
||||
FileConfiguration fileConfiguration;
|
||||
|
||||
@Override
|
||||
public Optional<String> resolveURI(Path path) {
|
||||
switch (path) {
|
||||
case FileSystemPath fsp:
|
||||
Optional<java.nio.file.Path> thumbnailAbsolutePath = getThumbnailPath(path);
|
||||
|
||||
if (thumbnailAbsolutePath.isPresent()) {
|
||||
java.nio.file.Path rootFolderPath = Paths.get(this.fileConfiguration.directory());
|
||||
return Optional.of(
|
||||
"/" + rootFolderPath.resolve("file").relativize(thumbnailAbsolutePath.get())
|
||||
.toString());
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
case ZipEntryPath zep:
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream(Path path) throws IOException {
|
||||
switch (path) {
|
||||
case FileSystemPath fsp:
|
||||
Optional<java.nio.file.Path> thumbnailAbsolutePath = getThumbnailPath(path);
|
||||
if (thumbnailAbsolutePath.isPresent()) {
|
||||
Files.delete(thumbnailAbsolutePath.get());
|
||||
}
|
||||
java.nio.file.Path newThumbnailAbsolutePath =
|
||||
getAbsolutePath(path).getParent().resolve(".thumbnails").resolve(path.getFilename());
|
||||
Files.createDirectories(newThumbnailAbsolutePath.getParent());
|
||||
return Files.newOutputStream(newThumbnailAbsolutePath);
|
||||
|
||||
case ZipEntryPath zep:
|
||||
throw new IOException("A zip file is not a valid location to store a thumbnail.");
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<java.nio.file.Path> getThumbnailPath(Path path) {
|
||||
try {
|
||||
return Files.list(getAbsolutePath(path).getParent().resolve(".thumbnails"))
|
||||
.filter(f -> f.getFileName().toString()
|
||||
.matches("^" + Pattern.quote(path.getFilename()) + "(\\.[^.]+)*$"))
|
||||
.findFirst();
|
||||
} catch (IOException ignored) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user