Skip to content

Commit

Permalink
Fix/Feat (CLI/Core) Cleanup content type descriptor (#29579)
Browse files Browse the repository at this point in the history
This PR includes changes to make the CLI Content Type descriptor more
friendly for the end user:
1. CLI: Now we display, for Relationship fields, an enum name for the
relationship cardinality instead of a number. For example: MANY_TO_MANY,
ONE_TO_ONE, etc.
2. CLI: The `systemActionMappings` is simplified by removing unnecessary
properties and using the format that it is expected by the Content Type
resource, example:
```json
  "systemActionMappings" : {
    "NEW" : "b9d89c80-3d88-4311-8365-187323c96436",
    "EDIT": "ceca71a0-deee-4999-bd47-b01baa1bcfc8",
    "UNPUBLISH": "38efc763-d78f-4e4b-b092-59cd8c579b93",
    "UNARCHIVE": "c92f9aa1-9503-4567-ac30-d3242b54d02d"
  }
```

Also, during the "cleanup" process the logic in the Content Type
Resource related to the system action mappings was improved allowing to
properly to add, edit and remove system action mappings.

---------

Co-authored-by: Nollymar Longa <[email protected]>
  • Loading branch information
jgambarios and nollymar authored Aug 19, 2024
1 parent c8f8051 commit 52d3299
Show file tree
Hide file tree
Showing 21 changed files with 1,928 additions and 324 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import io.vavr.Tuple2;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

Expand Down Expand Up @@ -80,8 +79,8 @@ public ContentTypeForm buildForm(final String json) {

final List<ContentType> typesToSave = new JsonContentTypeTransformer(json).asList();
final List<List<WorkflowFormEntry>> workflows = getWorkflowsFromJson(json);
final List<List<Tuple2<SystemAction, String>>> systemActionWorkflowActionIds = systemActionWorkflowActionIdMapFromJson(
json);
final List<List<Tuple2<SystemAction, String>>> systemActionWorkflowActionIds =
systemActionWorkflowActionIdMapFromJson(json);

final List<ContentTypeFormEntry> entries = getContentTypeFormEntries(typesToSave, workflows, systemActionWorkflowActionIds);

Expand All @@ -95,21 +94,25 @@ private List<List<Tuple2<SystemAction, String>>> systemActionWorkflowActionIdMap

try {

final JSONArray jsonArray = new JSONArray(json);
for (Object jsonObject : new JSONArray(json)) {

for (int i = 0; i < jsonArray.size(); i++) {
final JSONObject fieldJsonObject = (JSONObject) jsonArray.get(i);
systemActionWorkflowActionIdMapList.add(this.getSystemActionsWorkflowActionIds(fieldJsonObject));
final JSONObject fieldJsonObject = (JSONObject) jsonObject;
systemActionWorkflowActionIdMapList.add(
getSystemActionsWorkflowActionIds(fieldJsonObject)
);
}
} catch (JSONException e) {

try {
final JSONObject fieldJsonObject = new JSONObject(json);
systemActionWorkflowActionIdMapList.add(this.getSystemActionsWorkflowActionIds(fieldJsonObject));
final JSONObject fieldJsonObject = new JSONObject(json);
systemActionWorkflowActionIdMapList.add(
getSystemActionsWorkflowActionIds(fieldJsonObject)
);
} catch (JSONException e1) {
throw new DotRuntimeException(e1);
}
}

return systemActionWorkflowActionIdMapList;
}

Expand All @@ -123,11 +126,11 @@ private List<ContentTypeFormEntry> getContentTypeFormEntries(
for (int i = 0; i < workflows.size(); i++) {
final List<WorkflowFormEntry> contentTypeWorkflows = workflows.get(i);
final ContentType contentType = typesToSave.get(i);
final List<Tuple2<SystemAction, String>> systemActionWorkflowActions =
i < systemActionWorkflowActionIds.size()?systemActionWorkflowActionIds.get(i):Collections.emptyList();
final var systemActionWorkflowActions = systemActionWorkflowActionIds.get(i);

final ContentTypeFormEntry entry = new ContentTypeFormEntry(contentType,
contentTypeWorkflows, systemActionWorkflowActions);
final ContentTypeFormEntry entry = new ContentTypeFormEntry(
contentType, contentTypeWorkflows, systemActionWorkflowActions
);
entries.add(entry);
}
return entries;
Expand Down Expand Up @@ -249,12 +252,15 @@ private static WorkflowFormEntry mapToWorkflowFormEntry(final JSONObject workflo
private static List<Tuple2<SystemAction, String>> getSystemActionsWorkflowActionIds(
final JSONObject fieldJsonObject) throws JSONException {

SystemAction systemAction = null;
String workflowActionId = null;
final List<Tuple2<SystemAction, String>> tuple2List = new ArrayList<>();
List<Tuple2<SystemAction, String>> tuple2List = null;

if (fieldJsonObject.has(SYSTEM_ACTION_ATTRIBUTE_NAME)) {

SystemAction systemAction;
String workflowActionId;

tuple2List = new ArrayList<>();

final JSONObject systemActionWorkflowActionIdJSONObject = (JSONObject) fieldJsonObject.get(SYSTEM_ACTION_ATTRIBUTE_NAME);
final Iterator keys = systemActionWorkflowActionIdJSONObject.keys();

Expand All @@ -269,6 +275,7 @@ private static List<Tuple2<SystemAction, String>> getSystemActionsWorkflowAction

return tuple2List;
}

}

public static class ContentTypeFormEntry {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,24 @@
import com.dotcms.enterprise.LicenseUtil;
import com.dotcms.enterprise.license.LicenseLevel;
import com.dotcms.repackage.com.google.common.annotations.VisibleForTesting;
import com.dotcms.workflow.form.WorkflowSystemActionForm;
import com.dotcms.workflow.helper.WorkflowHelper;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.exception.DoesNotExistException;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotSecurityException;
import com.dotmarketing.portlets.workflows.business.DotWorkflowException;
import com.dotmarketing.portlets.workflows.business.WorkflowAPI;
import com.dotmarketing.portlets.workflows.business.WorkflowAPI.SystemAction;
import com.dotmarketing.portlets.workflows.model.SystemActionWorkflowActionMapping;
import com.dotmarketing.portlets.workflows.model.WorkflowScheme;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.liferay.portal.language.LanguageException;
import com.liferay.portal.language.LanguageUtil;
import com.liferay.portal.model.User;
import com.liferay.util.LocaleUtil;
import io.vavr.Tuple2;
import java.io.Serializable;
import java.net.URISyntaxException;
import java.util.Comparator;
Expand Down Expand Up @@ -121,6 +127,169 @@ public ContentType evaluateContentTypeRequest(final String idOrVarParameter,
return sortAndFixContentTypeFields(contentType, updatedContentTypeBuilder);
}

/**
* This method processes the workflow action mappings for a given content type. It adds or
* updates the mappings based on the formSystemActionMappings parameter. If isNew is false, it
* also checks for mappings that need to be deleted.
*
* @param contentType The content type for which the mappings need to be
* processed.
* @param user The user performing the action.
* @param formSystemActionMappings The list of system action mappings to be added or updated.
* @param isNew A flag indicating whether the content type is new or not.
* @return The updated version of the action mappings for the given content type.
* @throws DotDataException If there is an issue with the data storage.
* @throws DotSecurityException If there is a security violation.
*/
@WrapInTransaction
public List<SystemActionWorkflowActionMapping> processWorkflowActionMapping(
final ContentType contentType, final User user,
final List<Tuple2<SystemAction, String>> formSystemActionMappings, final boolean isNew)
throws DotDataException, DotSecurityException {

// If not mapping was sent at all by the user, we should ignore this processing,
// nothing to do.
if (null != formSystemActionMappings) {

// Add/update the given mappings
saveSystemActions(formSystemActionMappings, contentType, user);

// Compare to identify what needs to be deleted
if (!isNew) {
deleteSystemActionsIfNecessary(formSystemActionMappings, contentType, user);
}
}

// Regarding what we do, we need to return the updated version of the action mappings
return WorkflowHelper.getInstance().findSystemActionsByContentType(contentType, user);
}

/**
* Saves the system actions for a given list of system action mappings.
*
* @param formSystemActionMappings a list of tuples containing system actions and workflow
* action IDs
* @param contentType the content type to save the system actions for
* @param user the user performing the action
* @throws DotDataException if there is an error accessing the data
* @throws DotSecurityException if the user does not have permission to perform the action
*/
private void saveSystemActions(
final List<Tuple2<SystemAction, String>> formSystemActionMappings,
final ContentType contentType, final User user)
throws DotDataException, DotSecurityException {

final WorkflowHelper workflowHelper = WorkflowHelper.getInstance();

// Now we add/update the given mappings
for (final Tuple2<WorkflowAPI.SystemAction, String> tuple2 : formSystemActionMappings) {

final WorkflowAPI.SystemAction systemAction = tuple2._1;
final String workflowActionId = tuple2._2;
if (UtilMethods.isSet(workflowActionId)) {

Logger.warn(this, "Saving the system action: " + systemAction +
", for content type: " + contentType.variable()
+ ", with the workflow action: "
+ workflowActionId);

workflowHelper.mapSystemActionToWorkflowAction(
new WorkflowSystemActionForm.Builder().
systemAction(systemAction).
actionId(workflowActionId).
contentTypeVariable(contentType.variable()).build(),
user
);
}
}
}

/**
* Deletes system actions if necessary, comparing given system actions with the existing ones.
*
* @param formSystemActionMappings a list of tuple containing system actions and their
* respective IDs
* @param contentType the content type
* @param user the user performing the operation
* @throws DotDataException if there is an error accessing the data
* @throws DotSecurityException if there is an error with security permissions
*/
private void deleteSystemActionsIfNecessary(
final List<Tuple2<SystemAction, String>> formSystemActionMappings,
final ContentType contentType, final User user)
throws DotDataException, DotSecurityException {

final WorkflowHelper workflowHelper = WorkflowHelper.getInstance();

// Handle a special case where having the system action name without an ID implies we
// want to delete the mapping.
for (final Tuple2<WorkflowAPI.SystemAction, String> tuple2 : formSystemActionMappings) {

final WorkflowAPI.SystemAction systemAction = tuple2._1;
final String workflowActionId = tuple2._2;

if (UtilMethods.isNotSet(workflowActionId) && UtilMethods.isSet(systemAction)) {
deleteSystemAction(
systemAction, contentType, user
);
}
}

// Getting the existing mappings
final var existingSystemActionMappings = workflowHelper.findSystemActionsByContentType(
contentType, user
);

// Comparing existing mappings with the mappings in the form to decide whether
// they should be deleted.
for (final var existingSystemActionMapping : existingSystemActionMappings) {

var found = false;

for (final Tuple2<SystemAction, String> formMappingData : formSystemActionMappings) {

if (existingSystemActionMapping.getSystemAction().name().
equalsIgnoreCase(formMappingData._1().name())) {
found = true;
break;
}
}

if (!found) {

// Was not found in the user request, needs to be deleted.
deleteSystemAction(
existingSystemActionMapping.getSystemAction(), contentType, user
);
}

}
}

/**
* Deletes a system action for a specific content type and user.
*
* @param systemAction The system action to be deleted.
* @param contentType The content type associated with the system action.
* @param user The user performing the deletion.
* @throws DotDataException if there is an issue with the data layer.
* @throws DotSecurityException if there is a security violation.
*/
private void deleteSystemAction(final SystemAction systemAction, final ContentType contentType,
final User user) throws DotDataException, DotSecurityException {

final WorkflowHelper workflowHelper = WorkflowHelper.getInstance();

Logger.warn(this, "Deleting the system action: " + systemAction +
", for content type: " + contentType.variable());

final var mappingDeleted = workflowHelper.deleteSystemAction(
systemAction, contentType, user
);

Logger.warn(this, "Deleted the system action mapping: " + mappingDeleted);
}

/**
* Saves the associated schemes for the provided content type.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.dotcms.util.diff.DiffResult;
import com.dotcms.util.pagination.ContentTypesPaginator;
import com.dotcms.util.pagination.OrderDirection;
import com.dotcms.workflow.form.WorkflowSystemActionForm;
import com.dotcms.workflow.helper.WorkflowHelper;
import com.dotmarketing.beans.Host;
import com.dotmarketing.business.APILocator;
Expand Down Expand Up @@ -776,7 +775,6 @@ private Tuple2<ContentType, List<SystemActionWorkflowActionMapping>> saveContent
final ContentTypeAPI contentTypeAPI,
final boolean isNew) throws DotSecurityException, DotDataException {

final List<SystemActionWorkflowActionMapping> systemActionWorkflowActionMappings = new ArrayList<>();
ContentType contentTypeSaved = contentTypeAPI.save(contentType);
this.contentTypeHelper.saveSchemesByContentType(contentTypeSaved, workflows);

Expand All @@ -791,38 +789,11 @@ private Tuple2<ContentType, List<SystemActionWorkflowActionMapping>> saveContent
contentTypeSaved.id(), user
);

if (UtilMethods.isSet(systemActionMappings)) {

for (final Tuple2<WorkflowAPI.SystemAction,String> tuple2 : systemActionMappings) {

final WorkflowAPI.SystemAction systemAction = tuple2._1;
final String workflowActionId = tuple2._2;
if (UtilMethods.isSet(workflowActionId)) {

Logger.warn(this, "Saving the system action: " + systemAction +
", for content type: " + contentTypeSaved.variable() + ", with the workflow action: "
+ workflowActionId );

systemActionWorkflowActionMappings.add(this.workflowHelper.mapSystemActionToWorkflowAction(new WorkflowSystemActionForm.Builder()
.systemAction(systemAction).actionId(workflowActionId)
.contentTypeVariable(contentTypeSaved.variable()).build(), user));
} else if (UtilMethods.isSet(systemAction)) {

if (!isNew) {
Logger.warn(this, "Deleting the system action: " + systemAction +
", for content type: " + contentTypeSaved.variable());

final SystemActionWorkflowActionMapping mappingDeleted =
this.workflowHelper.deleteSystemAction(systemAction, contentTypeSaved, user);

Logger.warn(this, "Deleted the system action mapping: " + mappingDeleted);
}
} else {

throw new IllegalArgumentException("On System Action Mappings, a system action has been sent null or empty");
}
}
}
// Processing the content type action mappings
final List<SystemActionWorkflowActionMapping> systemActionWorkflowActionMappings =
this.contentTypeHelper.processWorkflowActionMapping(
contentTypeSaved, user, systemActionMappings, isNew
);

return Tuple.of(contentTypeSaved, systemActionWorkflowActionMappings);
}
Expand Down
Loading

0 comments on commit 52d3299

Please sign in to comment.