public async Task <IActionResult> Create(string activityName, int workflowTypeId, string returnUrl) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageWorkflows)) { return(Forbid()); } 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)); }
internal static IEnumerable <WorkflowRoutesEntry> GetWorkflowTypeRoutesEntries(WorkflowType workflowType, IActivityLibrary activityLibrary) { return(workflowType.Activities.Where(x => x.IsStart && x.Name == HttpRequestFilterEvent.EventName).Select(x => { var activity = activityLibrary.InstantiateActivity <HttpRequestFilterEvent>(x); var entry = new WorkflowRoutesEntry { WorkflowId = workflowType.Id.ToString(), ActivityId = x.ActivityId, HttpMethod = activity.HttpMethod, RouteValues = activity.RouteValues }; return entry; })); }
private IEnumerable <string> GetUserTaskActions(WorkflowState workflowState, string activityId, IEnumerable <string> userRoles) { if (workflowState.ActivityStates.TryGetValue(activityId, out var activityState)) { var activity = _activityLibrary.InstantiateActivity <UserTaskEvent>(nameof(UserTaskEvent), activityState); if (activity.Roles.Any() && !userRoles.Any(x => activity.Roles.Contains(x))) { yield break; } foreach (var action in activity.Actions) { yield return(action); } } }
public Task <ActivityContext> CreateActivityExecutionContextAsync(ActivityRecord activityRecord, JObject properties) { var activity = _activityLibrary.InstantiateActivity <IActivity>(activityRecord.Name, properties); if (activity == null) { _logger.LogWarning("Requested activity '{ActivityName}' does not exist in the library. This could indicate a changed name or a missing feature. Replacing it with MissingActivity.", activityRecord.Name); activity = new MissingActivity(_missingActivityLocalizer, _missingActivityLogger, activityRecord); } var context = new ActivityContext { ActivityRecord = activityRecord, Activity = activity }; return(Task.FromResult(context)); }
internal static IEnumerable <WorkflowRoutesEntry> GetWorkflowRoutesEntries(WorkflowType workflowType, Workflow workflow, IActivityLibrary activityLibrary) { var awaitingActivityIds = workflow.BlockingActivities.Select(x => x.ActivityId).ToDictionary(x => x); return(workflowType.Activities.Where(x => x.Name == HttpRequestFilterEvent.EventName && awaitingActivityIds.ContainsKey(x.ActivityId)).Select(x => { var activity = activityLibrary.InstantiateActivity <HttpRequestFilterEvent>(x); var entry = new WorkflowRoutesEntry { WorkflowId = workflow.WorkflowId, ActivityId = x.ActivityId, HttpMethod = activity.HttpMethod, RouteValues = activity.RouteValues, }; return entry; })); }
public static T InstantiateActivity <T>(this IActivityLibrary library, string typeName) where T : IActivity { return((T)library.InstantiateActivity(typeName)); }
public async Task <IActionResult> Invoke(string token) { if (!_securityTokenService.TryDecryptToken <WorkflowPayload>(token, out var payload)) { _logger.LogWarning("Invalid SAS token provided"); return(NotFound()); } // Get the workflow type. var workflowType = await _workflowTypeStore.GetAsync(payload.WorkflowId); if (workflowType == null) { if (_logger.IsEnabled(LogLevel.Warning)) { _logger.LogWarning("The provided workflow with ID '{WorkflowTypeId}' could not be found.", payload.WorkflowId); } return(NotFound()); } if (!workflowType.IsEnabled) { if (_logger.IsEnabled(LogLevel.Warning)) { _logger.LogWarning("The provided workflow with ID '{WorkflowTypeId}' is not enabled.", payload.WorkflowId); } return(NotFound()); } // Get the activity record using the activity ID provided by the token. var startActivity = workflowType.Activities.FirstOrDefault(x => x.ActivityId == payload.ActivityId); if (startActivity == null) { if (_logger.IsEnabled(LogLevel.Warning)) { _logger.LogWarning("The provided activity with ID '{ActivityId}' could not be found.", payload.ActivityId); } return(NotFound()); } // Instantiate and bind an actual HttpRequestEvent object to check its settings. var httpRequestActivity = _activityLibrary.InstantiateActivity <HttpRequestEvent>(startActivity); if (httpRequestActivity == null) { if (_logger.IsEnabled(LogLevel.Warning)) { _logger.LogWarning("Activity with name '{ActivityName}' could not be found.", startActivity.Name); } return(NotFound()); } // Check if the HttpRequestEvent is configured to perform antiforgery token validation. If so, perform the validation. if (httpRequestActivity.ValidateAntiforgeryToken && (!await _antiforgery.IsRequestValidAsync(HttpContext))) { _logger.LogWarning("Antiforgery token validation failed."); return(BadRequest()); } // If the activity is a start activity, start a new workflow. if (startActivity.IsStart) { // If a singleton, try to acquire a lock per workflow type. (var locker, var locked) = await _distributedLock.TryAcquireWorkflowTypeLockAsync(workflowType); if (locked) { await using var acquiredLock = locker; // Check if this is not a workflow singleton or there's not already an halted instance on any activity. if (!workflowType.IsSingleton || !await _workflowStore.HasHaltedInstanceAsync(workflowType.WorkflowTypeId)) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Invoking new workflow of type '{WorkflowTypeId}' with start activity '{ActivityId}'", workflowType.WorkflowTypeId, startActivity.ActivityId); } await _workflowManager.StartWorkflowAsync(workflowType, startActivity); } } } else { // Otherwise, we need to resume all halted workflows on this activity. var workflows = await _workflowStore.ListAsync(workflowType.WorkflowTypeId, new[] { startActivity.ActivityId }); if (!workflows.Any()) { if (_logger.IsEnabled(LogLevel.Warning)) { _logger.LogWarning("No workflow found that is blocked on activity '{ActivityId}'", startActivity.ActivityId); } return(NotFound()); } foreach (var workflow in workflows) { var blockingActivity = workflow.BlockingActivities.FirstOrDefault(x => x.ActivityId == startActivity.ActivityId); if (blockingActivity != null) { if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Resuming workflow with ID '{WorkflowId}' on activity '{ActivityId}'", workflow.WorkflowId, blockingActivity.ActivityId); } // 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. var haltedWorkflow = workflow.IsAtomic ? await _workflowStore.GetAsync(workflow.WorkflowId) : workflow; if (haltedWorkflow == null) { continue; } // And if it is still halted on this activity. blockingActivity = haltedWorkflow.BlockingActivities.FirstOrDefault(x => x.ActivityId == startActivity.ActivityId); if (blockingActivity != null) { await _workflowManager.ResumeWorkflowAsync(haltedWorkflow, blockingActivity); } } } } return(GetWorkflowActionResult()); }
public async Task <IActionResult> Invoke(string token) { if (!_securityTokenService.TryDecryptToken <WorkflowPayload>(token, out var payload)) { _logger.LogWarning("Invalid SAS token provided"); return(NotFound()); } // Get the workflow type. var workflowType = await _workflowTypeStore.GetAsync(payload.WorkflowId); if (workflowType == null) { _logger.LogWarning("The provided workflow type with ID '{WorkflowTypeId}' could not be found.", payload.WorkflowId); return(NotFound()); } // Get the activity record using the activity ID provided by the token. var startActivity = workflowType.Activities.FirstOrDefault(x => x.ActivityId == payload.ActivityId); if (startActivity == null) { _logger.LogWarning("The provided activity with ID '{ActivityId}' could not be found.", payload.ActivityId); return(NotFound()); } // Instantiate and bind an actual HttpRequestEvent object to check its settings. var httpRequestActivity = _activityLibrary.InstantiateActivity <HttpRequestEvent>(startActivity); if (httpRequestActivity == null) { _logger.LogWarning("Activity with name '{ActivityName}' could not be found.", startActivity.Name); return(NotFound()); } // Check if the HttpRequestEvent is configured to perform antiforgery token validation. If so, perform the validation. if (httpRequestActivity.ValidateAntiforgeryToken && (!await _antiforgery.IsRequestValidAsync(HttpContext))) { _logger.LogWarning("Antiforgery token validation failed."); return(BadRequest()); } // If the activity is a start activity, start a new workflow. if (startActivity.IsStart) { _logger.LogDebug("Invoking new workflow of type {WorkflowTypeId} with start activity {ActivityId}", workflowType.WorkflowTypeId, startActivity.ActivityId); await _workflowManager.StartWorkflowAsync(workflowType, startActivity); } else { // Otherwise, we need to resume a halted workflow. var workflow = (await _workflowStore.ListAsync(workflowType.WorkflowTypeId, new[] { startActivity.ActivityId })).FirstOrDefault(); if (workflow == null) { _logger.LogWarning("No workflow found that is blocked on activity {ActivityId}", startActivity.ActivityId); return(NotFound()); } var blockingActivity = workflow.BlockingActivities.FirstOrDefault(x => x.ActivityId == startActivity.ActivityId); if (blockingActivity != null) { _logger.LogDebug("Resuming workflow with ID {WorkflowId} on activity {ActivityId}", workflow.WorkflowId, blockingActivity.ActivityId); await _workflowManager.ResumeWorkflowAsync(workflow, blockingActivity); } } return(GetWorkflowActionResult()); }