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));
        }
Ejemplo n.º 2
0
        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);
                }
            }
        }
Ejemplo n.º 4
0
        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));
        }
Ejemplo n.º 5
0
        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));
 }
Ejemplo n.º 7
0
        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());
        }