Filename API renamed to GET /resource/properties/{service}/{name}/{identifier}.

Now returns filename, size, and mimeType where available.
This commit is contained in:
CalDescent 2023-03-18 16:39:23 +00:00
parent 46b225cdfb
commit 1b9afce21f
2 changed files with 40 additions and 20 deletions

View File

@ -0,0 +1,16 @@
package org.qortal.api.model;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
@XmlAccessorType(XmlAccessType.FIELD)
public class FileProperties {
public String filename;
public String mimeType;
public Long size;
public FileProperties() {
}
}

View File

@ -12,6 +12,8 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import java.io.*; import java.io.*;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
@ -26,11 +28,13 @@ import javax.ws.rs.*;
import javax.ws.rs.core.Context; import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Base64;
import org.qortal.api.*; import org.qortal.api.*;
import org.qortal.api.model.FileProperties;
import org.qortal.api.resource.TransactionsResource.ConfirmationStatus; import org.qortal.api.resource.TransactionsResource.ConfirmationStatus;
import org.qortal.arbitrary.*; import org.qortal.arbitrary.*;
import org.qortal.arbitrary.ArbitraryDataFile.ResourceIdType; import org.qortal.arbitrary.ArbitraryDataFile.ResourceIdType;
@ -279,22 +283,18 @@ public class ArbitraryResource {
} }
@GET @GET
@Path("/resource/filename/{service}/{name}/{identifier}") @Path("/resource/properties/{service}/{name}/{identifier}")
@Operation( @Operation(
summary = "Get filename in published data", summary = "Get properties of a QDN resource",
description = "This causes a download of the data if it's not local. A filename will only be returned for single file resources.", description = "This attempts a download of the data if it's not available locally. A filename will only be returned for single file resources. mimeType is only returned when it can be determined.",
responses = { responses = {
@ApiResponse( @ApiResponse(
content = @Content(mediaType = MediaType.TEXT_PLAIN, content = @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = FileProperties.class))
schema = @Schema(
type = "string"
)
)
) )
} }
) )
@SecurityRequirement(name = "apiKey") @SecurityRequirement(name = "apiKey")
public String getResourceFilename(@HeaderParam(Security.API_KEY_HEADER) String apiKey, public FileProperties getResourceProperties(@HeaderParam(Security.API_KEY_HEADER) String apiKey,
@PathParam("service") Service service, @PathParam("service") Service service,
@PathParam("name") String name, @PathParam("name") String name,
@PathParam("identifier") String identifier) { @PathParam("identifier") String identifier) {
@ -302,7 +302,7 @@ public class ArbitraryResource {
if (!Settings.getInstance().isQDNAuthBypassEnabled()) if (!Settings.getInstance().isQDNAuthBypassEnabled())
Security.requirePriorAuthorizationOrApiKey(request, name, service, identifier, apiKey); Security.requirePriorAuthorizationOrApiKey(request, name, service, identifier, apiKey);
return this.getFilename(service, name, identifier); return this.getFileProperties(service, name, identifier);
} }
@GET @GET
@ -1378,8 +1378,7 @@ public class ArbitraryResource {
} }
} }
private String getFilename(Service service, String name, String identifier) { private FileProperties getFileProperties(Service service, String name, String identifier) {
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier); ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, identifier);
try { try {
arbitraryDataReader.loadSynchronously(false); arbitraryDataReader.loadSynchronously(false);
@ -1389,15 +1388,20 @@ public class ArbitraryResource {
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.FILE_NOT_FOUND, "File not found"); throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.FILE_NOT_FOUND, "File not found");
} }
FileProperties fileProperties = new FileProperties();
fileProperties.size = FileUtils.sizeOfDirectory(outputPath.toFile());
String[] files = ArrayUtils.removeElement(outputPath.toFile().list(), ".qortal"); String[] files = ArrayUtils.removeElement(outputPath.toFile().list(), ".qortal");
if (files.length == 1) { if (files.length == 1) {
LOGGER.info("File: {}", files[0]); String filename = files[0];
return files[0]; FileNameMap fileNameMap = URLConnection.getFileNameMap();
} String mimeType = fileNameMap.getContentTypeFor(filename);
else { fileProperties.filename = filename;
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Filename not available for multi file resources"); fileProperties.mimeType = mimeType;
} }
return fileProperties;
} catch (Exception e) { } catch (Exception e) {
LOGGER.debug(String.format("Unable to load %s %s: %s", service, name, e.getMessage())); LOGGER.debug(String.format("Unable to load %s %s: %s", service, name, e.getMessage()));
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.FILE_NOT_FOUND, e.getMessage()); throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.FILE_NOT_FOUND, e.getMessage());