Bugfixes for workflow handling.
parent
eef4210785
commit
7dd51f4c46
|
|
@ -301,19 +301,19 @@ public class DocumentWorkflowController {
|
||||||
* @param documentPath The path of the currentd document.
|
* @param documentPath The path of the currentd document.
|
||||||
* @param newWorkflowUuid The UUID of the the workflow definition form
|
* @param newWorkflowUuid The UUID of the the workflow definition form
|
||||||
* which the new workflow is created.
|
* which the new workflow is created.
|
||||||
* @param returnUrl The URL to return to.
|
* @param returnUrlParam The URL to return to.
|
||||||
*
|
*
|
||||||
* @return A redirect to the {@code returnUrl}.
|
* @return A redirect to the {@code returnUrl}.
|
||||||
*/
|
*/
|
||||||
@POST
|
@POST
|
||||||
@Path("@workflow/@applyAlternative/{workflowIdentifier}")
|
@Path("/apply-alternative")
|
||||||
@AuthorizationRequired
|
@AuthorizationRequired
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public String applyAlternateWorkflow(
|
public String applyAlternateWorkflow(
|
||||||
@PathParam("sectionIdentifier") final String sectionIdentifier,
|
@PathParam("sectionIdentifier") final String sectionIdentifier,
|
||||||
@PathParam("documentPath") final String documentPath,
|
@PathParam("documentPath") final String documentPath,
|
||||||
@FormParam("newWorkflowUuid") final String newWorkflowUuid,
|
@FormParam("newWorkflowUuid") final String newWorkflowUuid,
|
||||||
@FormParam("returnUrl") final String returnUrl
|
@FormParam("returnUrl") final String returnUrlParam
|
||||||
) {
|
) {
|
||||||
final Optional<ContentSection> sectionResult = sectionsUi
|
final Optional<ContentSection> sectionResult = sectionsUi
|
||||||
.findContentSection(sectionIdentifier);
|
.findContentSection(sectionIdentifier);
|
||||||
|
|
@ -347,18 +347,35 @@ public class DocumentWorkflowController {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Optional<Workflow> workflowResult = section
|
final Optional<Workflow> workflowTemplateResult = section
|
||||||
.getWorkflowTemplates()
|
.getWorkflowTemplates()
|
||||||
.stream()
|
.stream()
|
||||||
.filter(template -> template.getUuid().equals(newWorkflowUuid))
|
.filter(template -> template.getUuid().equals(newWorkflowUuid))
|
||||||
.findAny();
|
.findAny();
|
||||||
if (!workflowResult.isPresent()) {
|
if (!workflowTemplateResult.isPresent()) {
|
||||||
models.put("section", section.getLabel());
|
models.put("section", section.getLabel());
|
||||||
models.put("workflowUuid", newWorkflowUuid);
|
models.put("workflowUuid", newWorkflowUuid);
|
||||||
return "org/librecms/ui/contentsection/documents/workflow-not-found.xhtml";
|
return "org/librecms/ui/contentsection/documents/workflow-not-found.xhtml";
|
||||||
}
|
}
|
||||||
|
|
||||||
workflowManager.createWorkflow(workflowResult.get(), item);
|
final String returnUrl;
|
||||||
|
if (returnUrlParam.startsWith("/@contentsections")) {
|
||||||
|
returnUrl = returnUrlParam.substring("/@contentsections".length());
|
||||||
|
} else if(returnUrlParam.startsWith("@contentsections")) {
|
||||||
|
returnUrl = returnUrlParam.substring("@contentsections".length());
|
||||||
|
} else {
|
||||||
|
returnUrl = returnUrlParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Workflow oldWorkflow = item.getWorkflow();
|
||||||
|
if (oldWorkflow != null) {
|
||||||
|
workflowManager.removeWorkflowFromObject(oldWorkflow, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Workflow workflow = workflowManager.createWorkflow(
|
||||||
|
workflowTemplateResult.get(), item
|
||||||
|
);
|
||||||
|
item.setWorkflow(workflow);
|
||||||
return String.format("redirect:%s", returnUrl);
|
return String.format("redirect:%s", returnUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import org.librecms.contentsection.Folder;
|
||||||
import org.librecms.contentsection.FolderManager;
|
import org.librecms.contentsection.FolderManager;
|
||||||
import org.librecms.contentsection.privileges.ItemPrivileges;
|
import org.librecms.contentsection.privileges.ItemPrivileges;
|
||||||
import org.librecms.ui.contentsections.FolderBreadcrumbsModel;
|
import org.librecms.ui.contentsections.FolderBreadcrumbsModel;
|
||||||
|
import org.librecms.ui.contentsections.WorkflowTemplateListModel;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
@ -45,6 +46,7 @@ import javax.enterprise.context.RequestScoped;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.transaction.Transactional;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -166,6 +168,11 @@ public class SelectedDocumentModel {
|
||||||
*/
|
*/
|
||||||
private List<TaskListEntry> allTasks;
|
private List<TaskListEntry> allTasks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Available workflows that can be assigned to the item.
|
||||||
|
*/
|
||||||
|
private List<WorkflowTemplateListModel> availableWorkflows;
|
||||||
|
|
||||||
public String getItemName() {
|
public String getItemName() {
|
||||||
return itemName;
|
return itemName;
|
||||||
}
|
}
|
||||||
|
|
@ -216,12 +223,17 @@ public class SelectedDocumentModel {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<WorkflowTemplateListModel> getAvailableWorkflows() {
|
||||||
|
return Collections.unmodifiableList(availableWorkflows);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current content item/document and sets the properties of this
|
* Sets the current content item/document and sets the properties of this
|
||||||
* model based on the item.
|
* model based on the item.
|
||||||
*
|
*
|
||||||
* @param item
|
* @param item
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
void setContentItem(final ContentItem item) {
|
void setContentItem(final ContentItem item) {
|
||||||
this.item = Objects.requireNonNull(item);
|
this.item = Objects.requireNonNull(item);
|
||||||
itemName = item.getDisplayName();
|
itemName = item.getDisplayName();
|
||||||
|
|
@ -261,6 +273,14 @@ public class SelectedDocumentModel {
|
||||||
currentTask.setCurrentTask(true);
|
currentTask.setCurrentTask(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
availableWorkflows = item
|
||||||
|
.getContentType()
|
||||||
|
.getContentSection()
|
||||||
|
.getWorkflowTemplates()
|
||||||
|
.stream()
|
||||||
|
.map(this::buildWorkflowTemplateListModel)
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -395,4 +415,30 @@ public class SelectedDocumentModel {
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method for building a {@link WorkflowTemplateListModel} for a
|
||||||
|
* {@link Workflow}.
|
||||||
|
*
|
||||||
|
* @param workflow The workflow.
|
||||||
|
*
|
||||||
|
* @return A {@link WorkflowTemplateListModel} for the {@code workflow}.
|
||||||
|
*/
|
||||||
|
private WorkflowTemplateListModel buildWorkflowTemplateListModel(
|
||||||
|
final Workflow workflow
|
||||||
|
) {
|
||||||
|
final WorkflowTemplateListModel model = new WorkflowTemplateListModel();
|
||||||
|
model.setDescription(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(
|
||||||
|
workflow.getDescription()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
model.setHasTasks(!workflow.getTasks().isEmpty());
|
||||||
|
model.setName(
|
||||||
|
globalizationHelper.getValueFromLocalizedString(workflow.getName())
|
||||||
|
);
|
||||||
|
model.setUuid(workflow.getUuid());
|
||||||
|
model.setWorkflowId(workflow.getWorkflowId());
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<!DOCTYPE html [<!ENTITY times '×'>]>
|
<!DOCTYPE html [<!ENTITY times '×'>]>
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:bootstrap="http://xmlns.jcp.org/jsf/composite/components/bootstrap"
|
||||||
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
|
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
|
||||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
|
xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
|
||||||
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/contentsection.xhtml">
|
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/contentsection.xhtml">
|
||||||
|
|
@ -29,10 +30,72 @@
|
||||||
#{CmsAdminMessages['contentsection.document.authoring.workflow.active_workflow_label']}:
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.active_workflow_label']}:
|
||||||
#{CmsSelectedDocumentModel.workflowName}
|
#{CmsSelectedDocumentModel.workflowName}
|
||||||
<button class="btn btn-secondary btn-sm"
|
<button class="btn btn-secondary btn-sm"
|
||||||
|
data-toggle="modal"
|
||||||
|
data-target="#change-workflow-dialog"
|
||||||
disabled="#{!CmsSelectedDocumentModel.canChangeWorkflow ? 'disabled': ''}"
|
disabled="#{!CmsSelectedDocumentModel.canChangeWorkflow ? 'disabled': ''}"
|
||||||
type="button">
|
type="button">
|
||||||
#{CmsAdminMessages['contentsection.document.authoring.workflow.change_workflow']}
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.change_workflow']}
|
||||||
</button>
|
</button>
|
||||||
|
<c:if test="#{CmsSelectedDocumentModel.canChangeWorkflow}">
|
||||||
|
<div aria-labelledby="change-workflow-dialog-title"
|
||||||
|
aria-hidden="true"
|
||||||
|
class="modal fade"
|
||||||
|
id="change-workflow-dialog"
|
||||||
|
tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@workflow/apply-alternative"
|
||||||
|
class="modal-content"
|
||||||
|
method="post">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title"
|
||||||
|
id="change-workflow-dialog-title">
|
||||||
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.change_workflow.title']}
|
||||||
|
</h3>
|
||||||
|
<button aria-label="#{CmsAdminMessages['contentsection.document.authoring.workflow.change_workflow.close']} "
|
||||||
|
class="close"
|
||||||
|
data-dismiss="modal"
|
||||||
|
type="button">
|
||||||
|
<bootstrap:svgIcon icon="x-circle" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<c:forEach items="#{CmsSelectedDocumentModel.availableWorkflows}"
|
||||||
|
var="workflow">
|
||||||
|
|
||||||
|
<div class="form-group form-check">
|
||||||
|
<input
|
||||||
|
aria-describedby="workflow-#{workflow.uuid}-description"
|
||||||
|
id="workflow-#{workflow.uuid}"
|
||||||
|
name="newWorkflowUuid"
|
||||||
|
type="radio"
|
||||||
|
value="#{workflow.uuid}"/>
|
||||||
|
<label for="workflow-#{workflow.uuid}">#{workflow.name}</label>
|
||||||
|
<span class="form-text text-muted"
|
||||||
|
id="workflow-#{workflow.uuid}-description">
|
||||||
|
#{workflow.description}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</c:forEach>
|
||||||
|
<input
|
||||||
|
name="returnUrl"
|
||||||
|
type="hidden"
|
||||||
|
value="#{authoringStep}" />
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button class="btn btn-warning"
|
||||||
|
data-dismiss="modal"
|
||||||
|
type="button">
|
||||||
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.change_workflow.close']}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-success"
|
||||||
|
type="submit">
|
||||||
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.change_workflow.submit']}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</c:if>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<c:choose>
|
<c:choose>
|
||||||
|
|
@ -40,7 +103,7 @@
|
||||||
#{CmsAdminMessages['contentsection.document.authoring.workflow.active_task']}
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.active_task']}
|
||||||
#{CmsSelectedDocumentModel.currentTask.label}
|
#{CmsSelectedDocumentModel.currentTask.label}
|
||||||
</c:when>
|
</c:when>
|
||||||
<c:otherwise>
|
<c:when test="#{CmsSelectedDocumentModel.workflowName != null}">
|
||||||
#{CmsAdminMessages['contentsection.document.authoring.workflow.active_task.none']}
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.active_task.none']}
|
||||||
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@workflow/@start"
|
<form action="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@workflow/@start"
|
||||||
method="post">
|
method="post">
|
||||||
|
|
@ -53,6 +116,9 @@
|
||||||
#{CmsAdminMessages['contentsection.document.authoring.workflow.start']}
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.start']}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
</c:when>
|
||||||
|
<c:otherwise>
|
||||||
|
#{CmsAdminMessages['contentsection.document.authoring.workflow.none']}
|
||||||
</c:otherwise>
|
</c:otherwise>
|
||||||
</c:choose>
|
</c:choose>
|
||||||
<c:if test="#{CmsSelectedDocumentModel.currentTask != null}">
|
<c:if test="#{CmsSelectedDocumentModel.currentTask != null}">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml">
|
<ui:composition template="/WEB-INF/views/org/librecms/ui/contentsection/documents/authoringstep.xhtml">
|
||||||
|
|
||||||
<ui:param name="authoringStep"
|
<ui:param name="authoringStep"
|
||||||
value="/libreccm/@contentsections/info/documents/test-article/@article-basicproperties" />
|
value="#{mvc.basePath}/#{ContentSectionModel.sectionName}/documents/#{CmsSelectedDocumentModel.itemPath}/@article-basicproperties" />
|
||||||
|
|
||||||
<ui:define name="authoringStep">
|
<ui:define name="authoringStep">
|
||||||
<h2>#{CmsArticleMessageBundle.getMessage('basicproperties.header', [CmsArticlePropertiesStep.name])}</h2>
|
<h2>#{CmsArticleMessageBundle.getMessage('basicproperties.header', [CmsArticlePropertiesStep.name])}</h2>
|
||||||
|
|
|
||||||
|
|
@ -1010,3 +1010,7 @@ pages.page.details.dialog.category.label=Category
|
||||||
pages.page.details.dialog.properties.label=Properties
|
pages.page.details.dialog.properties.label=Properties
|
||||||
pages.page.details.dialog.properties.key=Name
|
pages.page.details.dialog.properties.key=Name
|
||||||
pages.page.details.dialog.properties.value=Value
|
pages.page.details.dialog.properties.value=Value
|
||||||
|
contentsection.document.authoring.workflow.none=No workflow assigned
|
||||||
|
contentsection.document.authoring.workflow.change_workflow.title=Assign workflow
|
||||||
|
contentsection.document.authoring.workflow.change_workflow.submit=Assign workflow
|
||||||
|
contentsection.document.authoring.workflow.change_workflow.close=Cancel
|
||||||
|
|
|
||||||
|
|
@ -1011,3 +1011,7 @@ pages.page.details.dialog.category.label=Kategorie
|
||||||
pages.page.details.dialog.properties.label=Eigenschaften
|
pages.page.details.dialog.properties.label=Eigenschaften
|
||||||
pages.page.details.dialog.properties.key=Name
|
pages.page.details.dialog.properties.key=Name
|
||||||
pages.page.details.dialog.properties.value=Wert
|
pages.page.details.dialog.properties.value=Wert
|
||||||
|
contentsection.document.authoring.workflow.none=Kein Arbeitsablauf zugewiesen
|
||||||
|
contentsection.document.authoring.workflow.change_workflow.title=Arbeitsablauf zuweisen
|
||||||
|
contentsection.document.authoring.workflow.change_workflow.submit=Arbeitsablauf zuweisen
|
||||||
|
contentsection.document.authoring.workflow.change_workflow.close=Abbrechen
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,12 @@ import java.util.Optional;
|
||||||
*/
|
*/
|
||||||
@RequestScoped
|
@RequestScoped
|
||||||
public class WorkflowManager implements Serializable {
|
public class WorkflowManager implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = -6939804120313699606L;
|
private static final long serialVersionUID = -6939804120313699606L;
|
||||||
|
|
||||||
private final static Logger LOGGER = LogManager.getLogger(
|
private final static Logger LOGGER = LogManager.getLogger(
|
||||||
WorkflowManager.class);
|
WorkflowManager.class
|
||||||
|
);
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
|
|
@ -105,7 +107,8 @@ public class WorkflowManager implements Serializable {
|
||||||
@PostConstruct
|
@PostConstruct
|
||||||
private void init() {
|
private void init() {
|
||||||
final KernelConfig kernelConfig = confManager.findConfiguration(
|
final KernelConfig kernelConfig = confManager.findConfiguration(
|
||||||
KernelConfig.class);
|
KernelConfig.class
|
||||||
|
);
|
||||||
defaultLocale = kernelConfig.getDefaultLocale();
|
defaultLocale = kernelConfig.getDefaultLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,23 +124,29 @@ public class WorkflowManager implements Serializable {
|
||||||
@AuthorizationRequired
|
@AuthorizationRequired
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Workflow createWorkflow(final Workflow template,
|
public Workflow createWorkflow(
|
||||||
final CcmObject object) {
|
final Workflow template, final CcmObject object
|
||||||
Objects.requireNonNull(template,
|
) {
|
||||||
"Can't create a workflow without a template.");
|
Objects.requireNonNull(
|
||||||
|
template, "Can't create a workflow without a template."
|
||||||
|
);
|
||||||
if (!template.isAbstractWorkflow()) {
|
if (!template.isAbstractWorkflow()) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"The provided template is not an abstract workflow");
|
"The provided template is not an abstract workflow"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Objects.requireNonNull(object,
|
Objects.requireNonNull(
|
||||||
"Can't create a workflow without an object.");
|
object, "Can't create a workflow without an object."
|
||||||
|
);
|
||||||
|
|
||||||
final Workflow workflow = new Workflow();
|
final Workflow workflow = new Workflow();
|
||||||
|
|
||||||
final LocalizedString name = new LocalizedString();
|
final LocalizedString name = new LocalizedString();
|
||||||
template.getName().getValues().forEach(
|
template
|
||||||
(locale, str) -> name.addValue(locale, str));
|
.getName()
|
||||||
|
.getValues()
|
||||||
|
.forEach((locale, str) -> name.addValue(locale, str));
|
||||||
workflow.setName(name);
|
workflow.setName(name);
|
||||||
|
|
||||||
final LocalizedString description = new LocalizedString();
|
final LocalizedString description = new LocalizedString();
|
||||||
|
|
@ -156,10 +165,13 @@ public class WorkflowManager implements Serializable {
|
||||||
.forEach(taskTemplate -> createTask(workflow, taskTemplate, tasks));
|
.forEach(taskTemplate -> createTask(workflow, taskTemplate, tasks));
|
||||||
template
|
template
|
||||||
.getTasks()
|
.getTasks()
|
||||||
.forEach(taskTemplate -> {
|
.forEach(
|
||||||
fixTaskDependencies(taskTemplate,
|
taskTemplate -> {
|
||||||
|
fixTaskDependencies(
|
||||||
|
taskTemplate,
|
||||||
tasks.get(taskTemplate.getTaskId()),
|
tasks.get(taskTemplate.getTaskId()),
|
||||||
tasks);
|
tasks
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (final Map.Entry<Long, Task> task : tasks.entrySet()) {
|
for (final Map.Entry<Long, Task> task : tasks.entrySet()) {
|
||||||
|
|
@ -175,6 +187,20 @@ public class WorkflowManager implements Serializable {
|
||||||
return workflow;
|
return workflow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AuthorizationRequired
|
||||||
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
|
public void removeWorkflowFromObject(
|
||||||
|
final Workflow workflow, final CcmObject object) {
|
||||||
|
Objects.requireNonNull(workflow, "Can't delete null.");
|
||||||
|
Objects.requireNonNull(object);
|
||||||
|
|
||||||
|
for(final Task task : workflow.getTasks()) {
|
||||||
|
taskRepo.delete(task);
|
||||||
|
}
|
||||||
|
workflowRepo.delete(workflow);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method for
|
* Helper method for
|
||||||
* {@link #createWorkflow(org.libreccm.workflow.WorkflowTemplate, org.libreccm.core.CcmObject)}
|
* {@link #createWorkflow(org.libreccm.workflow.WorkflowTemplate, org.libreccm.core.CcmObject)}
|
||||||
|
|
@ -184,15 +210,19 @@ public class WorkflowManager implements Serializable {
|
||||||
* @param template The template for the task from the workflow template.
|
* @param template The template for the task from the workflow template.
|
||||||
* @param tasks A map for storing the new tasks.
|
* @param tasks A map for storing the new tasks.
|
||||||
*/
|
*/
|
||||||
private void createTask(final Workflow workflow,
|
private void createTask(
|
||||||
|
final Workflow workflow,
|
||||||
final Task template,
|
final Task template,
|
||||||
final Map<Long, Task> tasks) {
|
final Map<Long, Task> tasks
|
||||||
|
) {
|
||||||
final Class<? extends Task> templateClass = template.getClass();
|
final Class<? extends Task> templateClass = template.getClass();
|
||||||
final Task task;
|
final Task task;
|
||||||
try {
|
try {
|
||||||
task = templateClass.getDeclaredConstructor().newInstance();
|
task = templateClass.getDeclaredConstructor().newInstance();
|
||||||
} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException ex) {
|
} catch (InstantiationException
|
||||||
|
| IllegalAccessException
|
||||||
|
| NoSuchMethodException
|
||||||
|
| InvocationTargetException ex) {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,8 +257,9 @@ public class WorkflowManager implements Serializable {
|
||||||
final LocalizedString localized = (LocalizedString) value;
|
final LocalizedString localized = (LocalizedString) value;
|
||||||
final LocalizedString copy = new LocalizedString();
|
final LocalizedString copy = new LocalizedString();
|
||||||
|
|
||||||
localized.getValues().forEach(
|
localized
|
||||||
(locale, str) -> copy.addValue(locale, str));
|
.getValues()
|
||||||
|
.forEach((locale, str) -> copy.addValue(locale, str));
|
||||||
|
|
||||||
writeMethod.invoke(task, copy);
|
writeMethod.invoke(task, copy);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -254,9 +285,11 @@ public class WorkflowManager implements Serializable {
|
||||||
.getAssignments()
|
.getAssignments()
|
||||||
.stream()
|
.stream()
|
||||||
.map(TaskAssignment::getRole)
|
.map(TaskAssignment::getRole)
|
||||||
.forEach(role -> {
|
.forEach(
|
||||||
assignableTaskManager.assignTask(assignableTask, role);
|
role -> assignableTaskManager.assignTask(
|
||||||
});
|
assignableTask, role
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,19 +303,19 @@ public class WorkflowManager implements Serializable {
|
||||||
* @param task
|
* @param task
|
||||||
* @param tasks
|
* @param tasks
|
||||||
*/
|
*/
|
||||||
private void fixTaskDependencies(final Task template,
|
private void fixTaskDependencies(
|
||||||
final Task task,
|
final Task template, final Task task, final Map<Long, Task> tasks
|
||||||
final Map<Long, Task> tasks) {
|
) {
|
||||||
|
|
||||||
if (template.getBlockedTasks() != null
|
if (template.getBlockedTasks() != null
|
||||||
&& !template.getBlockedTasks().isEmpty()) {
|
&& !template.getBlockedTasks().isEmpty()) {
|
||||||
|
|
||||||
for (final TaskDependency blocked : template.getBlockedTasks()) {
|
for (final TaskDependency blocked : template.getBlockedTasks()) {
|
||||||
|
|
||||||
final Task blockingTask = tasks
|
final Task blockingTask = tasks.get(
|
||||||
.get(blocked.getBlockingTask().getTaskId());
|
blocked.getBlockingTask().getTaskId()
|
||||||
final Task blockedTask = tasks
|
);
|
||||||
.get(blocked.getBlockedTask().getTaskId());
|
final Task blockedTask = tasks.get(
|
||||||
|
blocked.getBlockedTask().getTaskId()
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
taskManager.addDependentTask(blockingTask, blockedTask);
|
taskManager.addDependentTask(blockingTask, blockedTask);
|
||||||
} catch (CircularTaskDependencyException ex) {
|
} catch (CircularTaskDependencyException ex) {
|
||||||
|
|
@ -297,13 +330,16 @@ public class WorkflowManager implements Serializable {
|
||||||
// -> task.addDependentTask(tasks.get(dependent.getTaskId())));
|
// -> task.addDependentTask(tasks.get(dependent.getTaskId())));
|
||||||
// }
|
// }
|
||||||
for (final TaskDependency blocking : template.getBlockingTasks()) {
|
for (final TaskDependency blocking : template.getBlockingTasks()) {
|
||||||
|
final Task blockingTask = tasks.get(
|
||||||
final Task blockingTask = tasks
|
blocking.getBlockingTask().getTaskId()
|
||||||
.get(blocking.getBlockingTask().getTaskId());
|
);
|
||||||
final Task blockedTask = tasks
|
final Task blockedTask = tasks.get(
|
||||||
.get(blocking.getBlockedTask().getTaskId());
|
blocking.getBlockedTask().getTaskId()
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
taskManager.addDependentTask(blockingTask, blockedTask);
|
taskManager.addDependentTask(
|
||||||
|
blockingTask, blockedTask
|
||||||
|
);
|
||||||
} catch (CircularTaskDependencyException ex) {
|
} catch (CircularTaskDependencyException ex) {
|
||||||
throw new UnexpectedErrorException(ex);
|
throw new UnexpectedErrorException(ex);
|
||||||
}
|
}
|
||||||
|
|
@ -331,14 +367,18 @@ public class WorkflowManager implements Serializable {
|
||||||
public List<Task> findEnabledTasks(final Workflow workflow) {
|
public List<Task> findEnabledTasks(final Workflow workflow) {
|
||||||
if (workflow.getState() == WorkflowState.DELETED
|
if (workflow.getState() == WorkflowState.DELETED
|
||||||
|| workflow.getState() == WorkflowState.STOPPED) {
|
|| workflow.getState() == WorkflowState.STOPPED) {
|
||||||
LOGGER.debug(String.format("Workflow state is \"%s\". Workflow "
|
LOGGER.debug(
|
||||||
+ "has no enabled tasks.",
|
String.format(
|
||||||
workflow.getState().toString()));
|
"Workflow state is \"%s\". Workflow has no enabled tasks.",
|
||||||
|
workflow.getState().toString()
|
||||||
|
)
|
||||||
|
);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
final TypedQuery<Task> query = entityManager.createNamedQuery(
|
final TypedQuery<Task> query = entityManager.createNamedQuery(
|
||||||
"Task.findEnabledTasks", Task.class);
|
"Task.findEnabledTasks", Task.class
|
||||||
|
);
|
||||||
query.setParameter("workflow", workflow);
|
query.setParameter("workflow", workflow);
|
||||||
|
|
||||||
return Collections.unmodifiableList(query.getResultList());
|
return Collections.unmodifiableList(query.getResultList());
|
||||||
|
|
@ -357,7 +397,8 @@ public class WorkflowManager implements Serializable {
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public List<Task> findFinishedTasks(final Workflow workflow) {
|
public List<Task> findFinishedTasks(final Workflow workflow) {
|
||||||
final TypedQuery<Task> query = entityManager.createNamedQuery(
|
final TypedQuery<Task> query = entityManager.createNamedQuery(
|
||||||
"Task.findFinishedTasks", Task.class);
|
"Task.findFinishedTasks", Task.class
|
||||||
|
);
|
||||||
query.setParameter("workflow", workflow);
|
query.setParameter("workflow", workflow);
|
||||||
|
|
||||||
return Collections.unmodifiableList(query.getResultList());
|
return Collections.unmodifiableList(query.getResultList());
|
||||||
|
|
@ -376,7 +417,8 @@ public class WorkflowManager implements Serializable {
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public List<AssignableTask> findOverdueTasks(final Workflow workflow) {
|
public List<AssignableTask> findOverdueTasks(final Workflow workflow) {
|
||||||
final TypedQuery<AssignableTask> query = entityManager.createNamedQuery(
|
final TypedQuery<AssignableTask> query = entityManager.createNamedQuery(
|
||||||
"AssignableTask.findOverdueTasks", AssignableTask.class);
|
"AssignableTask.findOverdueTasks", AssignableTask.class
|
||||||
|
);
|
||||||
query.setParameter("workflow", workflow);
|
query.setParameter("workflow", workflow);
|
||||||
query.setParameter("now", new Date());
|
query.setParameter("now", new Date());
|
||||||
|
|
||||||
|
|
@ -392,7 +434,6 @@ public class WorkflowManager implements Serializable {
|
||||||
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
@RequiresPrivilege(CoreConstants.PRIVILEGE_ADMIN)
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void start(final Workflow workflow) {
|
public void start(final Workflow workflow) {
|
||||||
|
|
||||||
final WorkflowState oldState = workflow.getState();
|
final WorkflowState oldState = workflow.getState();
|
||||||
|
|
||||||
workflow.setState(WorkflowState.STARTED);
|
workflow.setState(WorkflowState.STARTED);
|
||||||
|
|
@ -414,10 +455,13 @@ public class WorkflowManager implements Serializable {
|
||||||
final Optional<User> currentUser = shiro.getUser();
|
final Optional<User> currentUser = shiro.getUser();
|
||||||
if (currentUser.isPresent()
|
if (currentUser.isPresent()
|
||||||
&& assignableTaskManager
|
&& assignableTaskManager
|
||||||
.isAssignedTo((AssignableTask) firstTask,
|
.isAssignedTo(
|
||||||
currentUser.get())) {
|
(AssignableTask) firstTask,
|
||||||
assignableTaskManager
|
currentUser.get()
|
||||||
.lockTask((AssignableTask) firstTask);
|
)) {
|
||||||
|
assignableTaskManager.lockTask(
|
||||||
|
(AssignableTask) firstTask
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -437,7 +481,8 @@ public class WorkflowManager implements Serializable {
|
||||||
private void updateState(final Workflow workflow) {
|
private void updateState(final Workflow workflow) {
|
||||||
if (workflow.getTasksState() == TaskState.ENABLED) {
|
if (workflow.getTasksState() == TaskState.ENABLED) {
|
||||||
final TypedQuery<Long> query = entityManager.createNamedQuery(
|
final TypedQuery<Long> query = entityManager.createNamedQuery(
|
||||||
"Task.countUnfinishedAndActiveTasksForWorkflow", Long.class);
|
"Task.countUnfinishedAndActiveTasksForWorkflow", Long.class
|
||||||
|
);
|
||||||
query.setParameter("workflow", workflow);
|
query.setParameter("workflow", workflow);
|
||||||
|
|
||||||
final Long result = query.getSingleResult();
|
final Long result = query.getSingleResult();
|
||||||
|
|
@ -451,7 +496,8 @@ public class WorkflowManager implements Serializable {
|
||||||
|
|
||||||
if (workflow.getTasksState() == TaskState.FINISHED) {
|
if (workflow.getTasksState() == TaskState.FINISHED) {
|
||||||
final TypedQuery<Long> query = entityManager.createNamedQuery(
|
final TypedQuery<Long> query = entityManager.createNamedQuery(
|
||||||
"Task.countUnfinishedTasksForWorkflow", Long.class);
|
"Task.countUnfinishedTasksForWorkflow", Long.class
|
||||||
|
);
|
||||||
query.setParameter("workflow", workflow);
|
query.setParameter("workflow", workflow);
|
||||||
|
|
||||||
final Long result = query.getSingleResult();
|
final Long result = query.getSingleResult();
|
||||||
|
|
@ -485,9 +531,12 @@ public class WorkflowManager implements Serializable {
|
||||||
@Transactional(Transactional.TxType.REQUIRED)
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public void finish(final Workflow workflow) {
|
public void finish(final Workflow workflow) {
|
||||||
if (workflow.getTasksState() != TaskState.ENABLED) {
|
if (workflow.getTasksState() != TaskState.ENABLED) {
|
||||||
throw new IllegalArgumentException(String.format(
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
"Workflow \"%s\" is not enabled.",
|
"Workflow \"%s\" is not enabled.",
|
||||||
workflow.getName().getValue(defaultLocale)));
|
workflow.getName().getValue(defaultLocale)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
workflow.setTasksState(TaskState.FINISHED);
|
workflow.setTasksState(TaskState.FINISHED);
|
||||||
|
|
@ -510,8 +559,10 @@ public class WorkflowManager implements Serializable {
|
||||||
|
|
||||||
switch (workflow.getTasksState()) {
|
switch (workflow.getTasksState()) {
|
||||||
case DISABLED:
|
case DISABLED:
|
||||||
LOGGER.debug("Workflow \"{}\" is disabled; enabling it.",
|
LOGGER.debug(
|
||||||
workflow.getName().getValue(defaultLocale));
|
"Workflow \"{}\" is disabled; enabling it.",
|
||||||
|
workflow.getName().getValue(defaultLocale)
|
||||||
|
);
|
||||||
workflow.setTasksState(TaskState.ENABLED);
|
workflow.setTasksState(TaskState.ENABLED);
|
||||||
workflowRepo.save(workflow);
|
workflowRepo.save(workflow);
|
||||||
break;
|
break;
|
||||||
|
|
@ -521,10 +572,12 @@ public class WorkflowManager implements Serializable {
|
||||||
workflowRepo.save(workflow);
|
workflowRepo.save(workflow);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOGGER.debug("Workflow \"{}\" has tasksState \"{}\", "
|
LOGGER.debug(
|
||||||
|
"Workflow \"{}\" has tasksState \"{}\", "
|
||||||
+ "#enable(Workflow) does nothing.",
|
+ "#enable(Workflow) does nothing.",
|
||||||
workflow.getName().getValue(defaultLocale),
|
workflow.getName().getValue(defaultLocale),
|
||||||
workflow.getTasksState());
|
workflow.getTasksState()
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,7 @@ public class WorkflowRepository extends AbstractEntityRepository<Long, Workflow>
|
||||||
* @return An {@link Optional} containing the {@link Workflow} identified by
|
* @return An {@link Optional} containing the {@link Workflow} identified by
|
||||||
* the provided UUID.
|
* the provided UUID.
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Optional<Workflow> findByUuid(final String uuid) {
|
public Optional<Workflow> findByUuid(final String uuid) {
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|
@ -102,6 +103,7 @@ public class WorkflowRepository extends AbstractEntityRepository<Long, Workflow>
|
||||||
* {@code object} if the object has a workflow. Otherwise an empty
|
* {@code object} if the object has a workflow. Otherwise an empty
|
||||||
* {@link Optional} is returned.
|
* {@link Optional} is returned.
|
||||||
*/
|
*/
|
||||||
|
@Transactional(Transactional.TxType.REQUIRED)
|
||||||
public Optional<Workflow> findWorkflowForObject(final CcmObject object) {
|
public Optional<Workflow> findWorkflowForObject(final CcmObject object) {
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue