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 3a23e01e8..955ddd7ec 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,17 +5,9 @@ */ 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; @@ -25,17 +17,11 @@ 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.lifecycle.PhaseRepository; import org.librecms.ui.contentsections.ContentSectionsUi; -import java.time.LocalDateTime; import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; -import java.time.temporal.TemporalAccessor; -import java.util.Date; import java.util.Optional; import java.util.stream.Collectors; @@ -70,6 +56,9 @@ public class DocumentController { @Inject private ContentSectionsUi sectionsUi; + @Inject + private DocumentUi documentUi; + @Inject private FolderRepository folderRepo; @@ -85,39 +74,18 @@ public class DocumentController { @Inject private GlobalizationHelper globalizationHelper; - @Inject - private IdentifierParser identifierParser; - - @Inject - private LifecycleManager lifecycleManager; - @Inject private Models models; @Inject private PermissionChecker permissionChecker; - @Inject - private PhaseRepository phaseRepository; - @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 @@ -287,7 +255,7 @@ public class DocumentController { final Optional itemResult = itemRepo .findByPath(section, documentPath); if (!itemResult.isPresent()) { - return showDocumentNotFound(section, documentPath); + return documentUi.showDocumentNotFound(section, documentPath); } final ContentItem item = itemResult.get(); if (!permissionChecker.isPermitted(ItemPrivileges.EDIT, item)) { @@ -324,7 +292,7 @@ public class DocumentController { final Optional itemResult = itemRepo .findByPath(section, documentPath); if (!itemResult.isPresent()) { - return showDocumentNotFound(section, documentPath); + return documentUi.showDocumentNotFound(section, documentPath); } final ContentItem item = itemResult.get(); if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { @@ -355,84 +323,6 @@ public class DocumentController { 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 - ) { - 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 (item.getLifecycle() != null) { - final Optional phaseResult = item - .getLifecycle() - .getPhases() - .stream() - .filter(phase -> phase.getPhaseId() == phaseId) - .findAny(); - - if (!phaseResult.isPresent()) { - models.put("section", section.getLabel()); - models.put("phaseId", phaseId); - return "org/librecms/ui/contentsection/phase-not-found.xhtml"; - } - - final Phase phase = phaseResult.get(); - final DateTimeFormatter dateTimeFormatter - = DateTimeFormatter.ISO_DATE_TIME - .withZone(ZoneId.systemDefault()); - final LocalDateTime startLocalDateTime = LocalDateTime - .parse(startDateParam, dateTimeFormatter); - phase.setStartDateTime( - Date.from( - startLocalDateTime.toInstant( - ZoneOffset.from(startLocalDateTime) - ) - ) - ); - final LocalDateTime endLocalDateTime = LocalDateTime - .parse(endDateParam, dateTimeFormatter); - phase.setEndDateTime( - Date.from( - endLocalDateTime.toInstant( - ZoneOffset.from(endLocalDateTime) - ) - ) - ); - - phaseRepository.save(phase); - } - - return String.format( - "redirect:/%s/documents/%s/@publish", - sectionIdentifier, - documentPath - ); - } - @POST @Path("/{documentPath:(.+)?}/@publish") @AuthorizationRequired @@ -453,7 +343,7 @@ public class DocumentController { final Optional itemResult = itemRepo .findByPath(section, documentPath); if (!itemResult.isPresent()) { - return showDocumentNotFound(section, documentPath); + return documentUi.showDocumentNotFound(section, documentPath); } final ContentItem item = itemResult.get(); if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { @@ -506,7 +396,7 @@ public class DocumentController { final Optional itemResult = itemRepo .findByPath(section, documentPath); if (!itemResult.isPresent()) { - return showDocumentNotFound(section, documentPath); + return documentUi.showDocumentNotFound(section, documentPath); } final ContentItem item = itemResult.get(); if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { @@ -543,7 +433,7 @@ public class DocumentController { final Optional itemResult = itemRepo .findByPath(section, documentPath); if (!itemResult.isPresent()) { - return showDocumentNotFound(section, documentPath); + return documentUi.showDocumentNotFound(section, documentPath); } final ContentItem item = itemResult.get(); if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { @@ -552,7 +442,7 @@ public class DocumentController { "documentPath", documentPath ); } - + itemManager.unpublish(item); return String.format( @@ -562,250 +452,248 @@ public class DocumentController { ); } - @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(); - } - } - +// @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 documentUi.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 documentUi.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 documentUi.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 documentUi.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 documentUi.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 ) { @@ -851,25 +739,6 @@ public class DocumentController { 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/DocumentLifecyclesController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentLifecyclesController.java new file mode 100644 index 000000000..8d19f1d85 --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentLifecyclesController.java @@ -0,0 +1,140 @@ +/* + * 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.security.AuthorizationRequired; +import org.libreccm.security.PermissionChecker; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemRepository; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.privileges.ItemPrivileges; +import org.librecms.lifecycle.Phase; +import org.librecms.lifecycle.PhaseRepository; +import org.librecms.ui.contentsections.ContentSectionsUi; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.inject.Named; +import javax.mvc.Controller; +import javax.mvc.Models; +import javax.transaction.Transactional; +import javax.ws.rs.FormParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path("/{sectionIdentifier}/documents/{documentPath:(.+)?}/@lifecycle/") +@Controller +public class DocumentLifecyclesController { + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContentSectionsUi sectionsUi; + + @Inject + private DocumentUi documentUi; + + @Inject + private Models models; + + @Inject + private PermissionChecker permissionChecker; + + @Inject + private PhaseRepository phaseRepository; + + @POST + @Path("/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 + ) { + 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 documentUi.showDocumentNotFound(section, documentPath); + } + final ContentItem item = itemResult.get(); + if (!permissionChecker.isPermitted(ItemPrivileges.PUBLISH, item)) { + return sectionsUi.showAccessDenied( + "sectionIdentifier", sectionIdentifier, + "documentPath", documentPath + ); + } + + if (item.getLifecycle() != null) { + final Optional phaseResult = item + .getLifecycle() + .getPhases() + .stream() + .filter(phase -> phase.getPhaseId() == phaseId) + .findAny(); + + if (!phaseResult.isPresent()) { + models.put("section", section.getLabel()); + models.put("phaseId", phaseId); + return "org/librecms/ui/contentsection/phase-not-found.xhtml"; + } + + final Phase phase = phaseResult.get(); + final DateTimeFormatter dateTimeFormatter + = DateTimeFormatter.ISO_DATE_TIME + .withZone(ZoneId.systemDefault()); + final LocalDateTime startLocalDateTime = LocalDateTime + .parse(startDateParam, dateTimeFormatter); + phase.setStartDateTime( + Date.from( + startLocalDateTime.toInstant( + ZoneOffset.from(startLocalDateTime) + ) + ) + ); + final LocalDateTime endLocalDateTime = LocalDateTime + .parse(endDateParam, dateTimeFormatter); + phase.setEndDateTime( + Date.from( + endLocalDateTime.toInstant( + ZoneOffset.from(endLocalDateTime) + ) + ) + ); + + phaseRepository.save(phase); + } + + return String.format( + "redirect:/%s/documents/%s/@publish", + sectionIdentifier, + documentPath + ); + } +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentUi.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentUi.java new file mode 100644 index 000000000..b380db69a --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentUi.java @@ -0,0 +1,34 @@ +/* + * 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.librecms.contentsection.ContentSection; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.mvc.Models; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +class DocumentUi { + + @Inject + private Models models; + + public 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"; + } + + + +} diff --git a/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentWorkflowController.java b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentWorkflowController.java new file mode 100644 index 000000000..3f487054e --- /dev/null +++ b/ccm-cms/src/main/java/org/librecms/ui/contentsections/documents/DocumentWorkflowController.java @@ -0,0 +1,325 @@ +/* + * 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.api.Identifier; +import org.libreccm.api.IdentifierParser; +import org.libreccm.security.AuthorizationRequired; +import org.libreccm.security.PermissionChecker; +import org.libreccm.workflow.AssignableTask; +import org.libreccm.workflow.AssignableTaskManager; +import org.libreccm.workflow.Workflow; +import org.libreccm.workflow.WorkflowManager; +import org.librecms.contentsection.ContentItem; +import org.librecms.contentsection.ContentItemRepository; +import org.librecms.contentsection.ContentSection; +import org.librecms.contentsection.privileges.ItemPrivileges; +import org.librecms.ui.contentsections.ContentSectionsUi; + +import java.util.Optional; + +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +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.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +/** + * + * @author Jens Pelzetter + */ +@RequestScoped +@Path("/{sectionIdentifier}/documents/{documentPath:(.+)?}/@workflow/") +@Controller +public class DocumentWorkflowController { + + @Inject + private AssignableTaskManager assignableTaskManager; + + @Inject + private ContentItemRepository itemRepo; + + @Inject + private ContentSectionsUi sectionsUi; + + @Inject + private DocumentUi documentUi; + + @Inject + private IdentifierParser identifierParser; + + @Inject + private PermissionChecker permissionChecker; + + @Inject + private SelectedDocumentModel selectedDocumentModel; + + @Inject + private Models models; + + @Inject + private WorkflowManager workflowManager; + + @POST + @Path("/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 documentUi.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("/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 documentUi.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("/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 documentUi.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("@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 documentUi.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("/@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 documentUi.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 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"; + } + +} diff --git a/ccm-cms/src/test/java/org/librecms/ui/contentsections/documents/LifecyclesControllerTest.java b/ccm-cms/src/test/java/org/librecms/ui/contentsections/documents/LifecyclesControllerTest.java new file mode 100644 index 000000000..5260b7fd1 --- /dev/null +++ b/ccm-cms/src/test/java/org/librecms/ui/contentsections/documents/LifecyclesControllerTest.java @@ -0,0 +1,61 @@ +/* + * 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.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author Jens Pelzetter + */ +public class LifecyclesControllerTest { + + public LifecyclesControllerTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + /** + * Test of updatePhaseDates method, of class DocumentLifecyclesController. + */ + @Test + public void testUpdatePhaseDates() { + System.out.println("updatePhaseDates"); + String sectionIdentifier = ""; + String documentPath = ""; + long phaseId = 0L; + String startDateParam = ""; + String endDateParam = ""; + DocumentLifecyclesController instance = new DocumentLifecyclesController(); + String expResult = ""; + String result + = instance.updatePhaseDates(sectionIdentifier, documentPath, phaseId, + startDateParam, endDateParam); + assertEquals(expResult, result); + // TODO review the generated test code and remove the default call to fail. + fail("The test case is a prototype."); + } + +} diff --git a/ccm-pagemodelseditor/package-lock.json b/ccm-pagemodelseditor/package-lock.json index 77ec6e01f..3fc7e615e 100644 --- a/ccm-pagemodelseditor/package-lock.json +++ b/ccm-pagemodelseditor/package-lock.json @@ -16,7 +16,7 @@ "integrity": "sha512-mOrlCEdwX3seT3n0AXNt4KNPAZZxcsABUHwBgFXOt+nvFUXkxCAO6UBJHPrDxWEa2KDMil86355fjo8jbZ+K0Q==", "dev": true, "requires": { - "@types/react": "16.4.11" + "@types/react": "*" } }, "@types/react": { @@ -25,8 +25,8 @@ "integrity": "sha512-1DQnmwO8u8N3ucvRX2ZLDEjQ2VctkAvL/rpbm2ev4uaZA0z4ysU+I0tk+K8ZLblC6p7MCgFyF+cQlSNIPUHzeQ==", "dev": true, "requires": { - "@types/prop-types": "15.5.5", - "csstype": "2.5.6" + "@types/prop-types": "*", + "csstype": "^2.2.0" } }, "@types/react-dom": { @@ -35,8 +35,8 @@ "integrity": "sha512-vaq4vMaJOaNgFff1t3LnHYr6vRa09vRspMkmLdXtFZmO1fwDI2snP+dpOkwrtlU8UC8qsqemCu4RmVM2OLq/fA==", "dev": true, "requires": { - "@types/node": "10.7.1", - "@types/react": "16.4.11" + "@types/node": "*", + "@types/react": "*" } }, "@types/react-modal": { @@ -45,7 +45,7 @@ "integrity": "sha512-EhRC3xjsehC0e8OKz/NmEyjc/ggHxVj4rNu8p/AfSohbn5NHY0V58fj0OZgQPZzXY42v+rLxiO7PL1uOeBfimg==", "dev": true, "requires": { - "@types/react": "16.4.11" + "@types/react": "*" } }, "ansi-regex": { @@ -66,7 +66,7 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, "asap": { @@ -80,9 +80,9 @@ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" }, "dependencies": { "chalk": { @@ -91,11 +91,11 @@ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } } } @@ -112,7 +112,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -128,9 +128,9 @@ "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "dependencies": { "ansi-styles": { @@ -139,7 +139,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.2" + "color-convert": "^1.9.0" } }, "supports-color": { @@ -148,7 +148,7 @@ "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -202,7 +202,7 @@ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { - "iconv-lite": "0.4.23" + "iconv-lite": "~0.4.13" } }, "escape-string-regexp": { @@ -233,13 +233,13 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", "requires": { - "core-js": "1.2.7", - "isomorphic-fetch": "2.2.1", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "promise": "7.3.1", - "setimmediate": "1.0.5", - "ua-parser-js": "0.7.18" + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.9" } }, "fs.realpath": { @@ -254,12 +254,12 @@ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "has-ansi": { @@ -268,7 +268,7 @@ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "has-flag": { @@ -287,7 +287,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "inflight": { @@ -296,8 +296,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -311,7 +311,7 @@ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" } }, "is-stream": { @@ -324,8 +324,8 @@ "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", "requires": { - "node-fetch": "1.7.3", - "whatwg-fetch": "2.0.4" + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" } }, "js-tokens": { @@ -339,8 +339,8 @@ "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, "lodash": { @@ -358,7 +358,7 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "requires": { - "js-tokens": "3.0.2" + "js-tokens": "^3.0.0" } }, "minimatch": { @@ -367,7 +367,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "node-fetch": { @@ -375,8 +375,8 @@ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", "requires": { - "encoding": "0.1.12", - "is-stream": "1.1.0" + "encoding": "^0.1.11", + "is-stream": "^1.0.1" } }, "object-assign": { @@ -390,7 +390,7 @@ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "path-is-absolute": { @@ -410,7 +410,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "requires": { - "asap": "2.0.6" + "asap": "~2.0.3" } }, "prop-types": { @@ -418,9 +418,9 @@ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.1.tgz", "integrity": "sha512-4ec7bY1Y66LymSUOH/zARVYObB23AT2h8cf6e/O6ZALB/N0sqZFEx7rq6EYPX2MkOdKORuooI/H5k9TlR4q7kQ==", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" } }, "react": { @@ -428,10 +428,10 @@ "resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz", "integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "prop-types": "15.6.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0" } }, "react-dom": { @@ -439,10 +439,10 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz", "integrity": "sha512-Usl73nQqzvmJN+89r97zmeUpQDKDlh58eX6Hbs/ERdDHzeBzWy+ENk7fsGQ+5KxArV1iOFPT46/VneklK9zoWw==", "requires": { - "fbjs": "0.8.16", - "loose-envify": "1.3.1", - "object-assign": "4.1.1", - "prop-types": "15.6.1" + "fbjs": "^0.8.16", + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.0" } }, "react-lifecycles-compat": { @@ -455,10 +455,10 @@ "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.5.1.tgz", "integrity": "sha512-GxL7ycOgKC+p641cR+V1bw5dC1faL2N86/AJlzbMVmvt1totoylgkJmn9zvLuHeuarGbB7CLfHMGpeRowaj2jQ==", "requires": { - "exenv": "1.2.2", - "prop-types": "15.6.1", - "react-lifecycles-compat": "3.0.4", - "warning": "3.0.0" + "exenv": "^1.2.0", + "prop-types": "^15.5.10", + "react-lifecycles-compat": "^3.0.0", + "warning": "^3.0.0" } }, "react-redux": { @@ -466,12 +466,12 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.7.tgz", "integrity": "sha512-5VI8EV5hdgNgyjfmWzBbdrqUkrVRKlyTKk1sGH3jzM2M2Mhj/seQgPXaz6gVAj2lz/nz688AdTqMO18Lr24Zhg==", "requires": { - "hoist-non-react-statics": "2.5.5", - "invariant": "2.2.4", - "lodash": "4.17.10", - "lodash-es": "4.17.10", - "loose-envify": "1.3.1", - "prop-types": "15.6.1" + "hoist-non-react-statics": "^2.5.0", + "invariant": "^2.0.0", + "lodash": "^4.17.5", + "lodash-es": "^4.17.5", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.0" } }, "redux": { @@ -479,8 +479,8 @@ "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.0.tgz", "integrity": "sha512-NnnHF0h0WVE/hXyrB6OlX67LYRuaf/rJcbWvnHHEPCF/Xa/AZpwhs/20WyqzQae5x4SD2F9nPObgBh2rxAgLiA==", "requires": { - "loose-envify": "1.3.1", - "symbol-observable": "1.2.0" + "loose-envify": "^1.1.0", + "symbol-observable": "^1.2.0" } }, "resolve": { @@ -489,7 +489,7 @@ "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "1.0.6" + "path-parse": "^1.0.5" } }, "safer-buffer": { @@ -520,7 +520,7 @@ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "supports-color": { @@ -546,18 +546,18 @@ "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", "dev": true, "requires": { - "babel-code-frame": "6.26.0", - "builtin-modules": "1.1.1", - "chalk": "2.4.1", - "commander": "2.17.1", - "diff": "3.5.0", - "glob": "7.1.2", - "js-yaml": "3.12.0", - "minimatch": "3.0.4", - "resolve": "1.8.1", - "semver": "5.5.0", - "tslib": "1.9.3", - "tsutils": "2.29.0" + "babel-code-frame": "^6.22.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^3.2.0", + "glob": "^7.1.1", + "js-yaml": "^3.7.0", + "minimatch": "^3.0.4", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.27.2" } }, "tsutils": { @@ -566,7 +566,7 @@ "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, "requires": { - "tslib": "1.9.3" + "tslib": "^1.8.1" } }, "typescript": { @@ -585,7 +585,7 @@ "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", "requires": { - "loose-envify": "1.3.1" + "loose-envify": "^1.0.0" } }, "whatwg-fetch": {