diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/actionlet/FourEyeApproverActionletTest.java b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/actionlet/FourEyeApproverActionletTest.java index c0c31662fbcc..5292b8465658 100644 --- a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/actionlet/FourEyeApproverActionletTest.java +++ b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/actionlet/FourEyeApproverActionletTest.java @@ -11,9 +11,7 @@ import com.dotcms.contenttype.transform.contenttype.StructureTransformer; import com.dotcms.util.IntegrationTestInitService; import com.dotmarketing.beans.Host; -import com.dotmarketing.beans.Permission; import com.dotmarketing.business.APILocator; -import com.dotmarketing.business.PermissionAPI; import com.dotmarketing.business.Role; import com.dotmarketing.business.RoleAPI; import com.dotmarketing.business.UserAPI; @@ -27,205 +25,263 @@ import com.dotmarketing.portlets.workflows.business.BaseWorkflowIntegrationTest; import com.dotmarketing.portlets.workflows.business.WorkflowAPI; import com.dotmarketing.portlets.workflows.model.WorkflowActionClass; -import com.dotmarketing.portlets.workflows.model.WorkflowActionClassParameter; -import com.dotmarketing.portlets.workflows.model.WorkflowActionletParameter; import com.dotmarketing.portlets.workflows.model.WorkflowProcessor; import com.liferay.portal.model.User; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.List; import org.junit.AfterClass; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; /** + * This class verifies the correct behavior of the {@link FourEyeApproverActionlet}, which requires + * a specific number of users to approve a content BEFORE it can be published. The workflow action + * that triggers this action should have the following actionlets in it: + *
    + *
  1. Unlock Content.
  2. + *
  3. '4 Eye' Approval.
  4. + *
  5. Publish Content.
  6. + *
+ * This ensures that a contentlet will be correctly published after the required approvers have + * accepted the new content. This is how the Multiple Approver action works too. + * * @author Jose Castro * @version 4.3.0 * @since Jan 10, 2018 */ public class FourEyeApproverActionletTest extends BaseWorkflowIntegrationTest { - private static RoleAPI roleAPI; private static WorkflowAPI workflowAPI; private static ContentletAPI contentletAPI; private static LanguageAPI languageAPI; private static ContentTypeAPI contentTypeAPI; private static UserAPI userAPI; - private static Role publisherRole; private static User systemUser; - private static CreateSchemeStepActionResult schemeStepActionResult = null; private static ContentType type = null; private static Contentlet contentlet = null; + private static User publisher1; + private static User publisher2; @BeforeClass public static void prepare() throws Exception { // Setting up the web app environment IntegrationTestInitService.getInstance().init(); - systemUser = APILocator.systemUser(); - roleAPI = APILocator.getRoleAPI(); - publisherRole = roleAPI.findRoleByName("Publisher / Legal", null); workflowAPI = APILocator.getWorkflowAPI(); contentTypeAPI = APILocator.getContentTypeAPI(systemUser); contentletAPI = APILocator.getContentletAPI(); languageAPI = APILocator.getLanguageAPI(); userAPI = APILocator.getUserAPI(); + final RoleAPI roleAPI = APILocator.getRoleAPI(); - final long sysTime = System.currentTimeMillis(); + // Get the test role and two users from such a role + final Role publisherRole = roleAPI.findRoleByName("Publisher / Legal", null); + publisher1 = userAPI.getUsersByNameOrEmailOrUserID("chris@dotcms.com", 0, 1).get(0); + publisher2 = userAPI.getUsersByNameOrEmailOrUserID("daniel@dotcms.com", 0, 1).get(0); - // creates the scheme and actions + // Create the scheme and actions. This method allows you to add just one sub-action + // in the beginning + final long sysTime = System.currentTimeMillis(); schemeStepActionResult = createSchemeStepActionActionlet ("itFourEyeApprovalScheme_" + sysTime, "step1", "action1", CheckinContentActionlet.class); - - final List permissions = new ArrayList<>(); - Permission permission = new Permission(schemeStepActionResult.getAction().getId(), publisherRole.getId(), PermissionAPI.PERMISSION_USE); - permissions.add(permission); - workflowAPI.saveAction(schemeStepActionResult.getAction(), permissions); - - WorkflowActionClass wac = new WorkflowActionClass(); - wac.setActionId(schemeStepActionResult.getAction().getId()); - wac.setClazz(FourEyeApproverActionlet.class.getName()); - wac.setName(WorkFlowActionlet.class.cast(FourEyeApproverActionlet.class.newInstance()).getName()); - wac.setOrder(1); - workflowAPI.saveActionClass(wac); - - wac = new WorkflowActionClass(); - wac.setActionId(schemeStepActionResult.getAction().getId()); - wac.setClazz(PublishContentActionlet.class.getName()); - wac.setName(WorkFlowActionlet.class.cast(PublishContentActionlet.class.newInstance()).getName()); - wac.setOrder(2); - workflowAPI.saveActionClass(wac); - - List actionClasses = workflowAPI - .findActionClasses(schemeStepActionResult.getAction()); - - wac = actionClasses.get(1); - WorkFlowActionlet actionlet = workflowAPI.findActionlet(wac.getClazz()); - List actionletParams = actionlet.getParameters(); - - List newParams = new ArrayList<>(); - WorkflowActionClassParameter testParam = new WorkflowActionClassParameter(); - testParam.setActionClassId(wac.getId()); - testParam.setKey(actionletParams.get(0).getKey()); - testParam.setValue("chris@dotcms.com,daniel@dotcms.com"); - newParams.add(testParam); - - testParam = new WorkflowActionClassParameter(); - testParam.setActionClassId(wac.getId()); - testParam.setKey(actionletParams.get(1).getKey()); - testParam.setValue("2"); - newParams.add(testParam); - - testParam = new WorkflowActionClassParameter(); - testParam.setActionClassId(wac.getId()); - testParam.setKey(actionletParams.get(2).getKey()); - testParam.setValue("'4 Eye' Approval Required"); - newParams.add(testParam); - - testParam = new WorkflowActionClassParameter(); - testParam.setActionClassId(wac.getId()); - testParam.setKey(actionletParams.get(3).getKey()); - testParam.setValue("Please review this content."); - newParams.add(testParam); - - workflowAPI.saveWorkflowActionClassParameters(newParams); - - //Map enteredParams = workflowAPI.findParamsForActionClass(wac); - - // creates the type to trigger the scheme - createTestType(); - - // associated the scheme to the type + // Set the role ID of the people who can use the action + addWhoCanUseToAction(schemeStepActionResult.getAction(), + Collections.singletonList(publisherRole.getId())); + // Add the remaining two sub-actions for this test + addActionletToAction(schemeStepActionResult.getAction().getId(), + FourEyeApproverActionlet.class, 1); + addActionletToAction(schemeStepActionResult.getAction().getId(), + PublishContentActionlet.class, 2); + // Add the required parameters to the '4-eyes' sub-action + final List actionletClasses = getActionletsFromAction( + schemeStepActionResult.getAction()); + WorkflowActionClass workflowActionClass = actionletClasses.get(1); + addParameterValuesToActionlet(workflowActionClass, + Arrays.asList("chris@dotcms.com,daniel@dotcms.com", "2", + "'4 Eye' Approval Required", "Please review this content.")); + + // Create the content type to trigger the scheme + createTestContentType(); + + // Associate the scheme to the content type workflowAPI.saveSchemesForStruct(new StructureTransformer(type).asStructure(), - Arrays.asList(schemeStepActionResult.getScheme())); + Collections.singletonList(schemeStepActionResult.getScheme())); } /** + * Creates the test Content Type + * * @throws DotDataException * @throws DotSecurityException */ - private static void createTestType() + private static void createTestContentType() throws DotDataException, DotSecurityException { - type = contentTypeAPI.save( ContentTypeBuilder.builder(BaseContentType.CONTENT.immutableClass()) .expireDateVar(null).folder(FolderAPI.SYSTEM_FOLDER).host(Host.SYSTEM_HOST) - .description("SaveContentActionletTest...") - .name("SaveContentActionletTest").owner(APILocator.systemUser().toString()) - .variable("SaveContentActionletTest").build()); - + .description("Content Type for testing the 4-Eye Approval actionlet.") + .name("FourEyeActionletTest").owner(APILocator.systemUser().toString()) + .variable("FourEyeActionletTest").build()); final List fields = new ArrayList<>(type.fields()); - fields.add(FieldBuilder.builder(TextField.class).name("title").variable("title") .contentTypeId(type.id()).dataType(DataTypes.TEXT).indexed(true).build()); fields.add(FieldBuilder.builder(TextField.class).name("txt").variable("txt") .contentTypeId(type.id()).dataType(DataTypes.TEXT).indexed(true).build()); - type = contentTypeAPI.save(type, fields); } @Test - public void runActionlet() throws DotSecurityException, DotDataException, InterruptedException { - User publisher1 = userAPI.getUsersByNameOrEmailOrUserID("chris@dotcms.com", 0, 2).get(0); - User publisher2 = userAPI.getUsersByNameOrEmailOrUserID("daniel@dotcms.com", 0, 2).get(0); + public void contentApprovalWithTwoApprovers() + throws DotSecurityException, DotDataException { + // Create a contentlet first and save it final long languageId = languageAPI.getDefaultLanguage().getId(); - Contentlet cont = new Contentlet(); + final Contentlet cont = new Contentlet(); cont.setContentTypeId(type.id()); cont.setOwner(APILocator.systemUser().toString()); cont.setModDate(new Date()); cont.setLanguageId(languageId); - cont.setStringProperty("title", "Test Save"); - cont.setStringProperty("txt", "Test Save Text"); + cont.setStringProperty("title", "4-Eye Approval Test Title"); + cont.setStringProperty("txt", "4-Eye Approval Test Text"); cont.setHost("48190c8c-42c4-46af-8d1a-0cd5db894797"); cont.setFolder("b37bed19-b1fd-497d-be5e-f8cc33c3fb8d"); - - // first save final Contentlet contentlet1 = contentletAPI.checkin(cont, systemUser, false); - boolean isLive = false; + Assert.assertFalse("The contentlet cannot be live, it has just been created.", + contentlet1.isLive()); - // triggering the save content action + // Set the appropriate workflow action to the contentlet contentlet1.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY, schemeStepActionResult.getAction().getId()); contentlet1.setStringProperty("title", "Test Save"); contentlet1.setStringProperty("txt", "Test Save Text"); + // Triggering the save content action WorkflowProcessor processor = workflowAPI.fireWorkflowPreCheckin(contentlet1, publisher1); workflowAPI.fireWorkflowPostCheckin(processor); - Thread.sleep(2000); + // The contentlet MUST NOT be live yet, it needs one more approval final Contentlet contentlet2 = contentletAPI .findContentletByIdentifier(contentlet1.getIdentifier(), false, languageId, systemUser, false); - isLive = contentlet2.isLive(); + Assert.assertFalse("The contentlet cannot be live, it needs 1 more approver.", + contentlet2.isLive()); processor = workflowAPI.fireWorkflowPreCheckin(contentlet2, publisher2); workflowAPI.fireWorkflowPostCheckin(processor); - Thread.sleep(2000); - Contentlet contentlet3 = contentletAPI + // The contentlet MUST be live now as it has been approved by another user + final Contentlet contentlet3 = contentletAPI .findContentletByIdentifier(contentlet2.getIdentifier(), false, languageId, systemUser, false); - isLive = contentlet3.isLive(); + Assert.assertTrue("The contentlet MUST be live, it has all the approvers.", + contentlet2.isLive()); - int counter = 0; + // Cleanup contentlet = contentlet3; + contentletAPI.delete(contentlet3, systemUser, false); + } + + @Test + public void contentApprovalWithOneApprover() + throws DotSecurityException, DotDataException, InterruptedException { + // Create a contentlet first and save it + final long languageId = languageAPI.getDefaultLanguage().getId(); + final Contentlet cont = new Contentlet(); + cont.setContentTypeId(type.id()); + cont.setOwner(APILocator.systemUser().toString()); + cont.setModDate(new Date()); + cont.setLanguageId(languageId); + cont.setStringProperty("title", "4-Eye Approval Test Title"); + cont.setStringProperty("txt", "4-Eye Approval Test Text"); + cont.setHost("48190c8c-42c4-46af-8d1a-0cd5db894797"); + cont.setFolder("b37bed19-b1fd-497d-be5e-f8cc33c3fb8d"); + final Contentlet contentlet1 = contentletAPI.checkin(cont, systemUser, false); + Assert.assertFalse("The contentlet cannot be live, it has just been created.", + contentlet1.isLive()); + + // Set the appropriate workflow action to the contentlet + contentlet1.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY, + schemeStepActionResult.getAction().getId()); + contentlet1.setStringProperty("title", "Test Save"); + contentlet1.setStringProperty("txt", "Test Save Text"); + + // Triggering the save content action + WorkflowProcessor processor = + workflowAPI.fireWorkflowPreCheckin(contentlet1, publisher1); + workflowAPI.fireWorkflowPostCheckin(processor); + + // The contentlet MUST NOT be live yet, it needs one more approval + final Contentlet contentlet2 = contentletAPI + .findContentletByIdentifier(contentlet1.getIdentifier(), + false, languageId, systemUser, false); + Assert.assertFalse("The contentlet cannot be live, it needs 1 more approver.", + contentlet2.isLive()); + + // Cleanup + contentletAPI.delete(contentlet2, systemUser, false); + } + + @Test + public void unauthorizedUserTriggeringWorkflowAction() + throws DotSecurityException, DotDataException { + // Create a contentlet first and save it + final long languageId = languageAPI.getDefaultLanguage().getId(); + final Contentlet cont = new Contentlet(); + cont.setContentTypeId(type.id()); + cont.setOwner(APILocator.systemUser().toString()); + cont.setModDate(new Date()); + cont.setLanguageId(languageId); + cont.setStringProperty("title", "4-Eye Approval Test Title"); + cont.setStringProperty("txt", "4-Eye Approval Test Text"); + cont.setHost("48190c8c-42c4-46af-8d1a-0cd5db894797"); + cont.setFolder("b37bed19-b1fd-497d-be5e-f8cc33c3fb8d"); + final Contentlet contentlet1 = contentletAPI.checkin(cont, systemUser, false); + Assert.assertFalse("The contentlet cannot be live, it has just been created.", + contentlet1.isLive()); + + contentlet1.setStringProperty(Contentlet.WORKFLOW_ACTION_KEY, + schemeStepActionResult.getAction().getId()); + contentlet1.setStringProperty("title", "Test Save"); + contentlet1.setStringProperty("txt", "Test Save Text"); + + // Expect the correct 'user cannot read' exception + boolean isErrorExpected = false; + final String expectedErrorMsg = "User Joe Contributor : dotcms.org.2789 cannot read action action1"; + try { + // Triggering the save content action with a non-authorized user + User incorrectUser = userAPI.getUsersByNameOrEmailOrUserID("joe@dotcms.com", 0, 1).get(0); + workflowAPI.fireWorkflowPreCheckin(contentlet1, incorrectUser); + } catch (Exception e) { + // Get the expected error message that validates if user can use the workflow action + final String errorMsg = e.getCause().getCause().getMessage(); + isErrorExpected = expectedErrorMsg.equalsIgnoreCase(errorMsg); + } + + // Cleanup + contentletAPI.delete(contentlet1, systemUser, false); + + Assert.assertTrue( + "The root cause of the exception IS NOT the expected error. Please check this test.", + isErrorExpected); } /** - * Remove the content type and workflows created + * Removes the test contentlet, workflow, and content type. */ @AfterClass public static void cleanup() throws DotDataException, DotSecurityException, AlreadyExistException { try { if (null != contentlet) { - contentletAPI.delete(contentlet, APILocator.systemUser(), false); + contentletAPI.delete(contentlet, systemUser, false); } } finally { try { diff --git a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java index 57ebcf1fc2a2..8a47fbd54ffe 100644 --- a/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java +++ b/dotCMS/src/integration-test/java/com/dotmarketing/portlets/workflows/business/BaseWorkflowIntegrationTest.java @@ -1,39 +1,52 @@ package com.dotmarketing.portlets.workflows.business; import com.dotcms.IntegrationTestBase; +import com.dotmarketing.beans.Permission; import com.dotmarketing.business.APILocator; +import com.dotmarketing.business.PermissionAPI; import com.dotmarketing.exception.AlreadyExistException; import com.dotmarketing.exception.DotDataException; import com.dotmarketing.exception.DotSecurityException; import com.dotmarketing.portlets.workflows.actionlet.WorkFlowActionlet; import com.dotmarketing.portlets.workflows.model.WorkflowAction; import com.dotmarketing.portlets.workflows.model.WorkflowActionClass; +import com.dotmarketing.portlets.workflows.model.WorkflowActionClassParameter; +import com.dotmarketing.portlets.workflows.model.WorkflowActionletParameter; import com.dotmarketing.portlets.workflows.model.WorkflowScheme; import com.dotmarketing.portlets.workflows.model.WorkflowStep; import com.dotmarketing.util.Logger; - +import java.util.ArrayList; import java.util.Date; import java.util.List; - +import java.util.Map; + +/** + * Utility class that provides useful methods to create and modify Workflows in dotCMS. + * + * @author Jonathan Sanchez + * @version 4.3.0 + */ public class BaseWorkflowIntegrationTest extends IntegrationTestBase { - /** * Creates a new scheme, with a new step, with a new action and action let. * the new action will be associated to the step + * * @param schemeName * @param stepName * @param actionName * @param actionClass + * * @return CreateSchemeStepActionResult: scheme, step, action + * * @throws AlreadyExistException * @throws DotDataException */ - protected static CreateSchemeStepActionResult createSchemeStepActionActionlet (final String schemeName, - final String stepName, - final String actionName, - final Class actionClass) throws AlreadyExistException, DotDataException { - + protected static CreateSchemeStepActionResult createSchemeStepActionActionlet( + final String schemeName, + final String stepName, + final String actionName, + final Class actionClass) throws AlreadyExistException, DotDataException { final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); final WorkflowScheme scheme = new WorkflowScheme(); @@ -62,19 +75,21 @@ protected static CreateSchemeStepActionResult createSchemeStepActionActionlet (f /** * Create an action and actionlet associated to scheme and step + * * @param schemeId * @param stepId * @param actionName * @param actionClass + * * @return CreateSchemeStepActionResult action and actionlet + * * @throws AlreadyExistException * @throws DotDataException */ - protected static CreateSchemeStepActionResult createActionActionlet (final String schemeId, - final String stepId, - final String actionName, - final Class actionClass) throws AlreadyExistException, DotDataException { - + protected static CreateSchemeStepActionResult createActionActionlet(final String schemeId, + final String stepId, + final String actionName, + final Class actionClass) throws AlreadyExistException, DotDataException { final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); final WorkflowAction action = new WorkflowAction(); @@ -94,7 +109,8 @@ protected static CreateSchemeStepActionResult createActionActionlet (final Strin workflowActionClass.setActionId(action.getId()); workflowActionClass.setClazz(actionClass.getName()); try { - workflowActionClass.setName(WorkFlowActionlet.class.cast(actionClass.newInstance()).getName()); + workflowActionClass + .setName(WorkFlowActionlet.class.cast(actionClass.newInstance()).getName()); workflowActionClass.setOrder(0); workflowAPI.saveActionClass(workflowActionClass); } catch (Exception e) { @@ -108,23 +124,27 @@ protected static CreateSchemeStepActionResult createActionActionlet (final Strin /** * Deletes the scheme, the actions and steps + * * @param scheme + * * @throws DotSecurityException * @throws DotDataException * @throws AlreadyExistException */ - protected static void cleanScheme (final WorkflowScheme scheme) throws DotSecurityException, DotDataException, AlreadyExistException { + protected static void cleanScheme(final WorkflowScheme scheme) + throws DotSecurityException, DotDataException, AlreadyExistException { final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); - final List schemeActions = workflowAPI.findActions(scheme, APILocator.systemUser()); + final List schemeActions = workflowAPI + .findActions(scheme, APILocator.systemUser()); - for (final WorkflowAction action: schemeActions) { + for (final WorkflowAction action : schemeActions) { workflowAPI.deleteAction(action); } final List workflowSteps = workflowAPI.findSteps(scheme); - for (final WorkflowStep step: workflowSteps) { + for (final WorkflowStep step : workflowSteps) { workflowAPI.deleteStep(step); } @@ -132,16 +152,108 @@ protected static void cleanScheme (final WorkflowScheme scheme) throws DotSecuri workflowAPI.deleteScheme(scheme); } + /** + * Adds the ID of one or more roles or users who can use the specified workflow action. In the + * UI, this method allows you to set the values for the 'Who Can Use' field. + * + * @param action The ID of the workflow action. + * @param roleIds The list of IDs of roles or users as they are in the 'cms_role' table. + * + * @throws AlreadyExistException + * @throws DotDataException + */ + protected static void addWhoCanUseToAction(final WorkflowAction action, + final List roleIds) + throws AlreadyExistException, DotDataException { + final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); + final List permissions = new ArrayList<>(); + for (final String roleId : roleIds) { + Permission permission = new Permission(action.getId(), roleId, + PermissionAPI.PERMISSION_USE); + permissions.add(permission); + } + workflowAPI.saveAction(action, permissions); + } + + /** + * Adds a specific actionlet (sub-action) to a workflow action in a given order. + * + * @param actionId The workflow action ID. + * @param actionletClass The actionlet class. + * @param order The zero-based order of the actionlet. + * @throws AlreadyExistException + * @throws DotDataException + * @throws IllegalAccessException + * @throws InstantiationException + */ + protected static void addActionletToAction(final String actionId, final Class actionletClass, + final int order) + throws AlreadyExistException, DotDataException, IllegalAccessException, InstantiationException { + final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); + final WorkflowActionClass wac = new WorkflowActionClass(); + wac.setActionId(actionId); + wac.setClazz(actionletClass.getName()); + wac.setName(WorkFlowActionlet.class.cast(actionletClass.newInstance()).getName()); + wac.setOrder(order); + workflowAPI.saveActionClass(wac); + } + + /** + * Returns the actionlets that are associated to the specified workflow action. + * + * @param workflowAction The workflow action. + * @return The list of actionlet classes that will run when the specified action is executed. + * @throws DotDataException + */ + protected static List getActionletsFromAction(final WorkflowAction workflowAction) + throws DotDataException { + final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); + return workflowAPI.findActionClasses(workflowAction); + } + + /** + * Some actionlets have fields where users can set parameters for them. This method allows you + * to set values for the parameters in a given actionlet. + * + * @param workflowActionletClass The actionlet class that will have the new parameters. + * @param paramValues + * @throws DotDataException + */ + protected static void addParameterValuesToActionlet(final WorkflowActionClass workflowActionletClass, + final List paramValues) throws DotDataException { + final WorkflowAPI workflowAPI = APILocator.getWorkflowAPI(); + final WorkFlowActionlet actionlet = workflowAPI.findActionlet(workflowActionletClass.getClazz()); + final List actionletParams = actionlet.getParameters(); + final List newParameters = new ArrayList<>(); + for (int i = 0; i < paramValues.size(); i++) { + final WorkflowActionClassParameter actionletParam = new WorkflowActionClassParameter(); + actionletParam.setActionClassId(workflowActionletClass.getId()); + actionletParam.setKey(actionletParams.get(i).getKey()); + actionletParam.setValue(paramValues.get(i)); + newParameters.add(actionletParam); + } + workflowAPI.saveWorkflowActionClassParameters(newParameters); + } + + /** + * This class represents a simple Workflow Scheme with its minimum parts: + *
    + *
  • A Workflow Scheme.
  • + *
  • One Workflow Step.
  • + *
  • One Workflow Action.
  • + *
  • One Workflow Sub-Action.
  • + *
+ */ public static final class CreateSchemeStepActionResult { private final WorkflowScheme scheme; - private final WorkflowStep step; + private final WorkflowStep step; private final WorkflowAction action; - private final WorkflowActionClass actionClass; - + private final WorkflowActionClass actionClass; public CreateSchemeStepActionResult( - final WorkflowScheme scheme, final WorkflowStep step, final WorkflowAction action, final WorkflowActionClass actionClass) { + final WorkflowScheme scheme, final WorkflowStep step, final WorkflowAction action, + final WorkflowActionClass actionClass) { this.scheme = scheme; this.step = step; this.action = action; diff --git a/dotCMS/src/main/java/com/dotmarketing/portlets/workflows/business/WorkflowAPIImpl.java b/dotCMS/src/main/java/com/dotmarketing/portlets/workflows/business/WorkflowAPIImpl.java index 0cab8ec27874..18ac2491cc6f 100644 --- a/dotCMS/src/main/java/com/dotmarketing/portlets/workflows/business/WorkflowAPIImpl.java +++ b/dotCMS/src/main/java/com/dotmarketing/portlets/workflows/business/WorkflowAPIImpl.java @@ -32,6 +32,8 @@ import com.dotmarketing.portlets.workflows.actionlet.PushNowActionlet; import com.dotmarketing.portlets.workflows.actionlet.PushPublishActionlet; import com.dotmarketing.portlets.workflows.actionlet.ResetTaskActionlet; +import com.dotmarketing.portlets.workflows.actionlet.SaveContentActionlet; +import com.dotmarketing.portlets.workflows.actionlet.SaveContentAsDraftActionlet; import com.dotmarketing.portlets.workflows.actionlet.SetValueActionlet; import com.dotmarketing.portlets.workflows.actionlet.TranslationActionlet; import com.dotmarketing.portlets.workflows.actionlet.TwitterActionlet;