forked from Qortal/qortal
Include "mimeType" in metadata for single file resources (but only when a metadata file would have otherwise been created).
This commit is contained in:
parent
055b66e835
commit
ea6225ab9a
@ -1,5 +1,7 @@
|
||||
package org.qortal.arbitrary;
|
||||
|
||||
import com.j256.simplemagic.ContentInfo;
|
||||
import com.j256.simplemagic.ContentInfoUtil;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@ -23,6 +25,8 @@ import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.FileNameMap;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.*;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
@ -48,6 +52,7 @@ public class ArbitraryDataWriter {
|
||||
private final List<String> tags;
|
||||
private final Category category;
|
||||
private List<String> files;
|
||||
private String mimeType;
|
||||
|
||||
private int chunkSize = ArbitraryDataFile.CHUNK_SIZE;
|
||||
|
||||
@ -79,6 +84,7 @@ public class ArbitraryDataWriter {
|
||||
this.tags = ArbitraryDataTransactionMetadata.limitTags(tags);
|
||||
this.category = category;
|
||||
this.files = new ArrayList<>(); // Populated in buildFileList()
|
||||
this.mimeType = null; // Populated in buildFileList()
|
||||
}
|
||||
|
||||
public void save() throws IOException, DataException, InterruptedException, MissingDataException {
|
||||
@ -144,20 +150,41 @@ public class ArbitraryDataWriter {
|
||||
}
|
||||
|
||||
private void buildFileList() throws IOException {
|
||||
// Single file resources consist of a single element in the file list
|
||||
// Check if the path already points to a single file
|
||||
boolean isSingleFile = this.filePath.toFile().isFile();
|
||||
Path singleFilePath = null;
|
||||
if (isSingleFile) {
|
||||
this.files.add(this.filePath.getFileName().toString());
|
||||
return;
|
||||
singleFilePath = this.filePath;
|
||||
}
|
||||
|
||||
// Multi file resources require a walk through the directory tree
|
||||
else {
|
||||
// Multi file resources (or a single file in a directory) require a walk through the directory tree
|
||||
try (Stream<Path> stream = Files.walk(this.filePath)) {
|
||||
this.files = stream
|
||||
.filter(Files::isRegularFile)
|
||||
.map(p -> this.filePath.relativize(p).toString())
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (this.files.size() == 1) {
|
||||
singleFilePath = Paths.get(this.filePath.toString(), this.files.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (singleFilePath != null) {
|
||||
// Single file resource, so try and determine the MIME type
|
||||
ContentInfoUtil util = new ContentInfoUtil();
|
||||
ContentInfo info = util.findMatch(singleFilePath.toFile());
|
||||
if (info != null) {
|
||||
// Attempt to extract MIME type from file contents
|
||||
this.mimeType = info.getMimeType();
|
||||
}
|
||||
else {
|
||||
// Fall back to using the filename
|
||||
FileNameMap fileNameMap = URLConnection.getFileNameMap();
|
||||
this.mimeType = fileNameMap.getContentTypeFor(singleFilePath.toFile().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,6 +331,7 @@ public class ArbitraryDataWriter {
|
||||
metadata.setCategory(this.category);
|
||||
metadata.setChunks(this.arbitraryDataFile.chunkHashList());
|
||||
metadata.setFiles(this.files);
|
||||
metadata.setMimeType(this.mimeType);
|
||||
metadata.write();
|
||||
|
||||
// Create an ArbitraryDataFile from the JSON file (we don't have a signature yet)
|
||||
|
@ -20,6 +20,7 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
||||
private List<String> tags;
|
||||
private Category category;
|
||||
private List<String> files;
|
||||
private String mimeType;
|
||||
|
||||
private static int MAX_TITLE_LENGTH = 80;
|
||||
private static int MAX_DESCRIPTION_LENGTH = 500;
|
||||
@ -92,6 +93,10 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
||||
}
|
||||
this.files = filesList;
|
||||
}
|
||||
|
||||
if (metadata.has("mimeType")) {
|
||||
this.mimeType = metadata.getString("mimeType");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,6 +139,10 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
||||
}
|
||||
outer.put("files", files);
|
||||
|
||||
if (this.mimeType != null && !this.mimeType.isEmpty()) {
|
||||
outer.put("mimeType", this.mimeType);
|
||||
}
|
||||
|
||||
this.jsonString = outer.toString(2);
|
||||
LOGGER.trace("Transaction metadata: {}", this.jsonString);
|
||||
}
|
||||
@ -187,6 +196,14 @@ public class ArbitraryDataTransactionMetadata extends ArbitraryDataMetadata {
|
||||
return this.files;
|
||||
}
|
||||
|
||||
public void setMimeType(String mimeType) {
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return this.mimeType;
|
||||
}
|
||||
|
||||
public boolean containsChunk(byte[] chunk) {
|
||||
for (byte[] c : this.chunks) {
|
||||
if (Arrays.equals(c, chunk)) {
|
||||
|
@ -16,16 +16,18 @@ public class ArbitraryResourceMetadata {
|
||||
private Category category;
|
||||
private String categoryName;
|
||||
private List<String> files;
|
||||
private String mimeType;
|
||||
|
||||
public ArbitraryResourceMetadata() {
|
||||
}
|
||||
|
||||
public ArbitraryResourceMetadata(String title, String description, List<String> tags, Category category, List<String> files) {
|
||||
public ArbitraryResourceMetadata(String title, String description, List<String> tags, Category category, List<String> files, String mimeType) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.tags = tags;
|
||||
this.category = category;
|
||||
this.files = files;
|
||||
this.mimeType = mimeType;
|
||||
|
||||
if (category != null) {
|
||||
this.categoryName = category.getName();
|
||||
@ -40,6 +42,7 @@ public class ArbitraryResourceMetadata {
|
||||
String description = transactionMetadata.getDescription();
|
||||
List<String> tags = transactionMetadata.getTags();
|
||||
Category category = transactionMetadata.getCategory();
|
||||
String mimeType = transactionMetadata.getMimeType();
|
||||
|
||||
// We don't always want to include the file list as it can be too verbose
|
||||
List<String> files = null;
|
||||
@ -47,11 +50,11 @@ public class ArbitraryResourceMetadata {
|
||||
files = transactionMetadata.getFiles();
|
||||
}
|
||||
|
||||
if (title == null && description == null && tags == null && category == null && files == null) {
|
||||
if (title == null && description == null && tags == null && category == null && files == null && mimeType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ArbitraryResourceMetadata(title, description, tags, category, files);
|
||||
return new ArbitraryResourceMetadata(title, description, tags, category, files, mimeType);
|
||||
}
|
||||
|
||||
public List<String> getFiles() {
|
||||
|
@ -118,6 +118,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
||||
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
||||
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
||||
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
||||
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
|
||||
|
||||
// Now build the latest data state for this name
|
||||
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
|
||||
@ -168,6 +169,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
||||
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
||||
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
||||
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
||||
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
|
||||
|
||||
// Delete the file, to simulate that it hasn't been fetched from the network yet
|
||||
arbitraryDataFile.delete();
|
||||
@ -230,6 +232,7 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
||||
assertEquals(description, arbitraryDataFile.getMetadata().getDescription());
|
||||
assertEquals(tags, arbitraryDataFile.getMetadata().getTags());
|
||||
assertEquals(category, arbitraryDataFile.getMetadata().getCategory());
|
||||
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
|
||||
|
||||
// Now build the latest data state for this name
|
||||
ArbitraryDataReader arbitraryDataReader = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier);
|
||||
@ -318,9 +321,11 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
||||
assertTrue(resourceMetadata.getFiles().contains("file.txt"));
|
||||
|
||||
// Ensure it's not returned when specified to be excluded
|
||||
// The entire object will be null because there is no metadata
|
||||
ArbitraryResourceMetadata resourceMetadataSimple = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), false);
|
||||
assertNull(resourceMetadataSimple);
|
||||
assertNull(resourceMetadataSimple.getFiles());
|
||||
|
||||
// Single-file resources should have a MIME type
|
||||
assertEquals("text/plain", arbitraryDataFile.getMetadata().getMimeType());
|
||||
}
|
||||
}
|
||||
|
||||
@ -369,6 +374,9 @@ public class ArbitraryTransactionMetadataTests extends Common {
|
||||
// The entire object will be null because there is no metadata
|
||||
ArbitraryResourceMetadata resourceMetadataSimple = ArbitraryResourceMetadata.fromTransactionMetadata(arbitraryDataFile.getMetadata(), false);
|
||||
assertNull(resourceMetadataSimple);
|
||||
|
||||
// Multi-file resources won't have a MIME type
|
||||
assertEquals(null, arbitraryDataFile.getMetadata().getMimeType());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user