public IHttpActionResult ResubmitWorkflowTask(TaskData model) { WorkflowInstancePoco instance = GetInstance(model.InstanceGuid); try { WorkflowProcess process = GetProcess(instance.Type); IUser currentUser = _utility.GetCurrentUser(); instance = process.ResubmitWorkflow( instance, currentUser.Id, model.Comment ); Log.Info($"{instance.TypeDescription} request for {instance.Node.Name} [{instance.NodeId}] was resubmitted by {currentUser.Name}"); return(Json(new { message = $"Changes resubmitted successfully. Page will be {instance.TypeDescriptionPastTense.ToLower()} following workflow completion.", status = 200 }, ViewHelpers.CamelCase)); } catch (Exception ex) { string msg = $"An error occurred processing the approval on {instance.Node.Name} [{instance.NodeId}]"; Log.Error(msg, ex); return(Content(HttpStatusCode.InternalServerError, ViewHelpers.ApiException(ex, msg))); } }
public IHttpActionResult RejectWorkflowTask(TaskData model) { WorkflowInstancePoco instance = GetInstance(model.InstanceGuid); try { WorkflowProcess process = GetProcess(instance.Type); IUser currentUser = _utility.GetCurrentUser(); instance = process.ActionWorkflow( instance, WorkflowAction.Reject, currentUser.Id, model.Comment ); Log.Info($"{instance.TypeDescription} request for {instance.Node.Name} [{instance.NodeId}] was rejected by {currentUser.Name}"); _hubContext.Clients.All.TaskRejected( _tasksService.ConvertToWorkflowTaskList(instance.TaskInstances.ToList(), instance: instance)); return(Json(new { message = instance.TypeDescription + " request has been rejected.", status = 200 }, ViewHelpers.CamelCase)); } catch (Exception ex) { string msg = $"An error occurred rejecting the workflow on {instance.Node.Name} [{instance.NodeId}]"; Log.Error(msg, ex); return(Content(HttpStatusCode.InternalServerError, ViewHelpers.ApiException(ex, msg))); } }
public void Can_Get_Populated_Instance(int taskCount, int lastGroupId) { IContent node = Scaffold.Node(ApplicationContext.Current.Services.ContentService); Guid guid = Guid.NewGuid(); WorkflowInstancePoco instance = Scaffold.Instance(guid, (int)WorkflowType.Publish, node.Id); _service.InsertInstance(instance); for (var i = 1; i <= taskCount; i += 1) { _tasksService.InsertTask(Scaffold.Task(guid, DateTime.Now, i < taskCount ? i : lastGroupId, i, i < taskCount ? 1 : 3)); } // this has groups, tasks, everything. Or it should. WorkflowInstancePoco populatedInstance = _service.GetPopulatedInstance(guid); Assert.Equal(taskCount, populatedInstance.TaskInstances.Count); Assert.Equal(0, populatedInstance.TotalSteps); // this shouldn't be set yet Assert.Equal(lastGroupId, populatedInstance.TaskInstances.First().UserGroup.GroupId); // tasks are descending by id Assert.Equal(WorkflowStatus.PendingApproval, populatedInstance.WorkflowStatus); }
/// <summary> /// Builds workflow instance details markup. /// </summary> /// <returns>HTML tr inner html definition</returns> public static string BuildProcessSummary(this WorkflowInstancePoco instance) { string result = $"<b>Workflow history</b><br/><br/>{instance.WorkflowType.Description(instance.ScheduledDate)} requested by {instance.AuthorUser.Name} on {instance.CreatedDate:d MMM yyyy}<br/>"; if (instance.AuthorComment.HasValue()) { result += $" Change description: <i>{instance.AuthorComment}</i><br/>"; } var statusColor = instance.WorkflowStatus.In(WorkflowStatus.Errored, WorkflowStatus.Rejected, WorkflowStatus.Cancelled) ? "red" : instance.WorkflowStatus.In(WorkflowStatus.PendingApproval, WorkflowStatus.Resubmitted) ? "orange" : "green"; result += $"<br/>Current status: <span style='color: {statusColor}'>{instance.StatusName}</span><br/><br/>"; bool first = true; foreach (WorkflowTaskPoco taskInstance in instance.TaskInstances.OrderBy(t => t.ApprovalStep).ThenByDescending(t => t.Id)) { if (first) { result += taskInstance.BuildTaskSummary(first); first = false; } else { result += taskInstance.BuildTaskSummary(first); } } return($"{result}<br/>"); }
public IHttpActionResult CancelWorkflowTask(TaskData model) { WorkflowInstancePoco instance = GetInstance(model.InstanceGuid); try { WorkflowProcess process = GetProcess(instance.Type); IUser currentUser = _utility.GetCurrentUser(); instance = process.CancelWorkflow( instance, currentUser.Id, model.Comment ); Log.Info($"{instance.TypeDescription} request for {instance.Node.Name} [{instance.NodeId}] was cancelled by {currentUser.Name}"); return(Json(new { status = 200, message = instance.TypeDescription + " workflow cancelled" }, ViewHelpers.CamelCase)); } catch (Exception ex) { string msg = $"An error occurred cancelling the workflow on {instance.Node.Name} [{instance.NodeId}]"; Log.Error(msg, ex); return(Content(HttpStatusCode.InternalServerError, ViewHelpers.ApiException(ex, msg))); } }
public IHttpActionResult ResubmitWorkflowTask(TaskData model) { WorkflowInstancePoco instance = GetInstance(model.InstanceGuid); try { WorkflowApprovalProcess process = GetProcess(instance.Type); instance = process.ResubmitWorkflow( instance, Utility.GetCurrentUser().Id, model.Comment ); return(Json(new { message = "Changes resubmitted successfully. Page will be " + instance.TypeDescriptionPastTense.ToLower() + " following workflow completion.", status = 200 }, ViewHelpers.CamelCase)); } catch (Exception ex) { string msg = "An error occurred processing the approval: " + ex.Message + ex.StackTrace; Log.Error(msg + " for workflow " + instance.Id, ex); return(Json(new { message = msg, status = 500 }, ViewHelpers.CamelCase)); } }
/// <summary> /// Maps Users to the UserGroup property of a WorkflowTaskInstance /// </summary> /// <param name="task"></param> /// <param name="instance"></param> /// <param name="userGroup"></param> /// <returns></returns> public WorkflowInstancePoco MapIt(WorkflowInstancePoco instance, WorkflowTaskPoco task, UserGroupPoco userGroup) { if (instance == null) { return(_current); } if (userGroup.GroupId == task.GroupId) { task.UserGroup = userGroup; } if (_current != null && _current.Guid == instance.Guid) { if (_current.TaskInstances.All(t => t.ApprovalStep != task.ApprovalStep)) { _current.TaskInstances.Add(task); } return(null); } WorkflowInstancePoco prev = _current; _current = instance; _current.TaskInstances.Add(task); return(prev); }
/// <summary> /// Maps Users to the UserGroup property of a WorkflowTaskInstance /// </summary> /// <param name="wtip"></param> /// <param name="wip"></param> /// <param name="ugp"></param> /// <returns></returns> public WorkflowInstancePoco MapIt(WorkflowInstancePoco wip, WorkflowTaskInstancePoco wtip, UserGroupPoco ugp) { if (wip == null) { return(Current); } if (ugp.GroupId == wtip.GroupId) { wtip.UserGroup = ugp; } if (Current != null && Current.Guid == wip.Guid) { if (Current.TaskInstances.All(t => t.ApprovalStep != wtip.ApprovalStep)) { Current.TaskInstances.Add(wtip); } return(null); } var prev = Current; Current = wip; Current.TaskInstances.Add(wtip); return(prev); }
public IHttpActionResult ApproveWorkflowTask(TaskData model) { WorkflowInstancePoco instance = GetInstance(model.InstanceGuid); try { WorkflowProcess process = GetProcess(instance.Type); IUser currentUser = _utility.GetCurrentUser(); instance = process.ActionWorkflow( instance, WorkflowAction.Approve, currentUser.Id, model.Comment ); string msg = string.Empty; string logMsg = string.Empty; switch (instance.WorkflowStatus) { case WorkflowStatus.PendingApproval: msg = $"Approval completed successfully. Page will be {instance.TypeDescriptionPastTense.ToLower()} following workflow completion."; logMsg = $"Workflow {instance.TypeDescription} task on {instance.Node.Name} [{instance.NodeId}] approved by {currentUser.Name}"; break; case WorkflowStatus.Approved: msg = "Workflow approved successfully."; logMsg = $"Workflow approved by {currentUser.Name} on {instance.Node.Name} [{instance.NodeId}]"; if (instance.ScheduledDate.HasValue) { string scheduled = $" Page scheduled for {instance.TypeDescription} at {instance.ScheduledDate.Value.ToString("dd MMM YYYY", CultureInfo.CurrentCulture)}"; msg += scheduled; logMsg += scheduled; } else { msg += $" Page has been {instance.TypeDescriptionPastTense.ToLower()}"; } break; } Log.Info(logMsg); return(Json(new { message = msg, status = 200 }, ViewHelpers.CamelCase)); } catch (Exception ex) { string msg = $"An error occurred processing the approval on {instance.Node.Name} [{instance.Node.Id}]"; Log.Error(msg, ex); return(Content(HttpStatusCode.InternalServerError, ViewHelpers.ApiException(ex, msg))); } }
public IHttpActionResult InitiateWorkflow(InitiateWorkflowModel model) { try { WorkflowProcess process; if (model.Publish) { process = new DocumentPublishProcess(); } else { process = new DocumentUnpublishProcess(); } IUser currentUser = _utility.GetCurrentUser(); WorkflowInstancePoco instance = process.InitiateWorkflow(int.Parse(model.NodeId), currentUser.Id, model.Comment); string msg = string.Empty; switch (instance.WorkflowStatus) { case WorkflowStatus.PendingApproval: msg = $"Page submitted for {(model.Publish ? "publish" : "unpublish")} approval."; break; case WorkflowStatus.Approved: msg = (model.Publish ? "Publish" : "Unpublish") + " workflow complete."; if (instance.ScheduledDate.HasValue) { msg += $" Page scheduled for publishing at {instance.ScheduledDate.Value.ToString("dd MMM YYYY", CultureInfo.CurrentCulture)}"; } break; } Log.Info(msg); // broadcast the new task back to the client to update dashboards etc // needs to be converted from a poco to remove unused properties and force camelCase _hubContext.Clients.All.WorkflowStarted( _tasksService.ConvertToWorkflowTaskList(instance.TaskInstances.ToList(), instance: instance) .FirstOrDefault()); return(Json(new { message = msg, status = 200 }, ViewHelpers.CamelCase)); } catch (Exception e) { const string msg = "An error occurred initiating the workflow"; Log.Error(msg, e); return(Content(HttpStatusCode.InternalServerError, ViewHelpers.ApiException(e, msg))); } }
/// <summary> /// Create the new process object for the instance - publish or unpublish /// </summary> /// <param name="instance"></param> /// <returns></returns> public static WorkflowProcess GetProcess(this WorkflowInstancePoco instance) { if ((WorkflowType)instance.Type == WorkflowType.Publish) { return(new DocumentPublishProcess()); } return(new DocumentUnpublishProcess()); }
public void Can_Initiate_Publish_Workflow() { Scaffold.Config(); var process = new DocumentPublishProcess(); WorkflowInstancePoco instance = process.InitiateWorkflow(1073, 3, "A test comment"); Assert.NotNull(instance); }
public void Can_Cancel() { var instance = new WorkflowInstancePoco(); instance.Cancel(); Assert.NotNull(instance.CompletedDate); Assert.Equal(WorkflowStatus.Cancelled, instance.WorkflowStatus); }
/// <summary> /// set the total steps property for a workflow instance /// </summary> /// <param name="instance"></param> /// <param name="steps">The number of approval groups in the current flow (explicit, inherited or content type)</param> public static void SetTotalSteps(this WorkflowInstancePoco instance, int steps) { if (instance.TotalSteps == steps) { return; } instance.TotalSteps = steps; }
public void Can_Get_Process(WorkflowType type, Type expected) { var instance = new WorkflowInstancePoco { Type = (int)type }; WorkflowProcess process = instance.GetProcess(); Assert.IsType(expected, process); }
public void Can_Get_By_Guid() { var guid = Guid.NewGuid(); _service.InsertInstance(Scaffold.Instance(guid, 1)); WorkflowInstancePoco instance = _service.GetByGuid(guid); Assert.NotNull(instance); Assert.Equal(guid, instance.Guid); }
public void Can_Set_Total_Steps(int steps, int instanceSteps) { var instance = new WorkflowInstancePoco { TotalSteps = instanceSteps }; instance.SetTotalSteps(steps); Assert.Equal(steps, instance.TotalSteps); }
/// <summary> /// Adds an approval task to this workflow instance, setting the approval step and instance guid /// </summary> /// <param name="instance"></param> public static WorkflowTaskPoco CreateApprovalTask(this WorkflowInstancePoco instance) { var taskInstance = new WorkflowTaskPoco(TaskType.Approve) { ApprovalStep = instance.TaskInstances.Count(x => x.TaskStatus.In(TaskStatus.Approved, TaskStatus.NotRequired)), WorkflowInstanceGuid = instance.Guid }; instance.TaskInstances.Add(taskInstance); return(taskInstance); }
public IHttpActionResult ResubmitWorkflowTask(TaskData model) { WorkflowInstancePoco instance = _instancesService.GetPopulatedInstance(model.InstanceGuid); WorkflowProcess process = instance.GetProcess(); try { IUser currentUser = _utility.GetCurrentUser(); instance = process.ResubmitWorkflow( instance, currentUser.Id, model.Comment ); string typeDescription = instance.WorkflowType.Description(instance.ScheduledDate); string typeDescriptionPast = instance.WorkflowType.DescriptionPastTense(instance.ScheduledDate); Log.Info($"{typeDescription} request for {instance.Node.Name} [{instance.NodeId}] was resubmitted by {currentUser.Name}"); _hubContext.Clients.All.TaskResubmitted( _tasksService.ConvertToWorkflowTaskList(instance.TaskInstances.ToList(), instance: instance)); return(Json(new { message = $"Changes resubmitted successfully. Page will be {typeDescriptionPast.ToLower()} following workflow completion.", status = 200, notifications = NotificationHelpers.MapEventMessagesToNotifications(process.EventMessages) }, ViewHelpers.CamelCase)); } catch (UmbracoOperationFailedException e) { string msg = $"A Publishing failure occurred processing the approval on {instance.Node.Name} [{instance.Node.Id}]"; Log.Error(msg, e); return(Json(new { message = msg, status = 200, isUmbracoOperationError = true, notifications = NotificationHelpers.MapEventMessagesToNotifications(process.EventMessages) } , ViewHelpers.CamelCase)); } catch (Exception ex) { string msg = $"An error occurred processing the approval on {instance.Node.Name} [{instance.NodeId}]"; Log.Error(msg, ex); return(Content(HttpStatusCode.InternalServerError, ViewHelpers.ApiException(ex, msg))); } }
public IHttpActionResult InitiateWorkflow(InitiateWorkflowModel model) { try { WorkflowProcess process; if (model.Publish) { process = new DocumentPublishProcess(); } else { process = new DocumentUnpublishProcess(); } WorkflowInstancePoco instance = process.InitiateWorkflow(int.Parse(model.NodeId), _utility.GetCurrentUser().Id, model.Comment); string msg = string.Empty; switch (instance.WorkflowStatus) { case WorkflowStatus.PendingApproval: msg = $"Page submitted for {(model.Publish ? "publish" : "unpublish")} approval."; break; case WorkflowStatus.Approved: msg = (model.Publish ? "Publish" : "Unpublish") + " workflow complete."; if (instance.ScheduledDate.HasValue) { msg += $" Page scheduled for publishing at {instance.ScheduledDate.Value.ToString("dd MMM YYYY", CultureInfo.CurrentCulture)}"; } break; } Log.Info(msg); return(Json(new { message = msg, status = 200 }, ViewHelpers.CamelCase)); } catch (Exception e) { const string msg = "An error occurred initiating the workflow"; Log.Error(msg, e); return(Content(HttpStatusCode.InternalServerError, ViewHelpers.ApiException(e, msg))); } }
/// <summary> /// Quickly scaffold a set of instances with arbitrary values and no tasks /// This method adds the instances to the db /// </summary> /// <param name="count"></param> /// <param name="type"></param> /// <param name="status"></param> /// <returns></returns> public static IEnumerable <WorkflowInstancePoco> Instances(int count, int type = 1, int status = (int)WorkflowStatus.PendingApproval, int?nodeId = null) { List <WorkflowInstancePoco> response = new List <WorkflowInstancePoco>(); for (var i = 0; i < count; i++) { WorkflowInstancePoco instance = Instance(Guid.NewGuid(), type, nodeId ?? Utility.RandomInt(), Utility.RandomInt(), status); InstancesService.InsertInstance(instance); response.Add(instance); } return(response); }
public string GetNotifications(Guid instanceGuid, int emailType) { try { WorkflowInstancePoco instance = _instancesService.GetByGuid(instanceGuid); Notifications.Send(instance, (EmailType)emailType); return("done - check the mail drop folder"); } catch (Exception e) { return(ViewHelpers.ApiException(e).ToString()); } }
public string GetNotifications(Guid instanceGuid, int emailType) { try { WorkflowInstancePoco instance = _instancesService.GetByGuid(instanceGuid); _emailer.Send(instance, (EmailType)emailType); return($"Notifications sent for { instance.Id }. Check the mail pickup folder."); } catch (Exception e) { return(ViewHelpers.ApiException(e).ToString()); } }
public string GetNotifications(int instanceId, int emailType) { try { WorkflowInstancePoco instance = Pr.GetAllInstances().FirstOrDefault(x => x.Id == instanceId); Notifications.Send(instance, (EmailType)emailType); return("done - check the mail drop folder"); } catch (Exception e) { return(ViewHelpers.ApiException(e).ToString()); } }
/// <summary> /// /// </summary> /// <param name="guid"></param> /// <returns></returns> public WorkflowInstancePoco GetPopulatedInstance(Guid guid) { WorkflowInstancePoco instance = GetByGuid(guid); // TODO -> fix this List <WorkflowTaskPoco> tasks = _tasksService.GetTasksWithGroupByInstanceGuid(instance.Guid); if (tasks.Any()) { // ordering by descending id to allow for cases with multiple rejections // most recent will be highest id instance.TaskInstances = tasks.OrderByDescending(t => t.Id).ToList(); } return(instance); }
/// <summary> /// /// </summary> /// <param name="instanceGuid"></param> /// <returns></returns> private static WorkflowInstancePoco GetInstance(Guid instanceGuid) { WorkflowInstancePoco instance = Pr.InstanceByGuid(instanceGuid); instance.SetScheduledDate(); // TODO -> fix this List <WorkflowTaskInstancePoco> tasks = Pr.TasksAndGroupByInstanceId(instance.Guid); if (tasks.Any()) { instance.TaskInstances = tasks; } return(instance); }
/// <summary> /// /// </summary> /// <param name="instanceGuid"></param> /// <returns></returns> private WorkflowInstancePoco GetInstance(Guid instanceGuid) { WorkflowInstancePoco instance = _instancesService.GetByGuid(instanceGuid); instance.SetScheduledDate(); // TODO -> fix this List <WorkflowTaskInstancePoco> tasks = _tasksService.GetTasksWithGroupByInstanceGuid(instance.Guid); if (tasks.Any()) { instance.TaskInstances = tasks; } return(instance); }
public void Can_Update_Instance() { Guid guid = Guid.NewGuid(); const string comment = "This here is an update"; _service.InsertInstance(Scaffold.Instance(guid, 1)); WorkflowInstancePoco instance = _service.GetByGuid(guid); instance.AuthorComment = comment; _service.UpdateInstance(instance); WorkflowInstancePoco updatedInstance = _service.GetByGuid(guid); Assert.Equal(comment, updatedInstance.AuthorComment); }
public string GetNotifications(Guid instanceGuid, int emailType) { try { WorkflowInstancePoco instance = _instancesService.GetByGuid(instanceGuid); var node = _utility.GetPublishedContent(1078); _notifications.Send(instance, (EmailType)emailType); return(node.Name); } catch (Exception e) { return(ViewHelpers.ApiException(e).ToString()); } }
/// <summary> /// Builds workflow instance details markup. /// </summary> /// <returns>HTML tr inner html definition</returns> public static string BuildProcessSummary(this WorkflowInstancePoco instance) { string result = $"{instance.WorkflowType.Description(instance.ScheduledDate)} requested by {instance.AuthorUser.Name} on {instance.CreatedDate:dd/MM/yy} - {instance.StatusName}<br/>"; if (instance.AuthorComment.HasValue()) { result += $" Comment: <i>{instance.AuthorComment}</i>"; } result += "<br/>"; foreach (WorkflowTaskPoco taskInstance in instance.TaskInstances.OrderBy(t => t.ApprovalStep)) { result += taskInstance.BuildTaskSummary() + "<br/>"; } return($"{result}<br/>"); }