diff --git a/dotCMS/src/curl-test/GraphQLTests.json b/dotCMS/src/curl-test/GraphQLTests.json index e329230bd8bc..0ca228aace3f 100644 --- a/dotCMS/src/curl-test/GraphQLTests.json +++ b/dotCMS/src/curl-test/GraphQLTests.json @@ -1,10 +1,9 @@ { "info": { - "_postman_id": "ec9b06ea-0e55-44b2-8364-6c503499f792", + "_postman_id": "611b379f-e7c5-4732-8b92-2d34993515d4", "name": "GraphQL", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "5403727", - "_collection_link": "https://cloudy-robot-285072.postman.co/workspace/JCastro-Workspace~5bfa586e-54db-429b-b7d5-c4ff997e3a0d/collection/5403727-ec9b06ea-0e55-44b2-8364-6c503499f792?action=share&source=collection_link&creator=5403727" + "_exporter_id": "5403727" }, "item": [ { @@ -4562,7 +4561,7 @@ " pm.expect(imageFieldJson.fileAsset.mime).to.eql(\"image/jpeg\");", " ", " // metaData", - " pm.expect(imageFieldJson.metaData.length).to.eql(12);", + " pm.expect(imageFieldJson.metaData.length).to.eql(13, \"Returned Metadata attributes is \" + imageFieldJson.metaData.length);", " pm.expect(hasProperty(imageFieldJson.metaData, \"fileSize\", \"5494\"), 'FAILED:[fileSize]').to.be.true;", " pm.expect(hasProperty(imageFieldJson.metaData, \"length\", \"5494\"), 'FAILED:[length]').to.be.true;", " pm.expect(hasProperty(imageFieldJson.metaData, \"width\", \"139\"), 'FAILED:[width]').to.be.true;", @@ -10034,83 +10033,5 @@ ] } } - ], - "variable": [ - { - "key": "languageId", - "value": "" - }, - { - "key": "contentTypeVariable", - "value": "" - }, - { - "key": "contentIdentifier", - "value": "" - }, - { - "key": "imageTypeInfo", - "value": "" - }, - { - "key": "videoTypeInfo", - "value": "" - }, - { - "key": "fileImageContentTypeVariable", - "value": "" - }, - { - "key": "imageFieldVariable", - "value": "" - }, - { - "key": "fileFieldVariable", - "value": "" - }, - { - "key": "fileContentIdentifier", - "value": "" - }, - { - "key": "imageContentIdentifier", - "value": "" - }, - { - "key": "childContentTypeVariable", - "value": "" - }, - { - "key": "parentContentTypeVariable", - "value": "" - }, - { - "key": "relFieldVariable", - "value": "" - }, - { - "key": "childContentIdentifier", - "value": "" - }, - { - "key": "parentContentIdentifier", - "value": "" - }, - { - "key": "contentTypeIdWithStoryBlock", - "value": "" - }, - { - "key": "contentTypeVarNameWithStoryBlock", - "value": "" - }, - { - "key": "contentletIdWithEmptyStoryBlock", - "value": "" - }, - { - "key": "dateFieldContentTypeVariable", - "value": "" - } ] } \ No newline at end of file diff --git a/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPI.java b/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPI.java index ef5372545fce..43dd708c85fe 100644 --- a/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPI.java +++ b/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPI.java @@ -1,5 +1,6 @@ package com.dotcms.storage; +import com.dotcms.storage.model.BasicMetadataFields; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.util.Config; @@ -8,8 +9,11 @@ import java.util.Map; /** - * This class is in charge of resolve File (on diff repositories), metadata, etc. + * This Storage API is in charge of generating, removing and storing file metadata in dotCMS using + * the File System as its storage volume. + * * @author jsanca + * @since Oct 19th, 2020 */ public interface FileStorageAPI { @@ -56,9 +60,23 @@ Map generateMetaData(final File binary, final GenerateMeta throws DotDataException; /** - * Retrieve the metadata - * @param requestMetaData {@link FetchMetadataParams} - * @return Map with the metadata + * Retrieves the metadata object from the configured Storage Provider. There are a couple of + * aspects to take into consideration when calling this method: + * + * + * @param requestMetaData The {@link FetchMetadataParams} object specifying how the metadata + * should be retrieved. + * + * @return A key/value Map with the expected metadata properties. + * + * @throws DotDataException An error occurred when retrieving the metadata from the Storage + * Provider. */ Map retrieveMetaData(final FetchMetadataParams requestMetaData) throws DotDataException; diff --git a/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPIImpl.java b/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPIImpl.java index 9b667b54b67e..817442bf8ff1 100644 --- a/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPIImpl.java +++ b/dotCMS/src/main/java/com/dotcms/storage/FileStorageAPIImpl.java @@ -6,10 +6,12 @@ import com.dotmarketing.business.CacheLocator; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.portlets.contentlet.business.MetadataCache; +import com.dotmarketing.util.FileUtil; import com.dotmarketing.util.Logger; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; +import com.liferay.util.StringPool; import io.vavr.control.Try; import java.io.File; @@ -26,6 +28,7 @@ import static com.dotcms.storage.StoragePersistenceAPI.HASH_OBJECT; import static com.dotcms.storage.model.BasicMetadataFields.CONTENT_TYPE_META_KEY; +import static com.dotcms.storage.model.BasicMetadataFields.EDITABLE_AS_TEXT; import static com.dotcms.storage.model.BasicMetadataFields.LENGTH_META_KEY; import static com.dotcms.storage.model.BasicMetadataFields.SIZE_META_KEY; import static com.dotcms.storage.model.BasicMetadataFields.VERSION_KEY; @@ -75,22 +78,11 @@ public FileStorageAPIImpl() { CacheLocator.getMetadataCache()); } - /** - * {@inheritDoc} - * @param binary {@link File} file to get the information - * @return - */ @Override public Map generateRawBasicMetaData(final File binary) { return this.generateBasicMetaData(binary, s -> true); // raw = no filter } - /** - * {@inheritDoc} - * @param binary {@link File} file to get the information - * @param maxLength {@link Long} max length is used when parse the content, how many bytes do you want to parse. - * @return - */ @Override public Map generateRawFullMetaData(final File binary, long maxLength) { return this.generateFullMetaData(binary, s -> true, maxLength); // raw = no filter @@ -195,12 +187,6 @@ private TreeMap ensureTypes(TreeMap return metadataMap; } - /** - * {@inheritDoc} - * @param binary {@link File} file to get the information - * @param configuration {@link GenerateMetadataConfig} - * @return - */ @Override public Map generateMetaData(final File binary, final GenerateMetadataConfig configuration) throws DotDataException { @@ -387,50 +373,59 @@ private void checkOverride(final StoragePersistenceAPI storage, final StorageKey } } - /** - * {@inheritDoc} - * @param requestMetaData {@link FetchMetadataParams} - * @return - */ @Override public Map retrieveMetaData(final FetchMetadataParams requestMetaData) throws DotDataException { if (requestMetaData.isCache()) { - final Map metadataMap = metadataCache + final Map metadataMap = this.metadataCache .getMetadataMap(requestMetaData.getCacheKeySupplier().get()); if (null != metadataMap) { + checkEditableAsText(metadataMap); + putIntoCache(requestMetaData.getCacheKeySupplier().get(), metadataMap); return metadataMap; } } Map metadataMap = null; final StorageKey storageKey = requestMetaData.getStorageKey(); - final StoragePersistenceAPI storage = persistenceProvider + final StoragePersistenceAPI storage = this.persistenceProvider .getStorage(storageKey.getStorage()); this.checkBucket(storageKey, storage); if (storage.existsObject(storageKey.getGroup(), storageKey.getPath())) { - metadataMap = retrieveMetadata(storageKey, storage); Logger.debug(FileStorageAPIImpl.class, - "Retrieve the meta data from storage, path: " + storageKey.getPath()); + () -> "Retrieve the meta data from storage path: " + storageKey.getPath()); + checkEditableAsText(metadataMap); if (null != requestMetaData.getCacheKeySupplier()) { final Map projection = requestMetaData.getProjectionMapForCache().apply(metadataMap); putIntoCache(requestMetaData.getCacheKeySupplier().get(), projection); return projection; } - } - return metadataMap; } - /*** - * {@inheritDoc} - * @param requestMetaData {@link FetchMetadataParams} - * @return - * @throws DotDataException + /** + * Performs a simple check that verifies whether the File that the metadata belongs to can be + * editable as a text file. If it can, the {@link BasicMetadataFields#EDITABLE_AS_TEXT} property + * will be added. + *

This is particularly useful in the File's edit mode in the back-end for dotCMS to allow + * content authors to edit the contents directly in the Code Editor field. If, for any reason, + * the MIME Type cannot be detected, the value of the + * the {@link BasicMetadataFields#EDITABLE_AS_TEXT} property will be set to {@code false}.

+ * + * @param metadataMap The File's metadata Map. */ + private void checkEditableAsText(final Map metadataMap) { + if (!metadataMap.containsKey(BasicMetadataFields.EDITABLE_AS_TEXT.key())) { + final String mimeType = + Try.of(() -> metadataMap.get(CONTENT_TYPE_META_KEY.key()).toString()).getOrElse(StringPool.BLANK); + metadataMap.put(EDITABLE_AS_TEXT.key(), FileUtil.isFileEditableAsText(mimeType)); + } + } + + @Override public boolean removeMetaData(final FetchMetadataParams requestMetaData) throws DotDataException{ boolean deleteSucceeded = false; final StorageKey storageKey = requestMetaData.getStorageKey(); @@ -443,12 +438,7 @@ public boolean removeMetaData(final FetchMetadataParams requestMetaData) throws return deleteSucceeded; } - /*** - * {@inheritDoc} - * @param requestMetaData {@link FetchMetadataParams} - * @return - * @throws DotDataException - */ + @Override public boolean removeVersionMetaData(final FetchMetadataParams requestMetaData) throws DotDataException{ boolean deleteSucceeded = false; final StorageKey storageKey = requestMetaData.getStorageKey(); @@ -461,12 +451,6 @@ public boolean removeVersionMetaData(final FetchMetadataParams requestMetaData) return deleteSucceeded; } - /** - * {@inheritDoc} - * @param fetchMetadataParams - * @param customAttributes - * @throws DotDataException - */ @Override public void putCustomMetadataAttributes( final FetchMetadataParams fetchMetadataParams, @@ -527,12 +511,7 @@ public void putCustomMetadataAttributes( } - /** - * {@inheritDoc} - * @param requestMetadata - * @param metadata - * @throws DotDataException - */ + @Override public boolean setMetadata(final FetchMetadataParams requestMetadata, final Map metadata) throws DotDataException { final StorageKey storageKey = requestMetadata.getStorageKey();