From c7a8756c9c0a92ff8bceb6b21bf401f2e7e7438c Mon Sep 17 00:00:00 2001 From: Jens Pelzetter Date: Mon, 15 Mar 2021 21:09:42 +0100 Subject: [PATCH] Controller methods for workflow and lifecycle management of content items/documents --- .../documents/DocumentController.java | 567 ++++++++++++++++++ .../documents/LifecycleListEntry.java | 46 ++ .../documents/PhaseListEntry.java | 84 +++ .../documents/PublishStepModel.java | 50 ++ .../documents/SelectedDocumentModel.java | 109 ++++ .../documents/TaskListEntry.java | 66 ++ 6 files changed, 922 insertions(+) create mode 100644 ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/LifecycleListEntry.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PhaseListEntry.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStepModel.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/SelectedDocumentModel.java create mode 100644 ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/TaskListEntry.java diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java index 7be123e9c..ac31ab8d6 100644 --- a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentController.java @@ -5,24 +5,47 @@ */ package org.librecms.ui.contentsections.documents; +import org.libreccm.api.Identifier; +import org.libreccm.api.IdentifierParser; +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.PermissionChecker; +import org.libreccm.workflow.AssignableTask; +import org.libreccm.workflow.AssignableTaskManager; +import org.libreccm.workflow.TaskManager; +import org.libreccm.workflow.Workflow; +import org.libreccm.workflow.WorkflowManager; +import org.libreccm.workflow.WorkflowRepository; import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemManager; import org.librecms.contentsection.ContentItemRepository; import org.librecms.contentsection.ContentSection; import org.librecms.contentsection.Folder; import org.librecms.contentsection.FolderRepository; import org.librecms.contentsection.FolderType; +import org.librecms.contentsection.privileges.ItemPrivileges; +import org.librecms.lifecycle.LifecycleDefinition; +import org.librecms.lifecycle.LifecycleManager; +import org.librecms.lifecycle.Phase; import org.librecms.ui.contentsections.ContentSectionsUi; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Optional; +import java.util.stream.Collectors; import javax.enterprise.context.RequestScoped; import javax.enterprise.inject.Instance; import javax.enterprise.util.AnnotationLiteral; import javax.inject.Inject; +import javax.inject.Named; import javax.mvc.Controller; import javax.mvc.Models; import javax.transaction.Transactional; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.FormParam; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; @@ -33,8 +56,12 @@ import javax.ws.rs.PathParam; @RequestScoped @Path("/{sectionIdentifier}/documents") @Controller +@Named("CmsDocumentController") public class DocumentController { + @Inject + private ContentItemManager itemManager; + @Inject private ContentSectionsUi sectionsUi; @@ -50,11 +77,42 @@ public class DocumentController { @Inject private Instance> createSteps; + @Inject + private GlobalizationHelper globalizationHelper; + + @Inject + private IdentifierParser identifierParser; + + @Inject + private LifecycleManager lifecycleManager; + @Inject private Models models; + @Inject + private PermissionChecker permissionChecker; + + @Inject + private PublishStepModel publishStepModel; + + @Inject + private SelectedDocumentModel selectedDocumentModel; + + @Inject + private WorkflowManager workflowManager; + + @Inject + private AssignableTaskManager assignableTaskManager; + + @Inject + private TaskManager taskManager; + + @Inject + private WorkflowRepository workflowRepository; + @GET @Path("/") + @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public String redirectToDocumentFolders( @PathParam("sectionIdentifider") final String sectionIdentifier @@ -66,6 +124,7 @@ public class DocumentController { } @Path("/@create/{documentType}") + @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public MvcDocumentCreateStep createDocument( @PathParam("sectionIdentifider") final String sectionIdentifier, @@ -75,6 +134,7 @@ public class DocumentController { } @Path("/{folderPath:(.+)?}/@create/{documentType}") + @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) @SuppressWarnings("unchecked") public MvcDocumentCreateStep createDocument( @@ -146,6 +206,7 @@ public class DocumentController { } @Path("/{documentPath:(.+)?}/@authoringsteps/{authoringStep}") + @AuthorizationRequired @Transactional(Transactional.TxType.REQUIRED) public MvcAuthoringStep editDocument( @PathParam("sectionIdentifider") final String sectionIdentifier, @@ -192,12 +253,518 @@ public class DocumentController { return new UnsupportedDocumentType(); } + selectedDocumentModel.setContentItem(item); + authoringStep.setContentSection(section); authoringStep.setContentItem(item); return authoringStep; } + @POST + @Path("/{documentPath:(.+)?}/@history") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String showHistory( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + if (!permissionChecker.isPermitted(ItemPrivileges.EDIT, item)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier, + "documentPath", documentPath + ); + } + selectedDocumentModel.setContentItem(item); + + models.put( + "revisions", + itemRepo.retrieveRevisions(item, item.getObjectId()) + ); + + return "org/librecms/ui/contentsection/documents/history.xhtml"; + } + + @GET + @Path("/{documentPath:(.+)?}/@publish") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String showPublishStep( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier, + "documentPath", documentPath + ); + } + + publishStepModel.setAvailableLifecycles( + section + .getLifecycleDefinitions() + .stream() + .map(this::buildLifecycleListEntry) + .collect(Collectors.toList()) + ); + if (item.getLifecycle() != null) { + publishStepModel.setPhases( + item + .getLifecycle() + .getPhases() + .stream() + .map(this::buildPhaseListEntry) + .collect(Collectors.toList()) + ); + } + + return "org/librecms/ui/contentsection/documents/publish.xhtml"; + } + + @POST + @Path("/{documentPath:(.+)?}/@lifecycle/phases/{phaseId}") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String updatePhaseDates( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath, + @PathParam("phaseId") final long phaseId, + @FormParam("startDate") final String startDateParam, + @FormParam("endDate") final String endDateParam + ) { + throw new UnsupportedOperationException("ToDo"); + } + + @POST + @Path("/{documentPath:(.+)?}/@publish") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String publish( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath, + @FormParam("selectedLifecycleUuid") @DefaultValue("") + final String selectedLifecycleUuid + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier, + "documentPath", documentPath + ); + } + + if (selectedLifecycleUuid.isEmpty()) { + itemManager.publish(item); + } else { + final Optional result = section + .getLifecycleDefinitions() + .stream() + .filter( + definition -> definition.getUuid().equals( + selectedLifecycleUuid + ) + ).findAny(); + if (!result.isPresent()) { + models.put("section", section.getLabel()); + models.put("lifecycleDefUuid", selectedLifecycleUuid); + return "org/librecms/ui/contentsection/lifecycle-def-not-found.xhtml"; + } + } + + return String.format( + "redirect:/%s/documents/%s/@publish", + sectionIdentifier, + documentPath + ); + } + + @POST + @Path("/{documentPath:(.+)?}/@republish") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String republish( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier, + "documentPath", documentPath + ); + } + + itemManager.publish(item); + + return String.format( + "redirect:/%s/documents/%s/@publish", + sectionIdentifier, + documentPath + ); + } + + public String unpublish() { + throw new UnsupportedOperationException("ToDo"); + } + + @POST + @Path("/{documentPath:(.+)?}/@workflow/tasks/${taskIdentifier}/@lock") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String lockTask( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath, + @PathParam("taskIdentifier") final String taskIdentifier, + @FormParam("returnUrl") final String returnUrl + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + selectedDocumentModel.setContentItem(item); + + final Optional taskResult = findTask( + item, taskIdentifier + ); + if (!taskResult.isPresent()) { + return showTaskNotFound(section, documentPath, taskIdentifier); + } + + final AssignableTask task = taskResult.get(); + assignableTaskManager.lockTask(task); + + return String.format("redirect:%s", returnUrl); + } + + @POST + @Path("/{documentPath:(.+)?}/@workflow/tasks/${taskIdentifier}/@unlock") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String unlockTask( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath, + @PathParam("taskIdentifier") final String taskIdentifier, + @FormParam("returnUrl") final String returnUrl + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + selectedDocumentModel.setContentItem(item); + + final Optional taskResult = findTask( + item, taskIdentifier + ); + if (!taskResult.isPresent()) { + return showTaskNotFound(section, documentPath, taskIdentifier); + } + + final AssignableTask task = taskResult.get(); + assignableTaskManager.unlockTask(task); + + return String.format("redirect:%s", returnUrl); + } + + @POST + @Path("/{documentPath:(.+)?}/@workflow/tasks/${taskIdentifier}/@finish") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String finishTask( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath, + @PathParam("taskIdentifier") final String taskIdentifier, + @FormParam("comment") @DefaultValue("") final String comment, + @FormParam("returnUrl") final String returnUrl + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + selectedDocumentModel.setContentItem(item); + + final Optional taskResult = findTask( + item, taskIdentifier + ); + if (!taskResult.isPresent()) { + return showTaskNotFound(section, documentPath, taskIdentifier); + } + + final AssignableTask task = taskResult.get(); + if (comment.isEmpty()) { + assignableTaskManager.finish(task); + } else { + assignableTaskManager.finish(task, comment); + } + + return String.format("redirect:%s", returnUrl); + } + + @POST + @Path( + "/{documentPath:(.+)?}/@workflow/@applyAlternative/{workflowIdentifier}") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String applyAlternateWorkflow( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath, + @FormParam("newWorkflowUuid") final String newWorkflowUuid, + @FormParam("returnUrl") final String returnUrl + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + selectedDocumentModel.setContentItem(item); + + if (!permissionChecker.isPermitted( + ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier, + "documentPath", documentPath + ); + } + + final Optional workflowResult = section + .getWorkflowTemplates() + .stream() + .filter(template -> template.getUuid().equals(newWorkflowUuid)) + .findAny(); + if (!workflowResult.isPresent()) { + models.put("section", section.getLabel()); + models.put("workflowUuid", newWorkflowUuid); + return "org/librecms/ui/contentsection/workflow-not-found.xhtml"; + } + + workflowManager.createWorkflow(workflowResult.get(), item); + return String.format("redirect:%s", returnUrl); + } + + @POST + @Path("/{documentPath:(.+)?}/@workflow/@restart") + @AuthorizationRequired + @Transactional(Transactional.TxType.REQUIRED) + public String restartWorkflow( + @PathParam("sectionIdentifider") final String sectionIdentifier, + @PathParam("documentPath") final String documentPath, + @FormParam("returnUrl") final String returnUrl + ) { + final Optional sectionResult = sectionsUi + .findContentSection(sectionIdentifier); + if (!sectionResult.isPresent()) { + return sectionsUi.showContentSectionNotFound(sectionIdentifier); + } + final ContentSection section = sectionResult.get(); + + final Optional itemResult = itemRepo + .findByPath(section, documentPath); + if (!itemResult.isPresent()) { + return showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + selectedDocumentModel.setContentItem(item); + + if (!permissionChecker.isPermitted( + ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier, + "documentPath", documentPath + ); + } + + if (item.getWorkflow() != null) { + workflowManager.start(item.getWorkflow()); + } + + return String.format("redirect:%s", returnUrl); + } + + private Optional findTask( + final ContentItem item, + final String taskIdentifier + ) { + final Workflow workflow = item.getWorkflow(); + if (workflow == null) { + return Optional.empty(); + } + + final Identifier identifier = identifierParser.parseIdentifier( + taskIdentifier + ); + switch (identifier.getType()) { + case ID: + return workflow + .getTasks() + .stream() + .filter(task -> task instanceof AssignableTask) + .map(task -> (AssignableTask) task) + .filter( + task -> task.getTaskId() == Long + .parseLong(identifier.getIdentifier()) + ).findAny(); + default: + return workflow + .getTasks() + .stream() + .filter(task -> task instanceof AssignableTask) + .map(task -> (AssignableTask) task) + .filter( + task -> task.getUuid().equals( + identifier.getIdentifier() + ) + ).findAny(); + } + } + + private LifecycleListEntry buildLifecycleListEntry( + final LifecycleDefinition definition + ) { + final LifecycleListEntry entry = new LifecycleListEntry(); + entry.setDescription( + globalizationHelper.getValueFromLocalizedString( + definition.getDescription() + ) + ); + entry.setLabel( + globalizationHelper.getValueFromLocalizedString( + definition.getLabel() + ) + ); + entry.setUuid(definition.getUuid()); + return entry; + } + + private PhaseListEntry buildPhaseListEntry(final Phase phase) { + final DateTimeFormatter dateTimeFormatter + = DateTimeFormatter.ISO_DATE_TIME + .withZone(ZoneId.systemDefault()); + final PhaseListEntry entry = new PhaseListEntry(); + entry.setDescription( + globalizationHelper.getValueFromLocalizedString( + phase.getDefinition().getDescription() + ) + ); + entry.setEndDateTime( + dateTimeFormatter.format(phase.getEndDateTime().toInstant()) + ); + entry.setFinished(phase.isFinished()); + entry.setLabel( + globalizationHelper.getValueFromLocalizedString( + phase.getDefinition().getLabel() + ) + ); + entry.setPhaseId(phase.getPhaseId()); + entry.setStartDateTime( + dateTimeFormatter.format(phase.getStartDateTime().toInstant()) + ); + entry.setStarted(phase.isStarted()); + return entry; + } + + private String showDocumentNotFound( + final ContentSection section, final String documentPath + ) { + models.put("section", section.getLabel()); + models.put("documentPath", documentPath); + return "org/librecms/ui/contentsection/document-not-found.xhtml"; + } + + private String showTaskNotFound( + final ContentSection section, + final String documentPath, + final String taskIdentifier + ) { + models.put("section", section.getLabel()); + models.put("documentPath", documentPath); + models.put("taskIdentifier", taskIdentifier); + return "org/librecms/ui/contentsection/task-not-found.xhtml"; + } + private static class CreateDocumentOfTypeLiteral extends AnnotationLiteral implements CreatesDocumentOfType { diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/LifecycleListEntry.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/LifecycleListEntry.java new file mode 100644 index 000000000..38b57a16d --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/LifecycleListEntry.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.librecms.ui.contentsections.documents; + +/** + * + * @author Jens Pelzetter + */ +public class LifecycleListEntry { + + private String uuid; + + private String label; + + private String description; + + public String getLabel() { + return label; + } + + public void setLabel(final String label) { + this.label = label; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(final String uuid) { + this.uuid = uuid; + } + + + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PhaseListEntry.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PhaseListEntry.java new file mode 100644 index 000000000..abe09a7d5 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PhaseListEntry.java @@ -0,0 +1,84 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.librecms.ui.contentsections.documents; + +/** + * + * @author Jens Pelzetter + */ +public class PhaseListEntry { + + private long phaseId; + + private String label; + + private String description; + + private boolean started; + + private boolean finished; + + private String startDateTime; + + private String endDateTime; + + public String getLabel() { + return label; + } + + public void setLabel(final String label) { + this.label = label; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + + public boolean isStarted() { + return started; + } + + public void setStarted(final boolean started) { + this.started = started; + } + + public boolean isFinished() { + return finished; + } + + public void setFinished(final boolean finished) { + this.finished = finished; + } + + public String getStartDateTime() { + return startDateTime; + } + + public void setStartDateTime(final String startDateTime) { + this.startDateTime = startDateTime; + } + + public String getEndDateTime() { + return endDateTime; + } + + public void setEndDateTime(final String endDateTime) { + this.endDateTime = endDateTime; + } + + public long getPhaseId() { + return phaseId; + } + + public void setPhaseId(long phaseId) { + this.phaseId = phaseId; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStepModel.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStepModel.java new file mode 100644 index 000000000..7d533f6eb --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/PublishStepModel.java @@ -0,0 +1,50 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.librecms.ui.contentsections.documents; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("CmsDocumentPublishStepModel") +public class PublishStepModel { + + private List availableListcycles; + + private List phases; + + public PublishStepModel() { + availableListcycles = new ArrayList<>(); + phases = new ArrayList<>(); + } + + public List getAvailableListcycles() { + return Collections.unmodifiableList(availableListcycles); + } + + public void setAvailableLifecycles( + final List availableListcycles + ) { + this.availableListcycles = new ArrayList<>(availableListcycles); + } + + public List getPhases() { + return Collections.unmodifiableList(phases); + } + + public void setPhases(final List phases) { + this.phases = new ArrayList<>(phases); + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/SelectedDocumentModel.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/SelectedDocumentModel.java new file mode 100644 index 000000000..0783967f8 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/SelectedDocumentModel.java @@ -0,0 +1,109 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.librecms.ui.contentsections.documents; + +import org.libreccm.l10n.GlobalizationHelper; +import org.libreccm.security.PermissionChecker; +import org.libreccm.security.Shiro; +import org.libreccm.workflow.AssignableTask; +import org.libreccm.workflow.AssignableTaskManager; +import org.libreccm.workflow.TaskState; +import org.libreccm.workflow.Workflow; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.privileges.ItemPrivileges; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.inject.Named; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Named("CmsSelectedDocumentModel") +public class SelectedDocumentModel { + + @Inject + private AssignableTaskManager taskManager; + + @Inject + private GlobalizationHelper globalizationHelper; + + @Inject + private PermissionChecker permissionChecker; + + @Inject + private Shiro shiro; + + private ContentItem item; + + private Workflow workflow; + + private TaskListEntry currentTask; + + private List allTasks; + + void setContentItem(final ContentItem item) { + this.item = Objects.requireNonNull(item); + workflow = item.getWorkflow(); + allTasks = workflow + .getTasks() + .stream() + .filter(task -> task instanceof AssignableTask) + .map(task -> (AssignableTask) task) + .map(this::buildTaskListEntry) + .collect(Collectors.toList()); + + currentTask = allTasks + .stream() + .filter(task -> task.getTaskState() == TaskState.ENABLED) + .findFirst() + .orElse(null); + if (currentTask != null) { + currentTask.setCurrentTask(true); + } + } + + public TaskListEntry getCurrentTask() { + return currentTask; + } + + public boolean getCanChangeWorkflow() { + return permissionChecker.isPermitted( + ItemPrivileges.APPLY_ALTERNATE_WORKFLOW, item + ); + } + + private TaskListEntry buildTaskListEntry(final AssignableTask task) { + final TaskListEntry entry = new TaskListEntry(); + entry.setLabel( + globalizationHelper.getValueFromLocalizedString( + task.getLabel() + ) + ); + entry.setDescription( + globalizationHelper.getValueFromLocalizedString( + task.getDescription() + ) + ); + entry.setTaskState(task.getTaskState()); + entry.setAssignedToCurrentUser( + shiro + .getUser() + .map(user -> taskManager.isAssignedTo(task, user)) + .orElse(false) + ); + + return entry; + } + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/TaskListEntry.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/TaskListEntry.java new file mode 100644 index 000000000..be6e8da85 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/TaskListEntry.java @@ -0,0 +1,66 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.librecms.ui.contentsections.documents; + +import org.libreccm.workflow.TaskState; + +/** + * + * @author Jens Pelzetter + */ +public class TaskListEntry { + + private String label; + + private String description; + + private TaskState taskState; + + private boolean currentTask; + + private boolean assignedToCurrentUser; + + public String getLabel() { + return label; + } + + public void setLabel(final String label) { + this.label = label; + } + + public TaskState getTaskState() { + return taskState; + } + + public void setTaskState(TaskState taskState) { + this.taskState = taskState; + } + + public boolean isCurrentTask() { + return currentTask; + } + + public void setCurrentTask(final boolean currentTask) { + this.currentTask = currentTask; + } + + public boolean isAssignedToCurrentUser() { + return assignedToCurrentUser; + } + + public void setAssignedToCurrentUser(final boolean assignedToCurrentUser) { + this.assignedToCurrentUser = assignedToCurrentUser; + } + + public String getDescription() { + return description; + } + + public void setDescription(final String description) { + this.description = description; + } + +}