Ejemplo n.º 1
0
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public async Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            if (context.Contact != null)
            {
                var contact = await FindContactAsync(context, cancellationToken);

                if (contact != null)
                {
                    PatchContact(contact, context.Contact);
                    context.Contact = contact;
                }
            }

            var result = await ExecuteNodeAsync(context, cancellationToken);

            if (result == null)
            {
                throw new InvalidOperationException("Action result is required.");
            }

            // Preserve backward-compatibility and log each event received from old actions
            // without having an effect on the action result
            if (!result.HasLogAction)
            {
                await ExecuteNodeAsync(context.Clone(new ActionItem
                {
                    Type    = ActionType.Log,
                    Enabled = true,
                    Options = JObject.FromObject(new { Anonymous = true })
                }),
                                       cancellationToken);
            }

            return(result);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Invokes an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext" /> to associate with this activity and execution.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult" /> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        private async Task <ActionActivityResult> ExecuteNodeAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            Debug.Assert(context != null);

            if (context.Action.Type == ActionType.Log)
            {
                context.HasLogAction = true;
            }
            if (!context.Action.Enabled)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }

            var descriptor = FindActionDescriptor(context.Action.Type);

            if (descriptor == null)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            var status = await descriptor.Activity.ExecuteAsync(context, cancellationToken);

            if (status.StatusCode == ActionActivityStatusCode.Success && context.Action.Children.Count > 0)
            {
                status = await ExecuteNodeListAsync(context, context.Action.Children.OfType <ActionItem>(), cancellationToken);
            }
            return(status);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public async Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            if (context.Contact == null || context.ContactState == ObjectState.Deleted)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            ValidationResult validationResult;
            var projectManager = context.Resolve <ProjectManager>();

            if (context.ContactExists)
            {
                validationResult = await projectManager.ReplaceContactAsync(context.Project, context.Contact, context.Contact, cancellationToken);

                if (validationResult.Succeeded)
                {
                    context.ContactState = ObjectState.Modified;
                }
            }
            else
            {
                validationResult = await projectManager.AddContactAsync(context.Project, context.Contact, cancellationToken);

                if (validationResult.Succeeded)
                {
                    context.ContactState = ObjectState.Added;
                }
            }
            return(context.CreateResult(validationResult.Succeeded ? ActionActivityStatusCode.Success : ActionActivityStatusCode.Failed));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            if (!context.ContactExists || context.ContactState == ObjectState.Deleted)
            {
                return(Task.FromResult(context.CreateResult(ActionActivityStatusCode.Failed)));
            }
            var options = context.Action.Options?.ToObject <Options>();

            if (options == null)
            {
                return(Task.FromResult(context.CreateResult(ActionActivityStatusCode.Failed)));
            }

            // Schedule this action with its children using the given time values
            BackgroundJob.Schedule <ScheduleActionJob>(job => job.Execute(new ScheduleActionJobData
            {
                ActionId     = context.Action.Id,
                AuthTicket   = context.AuthTicket,
                AnonymId     = context.AnonymId,
                Contact      = context.Contact,
                ContactState = context.ContactState,
                Properties   = context.Properties,
                Event        = context.Event
            }),
                                                       new DateTimeOffset(options.StartDate).Add(options.OffsetTime));

            // Break control flow to avoid to execute children actions
            return(Task.FromResult(context.CreateResult(ActionActivityStatusCode.Failed)));
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Called by the workflow runtime to execute an activity.
 /// </summary>
 /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
 /// <returns>
 /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
 /// </returns>
 public async Task <ActionActivityResult> InvokeAsync(ActionActivityContext context, CancellationToken cancellationToken)
 {
     if (context == null)
     {
         throw new ArgumentNullException(nameof(context));
     }
     if (context.Resolver == null)
     {
         context.Resolver = Resolver;
     }
     return(await Action.ExecuteAsync(context, cancellationToken));
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            var result  = context.CreateResult(ActionActivityStatusCode.Failed);
            var options = context.Action.Options?.ToObject <Options>();

            if (options != null)
            {
                result.StatusCode = ActionActivityStatusCode.Success;
                result.ReturnUrl  = GenerateUrl(context, options);
                //result.ReturnUrl = IsValidLocalUrl(context, options.Url) ? GenerateUrl(context, options) : options.Url;
            }
            return(Task.FromResult(result));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Generates an action URL.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext" /> to associate with this activity and execution.</param>
        /// <param name="options"></param>
        /// <returns></returns>
        private string GenerateUrl(ActionActivityContext context, Options options)
        {
            var service   = context.Resolve <IActionLinkService>();
            var uriParams = new List <UriParameter>
            {
                new UriParameter(
                    ResourceKeys.ActionParamName,
                    service.UrlTokenEncode(new ActionLink(context.RootAction.Id, context.Contact?.Id, context.Event.CustomUri)))
            };

            if (context.IsAuthenticated)
            {
                uriParams.Add(new UriParameter(ResourceKeys.ContactTokenParamName, AuthUtility.Protect(context.AuthTicket)));
            }
            return(UriUtility.MakeUri(options.Url, UriKind.Absolute, uriParams.ToArray()));
        }
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public async Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            var projectManager = context.Resolve <ProjectManager>();

            if (!context.ContactExists || context.ContactState == ObjectState.Deleted)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            var validationResult = await projectManager.RemoveContactAsync(context.Project, context.Contact, cancellationToken);

            if (validationResult.Succeeded)
            {
                context.ContactState = ObjectState.Deleted;
                return(context.CreateResult(ActionActivityStatusCode.Success));
            }
            return(context.CreateResult(ActionActivityStatusCode.Failed));
        }
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            if (!context.ContactExists)
            {
                return(Task.FromResult(context.CreateResult(ActionActivityStatusCode.Forbidden)));
            }
            if (context.ContactState == ObjectState.Deleted)
            {
                return(Task.FromResult(context.CreateResult(ActionActivityStatusCode.Failed)));
            }
            if ((context.AuthTicket == null) || (context.Contact.Id != context.AuthTicket.Id))
            {
                context.AnonymId = GuidUtility.NewSequentialGuid();
            }

            context.AuthTicket = AuthUtility.Create(context.Contact);

            return(Task.FromResult(context.CreateResult(ActionActivityStatusCode.Success)));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Invokes an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext" /> to associate with this activity and execution.</param>
        /// <param name="actions">The actions.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult" /> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        private async Task <ActionActivityResult> ExecuteNodeListAsync(ActionActivityContext context, IEnumerable <ActionItem> actions, CancellationToken cancellationToken)
        {
            Debug.Assert(context != null);
            Debug.Assert(actions != null);

            ActionActivityResult status = null;

            foreach (var action in actions)
            {
                context = context.Clone(action);
                status  = await ExecuteNodeAsync(context, cancellationToken);

                if (status.StatusCode == ActionActivityStatusCode.Success && status.ReturnUrl != null ||
                    status.StatusCode == ActionActivityStatusCode.Forbidden)
                {
                    return(status);
                }
            }
            return(status ?? context.CreateResult(ActionActivityStatusCode.Failed));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public async Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            var projectManager = context.Resolve <ProjectManager>();
            var mailService    = context.Resolve <IMailClientService>();

            if (!context.ContactExists || context.ContactState == ObjectState.Deleted)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            var options = context.Action.Options?.ToObject <Options>();

            if (options == null)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            var message = await projectManager.GetMailMessageByIdAsync(options.Id, MailMessageField.Body, cancellationToken);

            if (message == null)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            var project = await projectManager.FindByIdAsync(context.Project.Id, cancellationToken);

            if (project == null)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            var header = new MailMessageHeader();

            header.To.Add(context.Contact.Id);
            var invitation = context.Properties["Invitation"] as ProjectInvitation;

            if (invitation != null)
            {
                header.From = invitation.From;
                header.Placeholders[ActionResources.Invitation] = invitation;
            }
            await mailService.SendAsync(project, header, message, cancellationToken);

            return(context.CreateResult(ActionActivityStatusCode.Success));
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Merges contact data with DB contact data
        /// </summary>
        private static async Task <ContactItem> FindContactAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            var projectManager = context.Resolve <ProjectManager>();
            var contact        = default(ContactItem);

            if (context.Contact.Id > 0)
            {
                contact = await projectManager.GetContactByIdAsync(context.Contact.Id, ContactField.None, cancellationToken);
            }

            if (contact == null && context.Contact.FacebookId != null)
            {
                contact = await projectManager.GetContactByFacebookIdAsync(context.Project, (long)context.Contact.FacebookId, ContactField.None, cancellationToken);
            }

            if (contact == null && context.Contact.Email != null && context.Contact.Email.Address != null)
            {
                contact = await projectManager.GetContactByMailAsync(context.Project, context.Contact.Email.Address, ContactField.None, cancellationToken);
            }

            return(contact);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public async Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            var projectManager = context.Resolve <ProjectManager>();

            if (!context.ContactExists || context.ContactState == ObjectState.Deleted)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            var options = context.Action.Options?.ToObject <Options>();

            if (options == null)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            await projectManager.SetBusinessTagsAsync(
                new[] { context.Contact.Id },
                options.Include ?? Enumerable.Empty <int>(),
                options.Exclude ?? Enumerable.Empty <int>(),
                cancellationToken);

            context.ContactState = ObjectState.Modified;
            return(context.CreateResult(ActionActivityStatusCode.Success));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public async Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            var projectManager = context.Resolve <ProjectManager>();
            var logManager     = context.Resolve <LogManager>();
            var options        = context.Action.Options?.ToObject <Options>();

            if (options == null || (!options.Anonymous && !context.ContactExists))
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }
            if (context.ContactExists)
            {
                context.Event.Contact      = context.Contact;
                context.Event.ContactState = context.ContactState;
            }
            else
            {
                context.Event.Contact      = null;
                context.Event.ContactState = ObjectState.Unchanged;
            }
            await logManager.LogAsync(context.Event, context.Project.Owners, cancellationToken);

            return(context.CreateResult(ActionActivityStatusCode.Success));
        }
 /// <summary>
 /// Called by the workflow runtime to execute an activity.
 /// </summary>
 /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
 /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
 /// <returns>
 /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
 /// </returns>
 public Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
 {
     return(Task.FromResult(context.CreateResult(ActionActivityStatusCode.Success)));
 }
        /// <summary>
        /// Called by the workflow runtime to execute an activity.
        /// </summary>
        /// <param name="context">The <see cref="ActionActivityContext"/> to associate with this activity and execution.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> used to propagate notifications that the operation should be canceled.</param>
        /// <returns>
        /// The <see cref="ActionActivityResult"/> of the run task, which determines whether the activity remains in the executing state, or transitions to the closed state.
        /// </returns>
        public async Task <ActionActivityResult> ExecuteAsync(ActionActivityContext context, CancellationToken cancellationToken)
        {
            var options = context.Action.Options?.ToObject <Options>();

            if (options == null || options.Conditions == null)
            {
                return(context.CreateResult(ActionActivityStatusCode.Failed));
            }

            bool succeeded         = true;
            var  includeWithTagIds = new HashSet <int>();
            var  excludeWithTagIds = new HashSet <int>();

            foreach (var condition in options.Conditions)
            {
                switch (condition?.Type)
                {
                case ConditionType.DateGreaterThanOrEqualTo:
                {
                    DateTime value;
                    succeeded &= DateTime.TryParse(condition.Value, out value) ? (DateTime.UtcNow >= value) : false;
                }
                break;

                case ConditionType.DateLessThanOrEqualTo:
                {
                    DateTime value;
                    succeeded &= DateTime.TryParse(condition.Value, out value) ? (DateTime.UtcNow <= value) : false;
                }
                break;

                case ConditionType.Authenticated:
                {
                    bool value;
                    succeeded &= bool.TryParse(condition.Value, out value) ? context.IsAuthenticated == value : false;
                }
                break;

                case ConditionType.ContactExists:
                {
                    bool value;
                    succeeded &= bool.TryParse(condition.Value, out value) ? context.ContactExists == value : false;
                }
                break;

                case ConditionType.ContactWithTag:
                {
                    int value;
                    if (succeeded &= int.TryParse(condition.Value, out value))
                    {
                        includeWithTagIds.Add(value);
                    }
                }
                break;

                case ConditionType.ContactWithoutTag:
                {
                    int value;
                    if (succeeded &= int.TryParse(condition.Value, out value))
                    {
                        excludeWithTagIds.Add(value);
                    }
                }
                break;

                default:
                    succeeded = false;
                    break;
                }
                if (!succeeded)
                {
                    return(context.CreateResult(ActionActivityStatusCode.Failed));
                }
            }

            if (context.ContactExists &&
                context.ContactState != ObjectState.Deleted &&
                (includeWithTagIds.Count | excludeWithTagIds.Count) > 0)
            {
                var projectManager = context.Resolve <ProjectManager>();
                succeeded &= await projectManager.HasBusinessTagsAsync(
                    context.Contact, includeWithTagIds, excludeWithTagIds, cancellationToken);
            }

            return(context.CreateResult(succeeded ? ActionActivityStatusCode.Success : ActionActivityStatusCode.Failed));
        }