public async Task ExecuteAsync(RecipeExecutionContext context) { if (!String.Equals(context.Name, "WorkflowType", StringComparison.OrdinalIgnoreCase)) { return; } var model = context.Step.ToObject <WorkflowStepModel>(); foreach (JObject token in model.Data) { var workflow = token.ToObject <WorkflowType>(); var existing = await _workflowTypeStore.GetAsync(workflow.WorkflowTypeId); if (existing == null) { workflow.Id = 0; } else { await _workflowTypeStore.DeleteAsync(existing); } await _workflowTypeStore.SaveAsync(workflow); } }
public async Task <WorkflowExecutionContext> ResumeWorkflowAsync(Workflow workflow, BlockingActivity awaitingActivity, IDictionary <string, object> input = null) { var workflowType = await _workflowTypeStore.GetAsync(workflow.WorkflowTypeId); var activityRecord = workflowType.Activities.SingleOrDefault(x => x.ActivityId == awaitingActivity.ActivityId); var workflowContext = await CreateWorkflowExecutionContextAsync(workflowType, workflow, input); workflowContext.Status = WorkflowStatus.Resuming; // Signal every activity that the workflow is about to be resumed. var cancellationToken = new CancellationToken(); await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnInputReceivedAsync(workflowContext, input)); await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnWorkflowResumingAsync(workflowContext, cancellationToken)); if (cancellationToken.IsCancellationRequested) { // Workflow is aborted. workflowContext.Status = WorkflowStatus.Aborted; } else { // Check if the current activity can execute. if (activityRecord != null) { var activityContext = workflowContext.GetActivity(activityRecord.ActivityId); if (await activityContext.Activity.CanExecuteAsync(workflowContext, activityContext)) { // Signal every activity that the workflow is resumed. await InvokeActivitiesAsync(workflowContext, x => x.Activity.OnWorkflowResumedAsync(workflowContext)); // Remove the blocking activity. workflowContext.Workflow.BlockingActivities.Remove(awaitingActivity); // Resume the workflow at the specified blocking activity. await ExecuteWorkflowAsync(workflowContext, activityRecord); } else { workflowContext.Status = WorkflowStatus.Halted; return(workflowContext); } } } if (workflowContext.Status == WorkflowStatus.Finished && workflowType.DeleteFinishedWorkflows) { await _workflowStore.DeleteAsync(workflowContext.Workflow); } else { await PersistAsync(workflowContext); } return(workflowContext); }
private async Task UpdateRouteEntriesAsync(WorkflowContext context) { var workflow = context.Workflow; var workflowType = await _workflowTypeStore.GetAsync(workflow.WorkflowTypeId); var entries = WorkflowRouteEntries.GetWorkflowRoutesEntries(workflowType, context.Workflow, _activityLibrary); _workflowRouteEntries.AddEntries(entries); }
public async Task <IActionResult> BulkEdit(WorkflowTypeBulkAction bulkAction, PagerParameters pagerParameters) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageWorkflows)) { return(Unauthorized()); } var viewModel = new WorkflowTypeIndexViewModel { WorkflowTypes = new List <WorkflowTypeEntry>(), Options = new WorkflowTypeIndexOptions() }; if (!(await TryUpdateModelAsync(viewModel))) { return(View(viewModel)); } var checkedEntries = viewModel.WorkflowTypes.Where(t => t.IsChecked); switch (bulkAction) { case WorkflowTypeBulkAction.None: break; case WorkflowTypeBulkAction.Delete: foreach (var entry in checkedEntries) { var workflowType = await _workflowTypeStore.GetAsync(entry.Id); if (workflowType != null) { await _workflowTypeStore.DeleteAsync(workflowType); _notifier.Success(H["Workflow {0} has been deleted.", workflowType.Name]); } } break; default: throw new ArgumentOutOfRangeException(); } return(RedirectToAction("Index", new { page = pagerParameters.Page, pageSize = pagerParameters.PageSize })); }
public async Task <IActionResult> GenerateUrl(int workflowTypeId, string activityId, int tokenLifeSpan) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageWorkflows)) { return(Forbid()); } var workflowType = await _workflowTypeStore.GetAsync(workflowTypeId); if (workflowType == null) { return(NotFound()); } var token = _securityTokenService.CreateToken(new WorkflowPayload(workflowType.WorkflowTypeId, activityId), TimeSpan.FromDays(tokenLifeSpan == 0 ? NoExpiryTokenLifespan : tokenLifeSpan)); var url = Url.Action("Invoke", "HttpWorkflow", new { token = token }); return(Ok(url)); }
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var httpMethod = context.HttpContext.Request.Method; var routeValues = context.RouteData.Values; var workflowTypeEntries = await _workflowTypeRouteEntries.GetWorkflowRouteEntriesAsync(httpMethod, routeValues); var workflowEntries = await _workflowRouteEntries.GetWorkflowRouteEntriesAsync(httpMethod, routeValues); if (workflowTypeEntries.Any()) { var workflowTypeIds = workflowTypeEntries.Select(x => Int32.Parse(x.WorkflowId)).ToList(); var workflowTypes = (await _workflowTypeStore.GetAsync(workflowTypeIds)).ToDictionary(x => x.Id); var correlationId = routeValues.GetValue <string>("correlationid"); foreach (var entry in workflowTypeEntries) { if (workflowTypes.TryGetValue(Int32.Parse(entry.WorkflowId), out var workflowType)) { var activity = workflowType.Activities.Single(x => x.ActivityId == entry.ActivityId); if (activity.IsStart) { // If this is not a singleton workflow or there is not already an halted instance, start a new workflow. if (!workflowType.IsSingleton || !await _workflowStore.HasHaltedInstanceAsync(workflowType.WorkflowTypeId)) { await _workflowManager.StartWorkflowAsync(workflowType, activity, null, correlationId); } } } } } if (workflowEntries.Any()) { var workflowIds = workflowEntries.Select(x => x.WorkflowId).ToList(); var workflows = (await _workflowStore.GetAsync(workflowIds)).ToDictionary(x => x.WorkflowId); var correlationId = routeValues.GetValue <string>("correlationid"); foreach (var entry in workflowEntries) { if (workflows.TryGetValue(entry.WorkflowId, out var workflow) && (String.IsNullOrWhiteSpace(correlationId) || workflow.CorrelationId == correlationId)) { var blockingActivity = workflow.BlockingActivities.Single(x => x.ActivityId == entry.ActivityId); await _workflowManager.ResumeWorkflowAsync(workflow, blockingActivity); } } } await next(); }
public async Task <IActionResult> BulkEdit(WorkflowTypeIndexOptions options, IEnumerable <int> itemIds) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageWorkflows)) { return(Forbid()); } if (itemIds?.Count() > 0) { var checkedEntries = await _session.Query <WorkflowType, WorkflowTypeIndex>().Where(x => x.DocumentId.IsIn(itemIds)).ListAsync(); switch (options.BulkAction) { case WorkflowTypeBulkAction.None: break; case WorkflowTypeBulkAction.Delete: foreach (var entry in checkedEntries) { var workflowType = await _workflowTypeStore.GetAsync(entry.Id); if (workflowType != null) { await _workflowTypeStore.DeleteAsync(workflowType); _notifier.Success(H["Workflow {0} has been deleted.", workflowType.Name]); } } break; default: throw new ArgumentOutOfRangeException(); } } return(RedirectToAction("Index")); }
public async Task <IActionResult> Index(int workflowTypeId, PagerParameters pagerParameters, string returnUrl = null) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageWorkflows)) { return(Unauthorized()); } if (!Url.IsLocalUrl(returnUrl)) { returnUrl = Url.Action(nameof(Index), "WorkflowType"); } var workflowType = await _workflowTypeStore.GetAsync(workflowTypeId); var siteSettings = await _siteService.GetSiteSettingsAsync(); var count = await _workflowStore.CountAsync(workflowType.WorkflowTypeId); var pager = new Pager(pagerParameters, siteSettings.PageSize); var records = await _workflowStore.ListAsync(workflowType.WorkflowTypeId, pager.GetStartIndex(), pager.PageSize); var pagerShape = (await New.Pager(pager)).TotalItemCount(count); var viewModel = new WorkflowIndexViewModel { WorkflowType = workflowType, Workflows = records.Select(x => new WorkflowEntry { Workflow = x, Id = x.Id }).ToList(), Pager = pagerShape, ReturnUrl = returnUrl }; return(View(viewModel)); }
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var httpMethod = context.HttpContext.Request.Method; var routeValues = context.RouteData.Values; var workflowTypeEntries = _workflowTypeRouteEntries.GetWorkflowRouteEntries(httpMethod, routeValues); var workflowEntries = _workflowRouteEntries.GetWorkflowRouteEntries(httpMethod, routeValues); if (workflowTypeEntries.Any()) { var workflowTypeIds = workflowTypeEntries.Select(x => Int32.Parse(x.WorkflowId)).ToList(); var workflowTypes = (await _workflowTypeStore.GetAsync(workflowTypeIds)).ToDictionary(x => x.Id); foreach (var entry in workflowTypeEntries) { var workflowType = workflowTypes[Int32.Parse(entry.WorkflowId)]; var activity = workflowType.Activities.Single(x => x.ActivityId == entry.ActivityId); await _workflowManager.StartWorkflowAsync(workflowType, activity); } } await next(); }
public async Task <IActionResult> Index(int workflowTypeId, WorkflowIndexViewModel model, PagerParameters pagerParameters, string returnUrl = null) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageWorkflows)) { return(Forbid()); } if (!Url.IsLocalUrl(returnUrl)) { returnUrl = Url.Action(nameof(Index), "WorkflowType"); } var workflowType = await _workflowTypeStore.GetAsync(workflowTypeId); var siteSettings = await _siteService.GetSiteSettingsAsync(); var query = _session.Query <Workflow, WorkflowIndex>(); query = query.Where(x => x.WorkflowTypeId == workflowType.WorkflowTypeId); switch (model.Options.Filter) { case WorkflowFilter.Finished: query = query.Where(x => x.WorkflowStatus == WorkflowStatus.Finished); break; case WorkflowFilter.Faulted: query = query.Where(x => x.WorkflowStatus == WorkflowStatus.Faulted); break; case WorkflowFilter.All: default: break; } switch (model.Options.OrderBy) { case WorkflowOrder.CreatedDesc: query = query.OrderByDescending(x => x.CreatedUtc); break; case WorkflowOrder.Created: query = query.OrderBy(x => x.CreatedUtc); break; default: query = query.OrderByDescending(x => x.CreatedUtc); break; } var pager = new Pager(pagerParameters, siteSettings.PageSize); var routeData = new RouteData(); routeData.Values.Add("Filter", model.Options.Filter); var pagerShape = (await New.Pager(pager)).TotalItemCount(await query.CountAsync()).RouteData(routeData); var pageOfItems = await query.Skip(pager.GetStartIndex()).Take(pager.PageSize).ListAsync(); var viewModel = new WorkflowIndexViewModel { WorkflowType = workflowType, Workflows = pageOfItems.Select(x => new WorkflowEntry { Workflow = x, Id = x.Id }).ToList(), Options = model.Options, Pager = pagerShape, ReturnUrl = returnUrl }; model.Options.WorkflowsSorts = new List <SelectListItem>() { new SelectListItem() { Text = S["Recently created"], Value = nameof(WorkflowOrder.CreatedDesc) }, new SelectListItem() { Text = S["Least recently created"], Value = nameof(WorkflowOrder.Created) } }; model.Options.WorkflowsStatuses = new List <SelectListItem>() { new SelectListItem() { Text = S["All"], Value = nameof(WorkflowFilter.All) }, new SelectListItem() { Text = S["Faulted"], Value = nameof(WorkflowFilter.Faulted) }, new SelectListItem() { Text = S["Finished"], Value = nameof(WorkflowFilter.Finished) } }; viewModel.Options.WorkflowsBulkAction = new List <SelectListItem>() { new SelectListItem() { Text = S["Delete"], Value = nameof(WorkflowBulkAction.Delete) } }; return(View(viewModel)); }
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var httpMethod = context.HttpContext.Request.Method; var routeValues = context.RouteData.Values; var workflowTypeEntries = await _workflowTypeRouteEntries.GetWorkflowRouteEntriesAsync(httpMethod, routeValues); var workflowEntries = await _workflowRouteEntries.GetWorkflowRouteEntriesAsync(httpMethod, routeValues); if (workflowTypeEntries.Any()) { var workflowTypeIds = workflowTypeEntries.Select(x => Int32.Parse(x.WorkflowId)).ToList(); var workflowTypes = (await _workflowTypeStore.GetAsync(workflowTypeIds)).ToDictionary(x => x.Id); var correlationId = routeValues.GetValue <string>("correlationid"); foreach (var entry in workflowTypeEntries) { if (workflowTypes.TryGetValue(Int32.Parse(entry.WorkflowId), out var workflowType)) { var activity = workflowType.Activities.Single(x => x.ActivityId == entry.ActivityId); if (activity.IsStart) { // If a singleton, try to acquire a lock per workflow type. (var locker, var locked) = await _distributedLock.TryAcquireWorkflowTypeLockAsync(workflowType); if (!locked) { continue; } await using var acquiredLock = locker; // Check if this is a workflow singleton and there's already an halted instance on any activity. if (workflowType.IsSingleton && await _workflowStore.HasHaltedInstanceAsync(workflowType.WorkflowTypeId)) { continue; } await _workflowManager.StartWorkflowAsync(workflowType, activity, null, correlationId); } } } } if (workflowEntries.Any()) { var workflowIds = workflowEntries.Select(x => x.WorkflowId).ToList(); var workflows = (await _workflowStore.GetAsync(workflowIds)).ToDictionary(x => x.WorkflowId); var correlationId = routeValues.GetValue <string>("correlationid"); foreach (var entry in workflowEntries) { if (workflows.TryGetValue(entry.WorkflowId, out var workflow) && (String.IsNullOrWhiteSpace(correlationId) || workflow.CorrelationId == correlationId)) { // If atomic, try to acquire a lock per workflow instance. (var locker, var locked) = await _distributedLock.TryAcquireWorkflowLockAsync(workflow); if (!locked) { continue; } await using var acquiredLock = locker; // If atomic, check if the workflow still exists and is still correlated. var haltedWorkflow = workflow.IsAtomic ? await _workflowStore.GetAsync(workflow.Id) : workflow; if (haltedWorkflow == null || (!String.IsNullOrWhiteSpace(correlationId) && haltedWorkflow.CorrelationId != correlationId)) { continue; } // And if it is still halted on this activity. var blockingActivity = haltedWorkflow.BlockingActivities.SingleOrDefault(x => x.ActivityId == entry.ActivityId); if (blockingActivity != null) { await _workflowManager.ResumeWorkflowAsync(haltedWorkflow, blockingActivity); } } } } await next(); }
public async Task <IActionResult> InsertSnippet(string workflowsnippetname, int workflowTypeId, string returnUrl) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageWorkflows)) { return(Forbid()); } var workflowSnippet = await GetWorkFlowSnippet(workflowsnippetname); var sourceworkflowSnippetToInsert = workflowSnippet.WorkFlowType; var targetWorkflowType = await _workflowTypeStore.GetAsync(workflowTypeId); //copy source workflow into target workflow and save foreach (var act in sourceworkflowSnippetToInsert.Activities) { targetWorkflowType.Activities.Add(new ActivityRecord() { ActivityId = act.ActivityId, Name = act.Name, Properties = act.Properties, X = act.X, Y = act.Y, IsStart = act.IsStart }); } foreach (var trans in sourceworkflowSnippetToInsert.Transitions) { targetWorkflowType.Transitions.Add(new Transition { Id = trans.Id, SourceActivityId = trans.SourceActivityId, DestinationActivityId = trans.DestinationActivityId, SourceOutcomeName = trans.SourceOutcomeName }); } await _workflowTypeStore.SaveAsync(targetWorkflowType); // No editor to show; short-circuit to the "POST" action. return(Url.IsLocalUrl(returnUrl) ? (IActionResult)Redirect(returnUrl) : RedirectToAction("Edit", "WorkflowType", new { id = workflowTypeId })); /*//var activity = _activityLibrary.InstantiateActivity(activityName); * var activityId = _activityIdGenerator.GenerateUniqueId(new ActivityRecord()); * var activityEditor = await _activityDisplayManager.BuildEditorAsync(activity, _updateModelAccessor.ModelUpdater, isNew: true); * * activityEditor.Metadata.Type = "Activity_Edit"; * * var viewModel = new ActivityEditViewModel * { * Activity = activity, * ActivityId = activityId, * ActivityEditor = activityEditor, * WorkflowTypeId = workflowTypeId, * ReturnUrl = returnUrl * }; * * if (!activity.HasEditor) * { * // No editor to show; short-circuit to the "POST" action. * return await Create(activityName, viewModel); * } * * return View(viewModel);*/ }