Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(edit-content) : Allowing Users to add separators between workflow actions #26390

Merged
merged 30 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f830a05
feat(Workflows) : Allowing Users to add separators between actions in…
jcastro-dotcms Oct 6, 2023
91dbc46
Code refactoring. Adding Upgrade Task to create a new column: `metada…
jcastro-dotcms Oct 9, 2023
7f29b7d
Adding some Javadoc.
jcastro-dotcms Oct 9, 2023
45c88f5
Merge remote-tracking branch 'origin/master' into issue-26389-create-…
jcastro-dotcms Oct 10, 2023
6bdd0f6
Adding Integration Test and minor changes.
jcastro-dotcms Oct 10, 2023
0e1cd70
Implementing SonarQube feedback.
jcastro-dotcms Oct 10, 2023
1e26510
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Oct 10, 2023
e57bbe2
Implementing SonarQube feedback.
jcastro-dotcms Oct 11, 2023
4c9f37e
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Oct 11, 2023
3060fbf
Implementing SonarQube feedback.
jcastro-dotcms Oct 11, 2023
0e958f4
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Oct 11, 2023
c3cbc91
Implementing SonarQube feedback.
jcastro-dotcms Oct 11, 2023
56014d6
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Oct 11, 2023
4421e4a
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Oct 12, 2023
a56682d
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Dec 7, 2023
4e0eec6
Fixing Upgrade Task's name so that it will get executed correctly.
jcastro-dotcms Dec 7, 2023
7f55da1
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Dec 8, 2023
fc13007
Missing Java import statement.
jcastro-dotcms Dec 8, 2023
f4cf0a2
Implementing SonarQube feedback.
jcastro-dotcms Dec 8, 2023
29715e5
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Dec 8, 2023
f2b36b3
Implementing SonarQube feedback.
jcastro-dotcms Dec 11, 2023
79666b1
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Dec 11, 2023
f31ba93
dev: fix divider button
rjvelazco Dec 11, 2023
977aab4
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
fmontes Dec 11, 2023
6fbde92
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Dec 12, 2023
1c67029
dev: prevent the SEPARATOR action from being displayed and editing
rjvelazco Dec 12, 2023
f5fef64
Style: set default cursor when action is not editable (SEPARATOR)
rjvelazco Dec 12, 2023
870e385
Merge branch 'issue-26389-create-separator-for-Workflow-Actions' of h…
rjvelazco Dec 12, 2023
5bc7a94
Avoid displaying the `Separator` action in the LISTING rendering mode…
jcastro-dotcms Dec 12, 2023
bfa2adb
Merge branch 'master' into issue-26389-create-separator-for-Workflow-…
jcastro-dotcms Dec 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@

import com.dotcms.repackage.javax.validation.constraints.NotNull;
import com.dotcms.rest.api.Validated;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.Role;
import com.dotmarketing.exception.DotRuntimeException;
import com.dotmarketing.portlets.workflows.model.WorkflowAction;
import com.dotmarketing.portlets.workflows.model.WorkflowState;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.vavr.control.Try;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* This class represents a Workflow Action Form used by different parts of the system, such as REST
* Endpoints. It is used to create, update and delete Workflow Actions in dotCMS.
*
* @author Jonathan Sanchez
* @since Dec 6th, 2017
*/
@JsonDeserialize(builder = WorkflowActionForm.Builder.class)
public class WorkflowActionForm extends Validated {

Expand All @@ -17,7 +33,7 @@ public class WorkflowActionForm extends Validated {
@NotNull
private final String schemeId;

// you can send an optional stepId for a new Action when you want to associated the action to the step in the same transaction.
// You can send an optional stepId for a new Action when you want to associate it to the step in the same transaction.
private final String stepId;

@NotNull
Expand All @@ -39,6 +55,7 @@ public class WorkflowActionForm extends Validated {
private final String actionNextStep;
private final String actionNextAssign;
private final String actionCondition;
private Map<String, Object> metadata;

public String getStepId() {
return stepId;
Expand Down Expand Up @@ -100,6 +117,10 @@ public String getActionCondition() {
return actionCondition;
}

public Map<String, Object> getMetadata() {
return this.metadata;
}

@Override
public String toString() {
return "WorkflowActionForm{" +
Expand All @@ -118,6 +139,7 @@ public String toString() {
", actionNextStep='" + actionNextStep + '\'' +
", actionNextAssign='" + actionNextAssign + '\'' +
", actionCondition='" + actionCondition + '\'' +
", metadata='" + metadata + '\'' +
'}';
}

Expand All @@ -138,6 +160,7 @@ public WorkflowActionForm(final Builder builder) {
this.actionAssignable = builder.actionAssignable;
this.actionRoleHierarchyForAssign = builder.actionRoleHierarchyForAssign;
this.roleHierarchyForAssign = (actionAssignable && actionRoleHierarchyForAssign);
this.metadata = builder.metadata;
this.checkValid();
}

Expand All @@ -163,9 +186,14 @@ public static final class Builder {
@JsonProperty(required = true)
private boolean actionCommentable;

/**
* @deprecated This attribute is not necessary as a single workflow action can be available
* for locked and/or unlocked content now. See
* <a href="https://github.com/dotCMS/core/issues/13287">#13287</a>
*/
@Deprecated
@JsonProperty(required = true)
private boolean requiresCheckout;
private boolean requiresCheckout = false;
@JsonProperty(required = true)
private boolean actionRoleHierarchyForAssign;
@JsonProperty(required = true)
Expand All @@ -177,7 +205,8 @@ public static final class Builder {

@JsonProperty(required = true)
private Set<WorkflowState> showOn;

@JsonProperty()
private Map<String, Object> metadata;

public Builder showOn(Set<WorkflowState> showOn) {
this.showOn = showOn;
Expand Down Expand Up @@ -250,8 +279,45 @@ public Builder actionCondition(String actionCondition) {
return this;
}

public Builder metadata(final Map<String, Object> metadata) {
this.metadata = metadata;
return this;
}

/**
* Marks this Workflow Action as a Separator. This is a special type of action that does
* not execute any sub-actions at all, as it simply groups X number of actions together
* in the UI. The result of this may be seen as the differentiation between Primary and
* Secondary Actions.
*
* @param schemeId The ID of the Workflow Scheme that this action belongs to.
* @param stepId The ID of the Workflow Step that this action belongs to.
*
* @return The current {@link Builder} instance.
*/
public Builder separator(final String schemeId, final String stepId) {
this.schemeId(schemeId);
this.stepId(stepId);
this.actionName(WorkflowAction.SEPARATOR);
this.actionAssignable(false);
this.actionCommentable(false);
this.actionRoleHierarchyForAssign(false);
this.actionNextStep(WorkflowAction.CURRENT_STEP);
this.actionNextAssign(Try.of(() -> APILocator.getRoleAPI().loadRoleByKey(Role.CMS_ANONYMOUS_ROLE).getId())
.getOrElseThrow(e -> new DotRuntimeException("Anonymous Role ID not found", e)));
this.actionCondition(WorkflowAction.SEPARATOR);
this.showOn(Arrays.stream(WorkflowState.values()).collect(java.util.stream.Collectors.toSet()));
if (null == this.metadata) {
this.metadata = new HashMap<>();
}
this.metadata.put("subtype", WorkflowAction.SEPARATOR);
return this;
}

public WorkflowActionForm build() {
return new WorkflowActionForm(this);
}

}

}
35 changes: 21 additions & 14 deletions dotCMS/src/main/java/com/dotcms/workflow/helper/WorkflowHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -1536,11 +1536,16 @@ private ContentType findContentType (final String variable, final User user)
}

/**
* Save a WorkflowActionForm returning the WorkflowAction created.
* A WorkflowActionForm can send a stepId in that case the Action will be associated to the Step in the same transaction.
* @param actionId When present an update operation takes place otherwise an insert is executed
* @param workflowActionForm WorkflowActionForm
* @return WorkflowAction (workflow action created)
* Saves a Workflow Action. A {@link WorkflowActionForm} object can send a Step ID, in which
* case the Action will be associated to the Step in the same transaction.
*
* @param actionId If present, an update operation takes place. Otherwise, an insert
* is executed.
* @param workflowActionForm The {@link WorkflowActionForm} object with the Workflow Action data
* that will be saved.
* @param user The {@link User} that is performing this action.
*
* @return The {@link WorkflowAction} object that was created.
*/
@WrapInTransaction
public WorkflowAction saveAction(final String actionId, final WorkflowActionForm workflowActionForm, final User user) {
Expand All @@ -1564,7 +1569,7 @@ public WorkflowAction saveAction(final String actionId, final WorkflowActionForm
newAction.setRequiresCheckout(false);
newAction.setShowOn(workflowActionForm.getShowOn());
newAction.setRoleHierarchyForAssign(workflowActionForm.isRoleHierarchyForAssign());

newAction.setMetadata(workflowActionForm.getMetadata());
try {

newAction.setNextAssign(this.resolveRole(actionNextAssign).getId());
Expand Down Expand Up @@ -1607,17 +1612,19 @@ public WorkflowAction saveAction(final String actionId, final WorkflowActionForm
workflowActionClass.setName(NotifyAssigneeActionlet.class.getDeclaredConstructor().newInstance().getName());
workflowActionClass.setOrder(0);
this.workflowAPI.saveActionClass(workflowActionClass, user);
} catch (Exception e) {
Logger.error(this.getClass(), e.getMessage());
Logger.debug(this, e.getMessage(), e);
throw new DotWorkflowException(e.getMessage(), e);
} catch (final Exception e) {
final String errorMsg = String.format("Failed to save Workflow Action Class with ID '%s': %s", newAction.getId(), ExceptionUtil.getErrorMessage(e));
Logger.error(this.getClass(), errorMsg);
Logger.debug(this, errorMsg, e);
throw new DotWorkflowException(errorMsg, e);
}
});
}
} catch (Exception e) {
Logger.error(this.getClass(), e.getMessage());
Logger.debug(this, e.getMessage(), e);
throw new DotWorkflowException(e.getMessage(), e);
} catch (final Exception e) {
final String errorMsg = String.format("Failed to save Workflow Action '%s': %s", actionId, ExceptionUtil.getErrorMessage(e));
Logger.error(this.getClass(), errorMsg);
Logger.debug(this, errorMsg, e);
throw new DotWorkflowException(errorMsg, e);
}

return newAction;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.dotmarketing.portlets.workflows.ajax;

import com.dotcms.exception.ExceptionUtil;
import com.dotcms.workflow.form.WorkflowActionForm;
import com.dotcms.workflow.form.WorkflowReorderBean;
import com.dotcms.workflow.helper.WorkflowHelper;
Expand All @@ -9,6 +10,7 @@
import com.dotmarketing.portlets.workflows.model.WorkflowState;
import com.dotmarketing.portlets.workflows.model.WorkflowStep;
import com.dotmarketing.util.Logger;
import com.dotmarketing.util.UtilMethods;
import com.liferay.portal.model.User;
import com.liferay.util.StringPool;

Expand All @@ -20,21 +22,30 @@
import java.util.List;
import java.util.Set;


@Deprecated
/**
* This class is responsible for handling all CRUD requests related to Workflow Actions generated by
* DWR requests.
*
* @deprecated Classes related to the DWR framework will be removed in the near future.
* @author root
* @since Mar 22nd, 2012
*/
@Deprecated(forRemoval = true)
public class WfActionAjax extends WfBaseAction {

private final WorkflowHelper workflowHelper = WorkflowHelper.getInstance();
private final UserWebAPI userWebAPI = WebAPILocator.getUserWebAPI();

public void action(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{};
public void action(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// do nothing
}

public void reorder(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {

final String actionId = request.getParameter("actionId");
final String stepId = request.getParameter("stepId");
final String orderParam = request.getParameter("order");
final String actionId = request.getParameter(ACTION_ID_PARAM);
final String stepId = request.getParameter(STEP_ID_PARAM);
final String orderParam = request.getParameter(ORDER_PARAM);

try {

Expand All @@ -52,15 +63,14 @@ public void reorder(final HttpServletRequest request,
* Deletes just the action associated to the step, but the action still alive as part of the scheme.
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void deleteActionForStep(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {
final HttpServletResponse response) throws IOException {

final String actionId = request.getParameter("actionId");
final String stepId = request.getParameter("stepId");
WorkflowStep workflowStep = null;
final String actionId = request.getParameter(ACTION_ID_PARAM);
final String stepId = request.getParameter(STEP_ID_PARAM);
WorkflowStep workflowStep;

try {

Expand All @@ -86,7 +96,7 @@ public void deleteActionForStep(final HttpServletRequest request,
public void delete(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {

final String actionId = request.getParameter("actionId");
final String actionId = request.getParameter(ACTION_ID_PARAM);

try {

Expand All @@ -101,41 +111,53 @@ public void delete(final HttpServletRequest request,
}
} // delete.


/**
* Save or updates a Workflow Action.
*
* @param request The current instance of the {@link HttpServletRequest} class.
* @param response The current instance of the {@link HttpServletResponse} class.
*
* @throws IOException An error occurred when writing either a successful or failure response
*/
public void save(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {

final HttpServletResponse response) throws IOException {
final String actionId = request.getParameter(ACTION_ID_PARAM);
final String actionName = request.getParameter(ACTION_NAME_PARAM);
final WorkflowActionForm.Builder builder = new WorkflowActionForm.Builder();

builder.actionName(request.getParameter("actionName"))
.actionId (request.getParameter("actionId"))
.schemeId (request.getParameter("schemeId"))
.stepId (request.getParameter("stepId"))
.actionIcon(request.getParameter("actionIconSelect"))
.actionAssignable (request.getParameter("actionAssignable") != null)
.actionCommentable(request.getParameter("actionCommentable") != null)
.requiresCheckout(false)
.actionRoleHierarchyForAssign(request.getParameter("actionRoleHierarchyForAssign") != null)
.actionNextStep(request.getParameter ("actionNextStep"))
.actionNextAssign(request.getParameter("actionAssignToSelect"))
.actionCondition(request.getParameter ("actionCondition"))
.showOn(WorkflowState.toSet(request.getParameterValues ("showOn")));

final String whoCanUseTmp = request.getParameter("whoCanUse");
final List<String> whoCanUse = Arrays.asList(whoCanUseTmp.split(","));
if (!WorkflowAction.SEPARATOR.equalsIgnoreCase(actionId)) {
builder.actionName(actionName)
.actionId(actionId)
.schemeId(request.getParameter(SCHEME_ID_PARAM))
.stepId(request.getParameter(STEP_ID_PARAM))
.actionIcon(request.getParameter(ACTION_ICON_SELECT_PARAM))
.actionAssignable(request.getParameter(ACTION_ASSIGNABLE_PARAM) != null)
.actionCommentable(request.getParameter(ACTION_COMMENTABLE_PARAM) != null)
.requiresCheckout(false)
.actionRoleHierarchyForAssign(request.getParameter(ACTION_ROLE_HIERARCHY_FOR_ASSIGN_PARAM) != null)
.actionNextStep(request.getParameter(ACTION_NEXT_STEP_PARAM))
.actionNextAssign(request.getParameter(ACTION_ASSIGN_TO_SELECT_PARAM))
.actionCondition(request.getParameter(ACTION_CONDITION_PARAM))
.showOn(WorkflowState.toSet(request.getParameterValues(SHOW_ON_PARAM)));
} else {
builder.separator(request.getParameter(SCHEME_ID_PARAM), request.getParameter(STEP_ID_PARAM));
}
final String whoCanUseTmp = UtilMethods.isSet(request.getParameter(WHO_CAN_USE_PARAM))
? request.getParameter(WHO_CAN_USE_PARAM)
: StringPool.BLANK;
final List<String> whoCanUse = Arrays.asList(whoCanUseTmp.split(StringPool.COMMA));
builder.whoCanUse(whoCanUse);

WorkflowAction newAction = null;
WorkflowAction newAction;
final User user = this.userWebAPI.getUser(request);

try {

newAction = this.workflowHelper.saveAction(builder.build(), user);
response.getWriter().println("SUCCESS:" + newAction.getId());
} catch (Exception e) {

Logger.error(this.getClass(), e.getMessage(), e);
writeError(response, e.getMessage());
} catch (final Exception e) {
Logger.error(this.getClass(), String.format("An error occurred when saving Workflow " +
"Action '%s' [ %s ]: %s", actionName, actionId,
ExceptionUtil.getErrorMessage(e)), e);
writeError(response, ExceptionUtil.getErrorMessage(e));
}
} // save.

Expand All @@ -149,4 +171,5 @@ public void save(final HttpServletRequest request,
protected Set<String> getAllowedCommands() {
return Set.of( "action", "reorder", "delete", "add", "save", "deleteActionForStep" );
}

}
Loading
Loading