Skip to content

Commit

Permalink
chore(core): Expose the editableAsText attribute, even if the metad…
Browse files Browse the repository at this point in the history
…ata file doesn't have it yet #27393 (#27398)

* fix(Edit Content) #27393 : Expose the `editableAsText` attribute even if the metadata file doesn't have it yet

* Fixing Integration Test

* Fixing `GraphQLTests.json` Postman Test

---------

Co-authored-by: Freddy Montes <751424+fmontes@users.noreply.github.com>
  • Loading branch information
jcastro-dotcms and fmontes authored Feb 1, 2024
1 parent a090821 commit 3e467cb
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 137 deletions.
85 changes: 3 additions & 82 deletions dotCMS/src/curl-test/GraphQLTests.json
Original file line number Diff line number Diff line change
@@ -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": [
{
Expand Down Expand Up @@ -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;",
Expand Down Expand Up @@ -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": ""
}
]
}
26 changes: 22 additions & 4 deletions dotCMS/src/main/java/com/dotcms/storage/FileStorageAPI.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dotcms.storage;

import com.dotcms.storage.model.BasicMetadataFields;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.util.Config;

Expand All @@ -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 {

Expand Down Expand Up @@ -56,9 +60,23 @@ Map<String, Serializable> 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:
* <ul>
* <li>Depending on the configuration of the {@link FetchMetadataParams} parameter, the
* resulting metadata object may be cached.</li>
* <li>For performance reasons, the {@link BasicMetadataFields#EDITABLE_AS_TEXT} property
* is always calculated <b>UNLESS</b> it's already present in the metadata Map. This way,
* Files don't need to be re-indexed for it to be available.</li>
* </ul>
*
* @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<String, Serializable> retrieveMetaData(final FetchMetadataParams requestMetaData) throws DotDataException;

Expand Down
81 changes: 30 additions & 51 deletions dotCMS/src/main/java/com/dotcms/storage/FileStorageAPIImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -75,22 +78,11 @@ public FileStorageAPIImpl() {
CacheLocator.getMetadataCache());
}

/**
* {@inheritDoc}
* @param binary {@link File} file to get the information
* @return
*/
@Override
public Map<String, Serializable> 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<String, Serializable> generateRawFullMetaData(final File binary, long maxLength) {
return this.generateFullMetaData(binary, s -> true, maxLength); // raw = no filter
Expand Down Expand Up @@ -195,12 +187,6 @@ private TreeMap<String, Serializable> ensureTypes(TreeMap<String, Serializable>
return metadataMap;
}

/**
* {@inheritDoc}
* @param binary {@link File} file to get the information
* @param configuration {@link GenerateMetadataConfig}
* @return
*/
@Override
public Map<String, Serializable> generateMetaData(final File binary,
final GenerateMetadataConfig configuration) throws DotDataException {
Expand Down Expand Up @@ -387,50 +373,59 @@ private void checkOverride(final StoragePersistenceAPI storage, final StorageKey
}
}

/**
* {@inheritDoc}
* @param requestMetaData {@link FetchMetadataParams}
* @return
*/
@Override
public Map<String, Serializable> retrieveMetaData(final FetchMetadataParams requestMetaData)
throws DotDataException {
if (requestMetaData.isCache()) {
final Map<String, Serializable> metadataMap = metadataCache
final Map<String, Serializable> metadataMap = this.metadataCache
.getMetadataMap(requestMetaData.getCacheKeySupplier().get());
if (null != metadataMap) {
checkEditableAsText(metadataMap);
putIntoCache(requestMetaData.getCacheKeySupplier().get(), metadataMap);
return metadataMap;
}
}

Map<String, Serializable> 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<String, Serializable> 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.
* <p>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}.</p>
*
* @param metadataMap The File's metadata Map.
*/
private void checkEditableAsText(final Map<String, Serializable> metadataMap) {
if (!metadataMap.containsKey(BasicMetadataFields.EDITABLE_AS_TEXT.key())) {

This comment has been minimized.

Copy link
@wezell

wezell Feb 2, 2024

Contributor

maybe use map.computeIfAbsent()

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();
Expand All @@ -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();
Expand All @@ -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,
Expand Down Expand Up @@ -527,12 +511,7 @@ public void putCustomMetadataAttributes(

}

/**
* {@inheritDoc}
* @param requestMetadata
* @param metadata
* @throws DotDataException
*/
@Override
public boolean setMetadata(final FetchMetadataParams requestMetadata,
final Map<String, Serializable> metadata) throws DotDataException {
final StorageKey storageKey = requestMetadata.getStorageKey();
Expand Down

0 comments on commit 3e467cb

Please sign in to comment.