diff --git a/src/main/java/org/qortal/api/resource/ArbitraryResource.java b/src/main/java/org/qortal/api/resource/ArbitraryResource.java index c17cecc0..bf40feb8 100644 --- a/src/main/java/org/qortal/api/resource/ArbitraryResource.java +++ b/src/main/java/org/qortal/api/resource/ArbitraryResource.java @@ -41,10 +41,7 @@ import org.qortal.controller.Controller; import org.qortal.controller.arbitrary.ArbitraryDataStorageManager; import org.qortal.controller.arbitrary.ArbitraryMetadataManager; import org.qortal.data.account.AccountData; -import org.qortal.data.arbitrary.ArbitraryCategoryInfo; -import org.qortal.data.arbitrary.ArbitraryResourceInfo; -import org.qortal.data.arbitrary.ArbitraryResourceNameInfo; -import org.qortal.data.arbitrary.ArbitraryResourceStatus; +import org.qortal.data.arbitrary.*; import org.qortal.data.naming.NameData; import org.qortal.data.transaction.ArbitraryTransactionData; import org.qortal.data.transaction.TransactionData; @@ -93,7 +90,8 @@ public class ArbitraryResource { @Parameter(ref = "limit") @QueryParam("limit") Integer limit, @Parameter(ref = "offset") @QueryParam("offset") Integer offset, @Parameter(ref = "reverse") @QueryParam("reverse") Boolean reverse, - @Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus) { + @Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus, + @Parameter(description = "Include metadata") @QueryParam("includemetadata") Boolean includeMetadata) { try (final Repository repository = RepositoryManager.getRepository()) { @@ -115,9 +113,12 @@ public class ArbitraryResource { return new ArrayList<>(); } - if (includeStatus != null && includeStatus == true) { + if (includeStatus != null && includeStatus) { resources = this.addStatusToResources(resources); } + if (includeMetadata != null && includeMetadata) { + resources = this.addMetadataToResources(resources); + } return resources; @@ -145,7 +146,8 @@ public class ArbitraryResource { @Parameter(ref = "limit") @QueryParam("limit") Integer limit, @Parameter(ref = "offset") @QueryParam("offset") Integer offset, @Parameter(ref = "reverse") @QueryParam("reverse") Boolean reverse, - @Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus) { + @Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus, + @Parameter(description = "Include metadata") @QueryParam("includemetadata") Boolean includeMetadata) { try (final Repository repository = RepositoryManager.getRepository()) { @@ -158,9 +160,12 @@ public class ArbitraryResource { return new ArrayList<>(); } - if (includeStatus != null && includeStatus == true) { + if (includeStatus != null && includeStatus) { resources = this.addStatusToResources(resources); } + if (includeMetadata != null && includeMetadata) { + resources = this.addMetadataToResources(resources); + } return resources; @@ -187,7 +192,8 @@ public class ArbitraryResource { @Parameter(ref = "limit") @QueryParam("limit") Integer limit, @Parameter(ref = "offset") @QueryParam("offset") Integer offset, @Parameter(ref = "reverse") @QueryParam("reverse") Boolean reverse, - @Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus) { + @Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus, + @Parameter(description = "Include metadata") @QueryParam("includemetadata") Boolean includeMetadata) { try (final Repository repository = RepositoryManager.getRepository()) { @@ -211,9 +217,13 @@ public class ArbitraryResource { List resources = repository.getArbitraryRepository() .getArbitraryResources(service, identifier, name, defaultRes, null, null, reverse); - if (includeStatus != null && includeStatus == true) { + if (includeStatus != null && includeStatus) { resources = this.addStatusToResources(resources); } + if (includeMetadata != null && includeMetadata) { + resources = this.addMetadataToResources(resources); + } + creatorName.resources = resources; } } @@ -458,6 +468,7 @@ public class ArbitraryResource { public List getHostedResources( @HeaderParam(Security.API_KEY_HEADER) String apiKey, @Parameter(description = "Include status") @QueryParam("includestatus") Boolean includeStatus, + @Parameter(description = "Include metadata") @QueryParam("includemetadata") Boolean includeMetadata, @Parameter(ref = "limit") @QueryParam("limit") Integer limit, @Parameter(ref = "offset") @QueryParam("offset") Integer offset, @QueryParam("query") String query) { @@ -485,9 +496,12 @@ public class ArbitraryResource { } } - if (includeStatus != null && includeStatus == true) { + if (includeStatus != null && includeStatus) { resources = this.addStatusToResources(resources); } + if (includeMetadata != null && includeMetadata) { + resources = this.addMetadataToResources(resources); + } return resources; @@ -1255,4 +1269,20 @@ public class ArbitraryResource { } return updatedResources; } + + private List addMetadataToResources(List resources) { + // Add metadata fields to each resource if they exist + List updatedResources = new ArrayList<>(); + for (ArbitraryResourceInfo resourceInfo : resources) { + ArbitraryDataResource resource = new ArbitraryDataResource(resourceInfo.name, ResourceIdType.NAME, + resourceInfo.service, resourceInfo.identifier); + ArbitraryDataTransactionMetadata transactionMetadata = resource.getLatestTransactionMetadata(); + ArbitraryResourceMetadata resourceMetadata = ArbitraryResourceMetadata.fromTransactionMetadata(transactionMetadata); + if (resourceMetadata != null) { + resourceInfo.metadata = ArbitraryResourceMetadata.fromTransactionMetadata(transactionMetadata); + } + updatedResources.add(resourceInfo); + } + return updatedResources; + } } diff --git a/src/main/java/org/qortal/arbitrary/ArbitraryDataResource.java b/src/main/java/org/qortal/arbitrary/ArbitraryDataResource.java index 36bd8f4c..616c9b03 100644 --- a/src/main/java/org/qortal/arbitrary/ArbitraryDataResource.java +++ b/src/main/java/org/qortal/arbitrary/ArbitraryDataResource.java @@ -3,6 +3,7 @@ package org.qortal.arbitrary; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.qortal.arbitrary.ArbitraryDataFile.ResourceIdType; +import org.qortal.arbitrary.metadata.ArbitraryDataTransactionMetadata; import org.qortal.arbitrary.misc.Service; import org.qortal.controller.arbitrary.ArbitraryDataBuildManager; import org.qortal.controller.arbitrary.ArbitraryDataManager; @@ -37,6 +38,7 @@ public class ArbitraryDataResource { private List transactions; private ArbitraryTransactionData latestPutTransaction; + private ArbitraryTransactionData latestTransaction; private int layerCount; private Integer localChunkCount = null; private Integer totalChunkCount = null; @@ -105,6 +107,33 @@ public class ArbitraryDataResource { return new ArbitraryResourceStatus(Status.DOWNLOADED, this.localChunkCount, this.totalChunkCount); } + public ArbitraryDataTransactionMetadata getLatestTransactionMetadata() { + this.fetchLatestTransaction(); + + if (latestTransaction != null) { + byte[] signature = latestTransaction.getSignature(); + byte[] metadataHash = latestTransaction.getMetadataHash(); + if (metadataHash == null) { + // This resource doesn't have metadata + return null; + } + + try { + ArbitraryDataFile metadataFile = ArbitraryDataFile.fromHash(metadataHash, signature); + if (metadataFile.exists()) { + ArbitraryDataTransactionMetadata transactionMetadata = new ArbitraryDataTransactionMetadata(metadataFile.getFilePath()); + transactionMetadata.read(); + return transactionMetadata; + } + + } catch (DataException | IOException e) { + // Do nothing + } + } + + return null; + } + public boolean delete() { try { this.fetchTransactions(); @@ -306,6 +335,32 @@ public class ArbitraryDataResource { this.transactions = transactionDataList; this.layerCount = transactionDataList.size(); + + } catch (DataException e) { + LOGGER.info(String.format("Repository error when fetching transactions for resource %s: %s", this, e.getMessage())); + } + } + + private void fetchLatestTransaction() { + if (this.latestTransaction != null) { + // Already fetched + return; + } + + try (final Repository repository = RepositoryManager.getRepository()) { + + // Get the most recent transaction + ArbitraryTransactionData latestTransaction = repository.getArbitraryRepository() + .getLatestTransaction(this.resourceId, this.service, null, this.identifier); + if (latestTransaction == null) { + String message = String.format("Couldn't find transaction for name %s, service %s and identifier %s", + this.resourceId, this.service, this.identifierString()); + throw new DataException(message); + } + this.latestTransaction = latestTransaction; + + } catch (DataException e) { + LOGGER.info(String.format("Repository error when fetching latest transaction for resource %s: %s", this, e.getMessage())); } } diff --git a/src/main/java/org/qortal/data/arbitrary/ArbitraryResourceInfo.java b/src/main/java/org/qortal/data/arbitrary/ArbitraryResourceInfo.java index d3605d65..135065aa 100644 --- a/src/main/java/org/qortal/data/arbitrary/ArbitraryResourceInfo.java +++ b/src/main/java/org/qortal/data/arbitrary/ArbitraryResourceInfo.java @@ -13,6 +13,7 @@ public class ArbitraryResourceInfo { public Service service; public String identifier; public ArbitraryResourceStatus status; + public ArbitraryResourceMetadata metadata; public Long size; diff --git a/src/main/java/org/qortal/data/arbitrary/ArbitraryResourceMetadata.java b/src/main/java/org/qortal/data/arbitrary/ArbitraryResourceMetadata.java new file mode 100644 index 00000000..652ddabf --- /dev/null +++ b/src/main/java/org/qortal/data/arbitrary/ArbitraryResourceMetadata.java @@ -0,0 +1,43 @@ +package org.qortal.data.arbitrary; + +import org.qortal.arbitrary.metadata.ArbitraryDataTransactionMetadata; +import org.qortal.arbitrary.misc.Category; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import java.util.List; + +@XmlAccessorType(XmlAccessType.FIELD) +public class ArbitraryResourceMetadata { + + private String title; + private String description; + private List tags; + private Category category; + + public ArbitraryResourceMetadata() { + } + + public ArbitraryResourceMetadata(String title, String description, List tags, Category category) { + this.title = title; + this.description = description; + this.tags = tags; + this.category = category; + } + + public static ArbitraryResourceMetadata fromTransactionMetadata(ArbitraryDataTransactionMetadata transactionMetadata) { + if (transactionMetadata == null) { + return null; + } + String title = transactionMetadata.getTitle(); + String description = transactionMetadata.getDescription(); + List tags = transactionMetadata.getTags(); + Category category = transactionMetadata.getCategory(); + + if (title == null && description == null && tags == null && category == null) { + return null; + } + + return new ArbitraryResourceMetadata(title, description, tags, category); + } +}