Пример #1
0
        /// <summary>
        /// Prepares to handle the form submission.
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public override void PrepareHandleForm(FormSubmissionContext context, object configuration)
        {
            // Track usage of this feature.
            UsageTracker.TrackDesignedEmail();

            // Boilerplate.
            base.PrepareHandleForm(context, configuration);
        }
Пример #2
0
        /// <summary>
        /// Handles a form submission (sends data to a web API).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Variables.
            var config = configuration as SendDataConfiguration;
            var form   = context.Form;
            var data   = context.Data;
            var result = default(SendDataResult);


            // Convert lists into dictionary.
            var fieldsById = form.Fields.ToDictionary(x => x.Id, x => x);
            var valuesById = data.GroupBy(x => x.FieldId).Select(x => new
            {
                Id     = x.Key,
                Values = x.SelectMany(y => y.FieldValues).ToList()
            }).ToDictionary(x => x.Id, x => x.Values);


            // Attempts to get a field value.
            Func <Guid, string> tryGetValue = fieldId =>
            {
                var tempValues = default(List <string>);
                var tempField  = default(IFormField);
                var hasValues  = valuesById.TryGetValue(fieldId, out tempValues);
                var hasField   = fieldsById.TryGetValue(fieldId, out tempField);
                if (hasField && (hasValues || tempField.IsServerSideOnly))
                {
                    tempValues = hasValues
                        ? tempValues
                        : null;
                    return(tempField.FormatValue(tempValues, FieldPresentationFormats.Transmission));
                }
                return(null);
            };


            // Get the data to transmit.
            var transmissionData = config.Fields
                                   .Where(x => fieldsById.ContainsKey(x.FieldId))
                                   .Select(x => new KeyValuePair <string, string>(x.FieldName, tryGetValue(x.FieldId)))
                                   .Where(x => x.Value != null)
                                   .ToArray();


            // Query string format?
            if ("Query String".InvariantEquals(config.TransmissionFormat))
            {
                result = SendQueryStringRequest(config.Url, transmissionData, config.Method);
            }


            // Call function to handle result?
            if (context != null)
            {
                result.Context = context;
            }
            config?.ResultHandler?.HandleResult(result);
        }
Пример #3
0
 /// <summary>
 /// Handles a form submission (stores it).
 /// </summary>
 /// <param name="context">
 /// The form submission context.
 /// </param>
 /// <param name="configuration">
 /// The handler configuration.
 /// </param>
 public void HandleForm(FormSubmissionContext context, object configuration)
 {
     // Store the submission to the database.
     if (Submission != null)
     {
         var db = context.UmbracoContext.Application.DatabaseContext.Database;
         db.Insert(Submission);
     }
 }
Пример #4
0
        /// <summary>
        /// Handles a form submission (sends an email).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Variables.
            var form    = context.Form;
            var data    = context.Data;
            var files   = context.Files;
            var payload = context.Payload;

            // Create message.
            var config  = configuration as EmailConfiguration;
            var message = new MailMessage()
            {
                IsBodyHtml = false
            };

            message.From    = new MailAddress(config.SenderEmail);
            message.Subject = config.Subject;


            // Any allowed recipients (if not, abort early)?
            var allowedRecipients = FilterEmails(config.Recipients);

            if (!allowedRecipients.Any())
            {
                return;
            }
            foreach (var recipient in allowedRecipients)
            {
                message.To.Add(recipient);
            }


            // Append fields?
            if (config.AppendFields)
            {
                var chosenPayload = config.AppendPayload
                    ? payload
                    : payload.Take(0);
                message.Body = ConstructMessage(form, data, files, chosenPayload, config);
                foreach (var file in files)
                {
                    var dataStream = new MemoryStream(file.FileData);
                    message.Attachments.Add(new Attachment(dataStream, file.FileName));
                }
            }
            else
            {
                message.Body = config.Message;
            }


            // Send email.
            using (var client = new SmtpClient())
            {
                client.Send(message);
            }
        }
Пример #5
0
 /// <summary>
 /// Handles a form submission (sends an email).
 /// </summary>
 /// <param name="context">
 /// The form submission context.
 /// </param>
 /// <param name="configuration">
 /// The handler configuration.
 /// </param>
 public void HandleForm(FormSubmissionContext context, object configuration)
 {
     // Send email.
     if (Message != null)
     {
         using (var client = new SmtpClient())
         {
             client.Send(Message);
         }
     }
 }
Пример #6
0
        /// <summary>
        /// Returns a dictionary of form field values by field alias.
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <returns>
        /// The dictionary of form field values.
        /// </returns>
        private Dictionary <string, object[]> GetFormValues(FormSubmissionContext context)
        {
            // Variables.
            var data       = context.Data;
            var files      = context.Files;
            var payload    = context.Payload;
            var fieldsById = context.Form.Fields.ToDictionary(x => x.Id, x => x);
            var values     = new Dictionary <string, object[]>();

            // Add the payload items.
            foreach (var item in payload)
            {
                values[item.Name] = new[] { item.Value };
            }

            // Add the field values.
            foreach (var item in data)
            {
                var field = fieldsById[item.FieldId];
                var name  = string.IsNullOrWhiteSpace(field.Alias)
                    ? field.Name
                    : field.Alias;
                if (string.IsNullOrWhiteSpace(name))
                {
                    continue;
                }
                values[name] = item.FieldValues.MakeSafe().ToArray();
            }

            // Add the files.
            foreach (var item in files)
            {
                var field = fieldsById[item.FieldId];
                var name  = string.IsNullOrWhiteSpace(field.Alias)
                    ? field.Name
                    : field.Alias;
                if (string.IsNullOrWhiteSpace(name))
                {
                    continue;
                }
                values[name] = new[] { item };
            }

            // Return the dictionary of values.
            return(values);
        }
Пример #7
0
        /// <summary>
        /// Handles a form submission (sends an email).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Variables.
            var config          = configuration as EmailConfiguration;
            var form            = context.Form;
            var data            = context.Data;
            var dataForMessage  = data;
            var files           = context.Files;
            var filesForMessage = files;
            var payload         = context.Payload;
            var extraContext    = context.ExtraContext;
            var extraEmails     = (AttemptGetValue(extraContext, ExtraRecipientsKey) as List <string>).MakeSafe();
            var extraSubject    = AttemptGetValue(extraContext, ExtraSubjectKey) as string ?? string.Empty;
            var extraMessage    = AttemptGetValue(extraContext, ExtraMessageKey) as string ?? string.Empty;
            var baseMessage     = config.Message + extraMessage;

            // Create message.
            var message = new MailMessage()
            {
                IsBodyHtml = false
            };

            message.From    = new MailAddress(config.SenderEmail);
            message.Subject = config.Subject + extraSubject;


            // Get recipients from field values.
            var emailFieldIds = new HashSet <Guid>(config.RecipientFields);
            var fieldEmails   = data
                                .Where(x => emailFieldIds.Contains(x.FieldId)).SelectMany(x => x.FieldValues)
                                .Where(x => !string.IsNullOrWhiteSpace(x))
                                .Where(x => IsEmailInValidFormat(x));


            // Include only specific fields in the email message?
            if (config.FieldsToInclude.Any())
            {
                // Variables.
                var fieldIdsToInclude = new HashSet <Guid>(config.FieldsToInclude);

                // Selected server side fields.
                var serverSideFields = form.Fields
                                       .Where(x => x.IsServerSideOnly)
                                       .Where(x => fieldIdsToInclude.Contains(x.Id))
                                       .Select(x => new FieldSubmission()
                {
                    FieldId = x.Id,
                    // The values don't matter here, as the IFormFieldType.FormatValue is how server
                    // side fields return a field value.
                    FieldValues = Enumerable.Empty <string>()
                });

                // Combine submitted data and server side field data.
                var dataWithServerSideFields = data.Concat(serverSideFields);

                // Filter normal fields.
                dataForMessage = dataWithServerSideFields
                                 .Where(x => fieldIdsToInclude.Contains(x.FieldId)).ToArray();

                // Filter file fields.
                filesForMessage = files
                                  .Where(x => fieldIdsToInclude.Contains(x.FieldId)).ToArray();
            }


            // Any allowed recipients (if not, abort early)?
            var rawRecipients = config.Recipients
                                .Concat(fieldEmails)
                                .Concat(extraEmails);
            var allowedRecipients = FilterEmails(rawRecipients);

            if (!allowedRecipients.Any())
            {
                return;
            }
            foreach (var recipient in allowedRecipients)
            {
                // We don't want recipients to see each other, so we use BCC instead of TO.
                message.Bcc.Add(recipient);
            }


            // Append fields?
            if (config.AppendFields)
            {
                var chosenPayload = config.AppendPayload
                    ? payload
                    : payload.Take(0);
                message.Body = ConstructMessage(form, dataForMessage, filesForMessage,
                                                chosenPayload, baseMessage, config.IncludeHiddenFields, config.ExcludeFieldLabels);
                foreach (var file in filesForMessage)
                {
                    var dataStream = new MemoryStream(file.FileData);
                    message.Attachments.Add(new Attachment(dataStream, file.FileName));
                }
            }
            else
            {
                message.Body = baseMessage;
            }


            // Send email.
            using (var client = new SmtpClient())
            {
                client.Send(message);
            }
        }
Пример #8
0
        /// <summary>
        /// Submits a form.
        /// </summary>
        /// <param name="formId">
        /// The ID of the form to submit.
        /// </param>
        /// <param name="data">
        /// The form data to submit.
        /// </param>
        /// <param name="files">
        /// The file data to submit.
        /// </param>
        /// <param name="payload">
        /// Extra data related to the submission.
        /// </param>
        /// <param name="options">
        /// The options for this submission.
        /// </param>
        /// <param name="context">
        /// The contextual information for the form request.
        /// </param>
        /// <returns>
        /// The result of the submission.
        /// </returns>
        public SubmissionResult SubmitForm(Guid formId,
                                           IEnumerable <FieldSubmission> data, IEnumerable <FileFieldSubmission> files,
                                           IEnumerable <PayloadSubmission> payload, SubmissionOptions options,
                                           FormRequestContext context)
        {
            // Is the form ID valid?
            var form = Forms.Retrieve(formId);

            if (form == null)
            {
                return(new SubmissionResult()
                {
                    Success = false
                });
            }


            // Create submission context.
            var submissionContext = new FormSubmissionContext()
            {
                Files               = files,
                Data                = data,
                Form                = form,
                Payload             = payload,
                CurrentPage         = context.CurrentPage,
                HttpContext         = context.HttpContext,
                Services            = context.Services,
                UmbracoContext      = context.UmbracoContext,
                UmbracoHelper       = context.UmbracoHelper,
                SubmissionId        = Guid.NewGuid(),
                ExtraContext        = new Dictionary <string, object>(),
                SubmissionCancelled = false
            };


            // Invoke submitting event (gives listeners a chance to change the submission).
            Submitting?.Invoke(submissionContext);


            // Fail the form submission if SubmissionCancelled is true.
            if (submissionContext.SubmissionCancelled)
            {
                return(new SubmissionResult()
                {
                    Success = false
                });
            }


            // Validate against native field validations.
            foreach (var field in form.Fields)
            {
                var fieldId = field.Id;
                var value   = data.Where(x => x.FieldId == fieldId)
                              .SelectMany(x => x.FieldValues);
                if (!field.IsValid(value))
                {
                    return(new SubmissionResult()
                    {
                        Success = false
                    });
                }
            }


            // Validate?
            if (options.Validate)
            {
                var valuesById = data.GroupBy(x => x.FieldId).Select(x => new
                {
                    Id     = x.Key,
                    Values = x.SelectMany(y => y.FieldValues).ToList()
                }).ToDictionary(x => x.Id, x => x.Values);
                var filesById = files.GroupBy(x => x.FieldId).Select(x => new
                {
                    Id     = x.Key,
                    Values = x.Select(y => y).ToList()
                }).ToDictionary(x => x.Id, x => x.Values);
                foreach (var field in form.Fields)
                {
                    var validations = field.Validations
                                      .Select(x => Validations.Retrieve(x))
                                      .ToList();
                    if (!validations.Any())
                    {
                        continue;
                    }
                    var validationContext = new ValidationContext()
                    {
                        Field = field,
                        Form  = form
                    };
                    foreach (var validation in validations)
                    {
                        var dataValues = valuesById.ContainsKey(field.Id)
                            ? valuesById[field.Id]
                            : new List <string>();
                        var fileValues = filesById.ContainsKey(field.Id)
                            ? filesById[field.Id]
                            : new List <FileFieldSubmission>();
                        var isValid = validation
                                      .IsValueValid(dataValues, fileValues, validationContext);
                        if (!isValid)
                        {
                            return(new SubmissionResult()
                            {
                                Success = false
                            });
                        }
                    }
                }
            }


            // Prepare the form handlers.
            // This occurs on the current thread in case the handler needs information
            // only available in the current thread.
            var enabledHandlers = form.Handlers
                                  .Where(x => x.Enabled)
                                  .ToArray();

            try
            {
                foreach (var handler in enabledHandlers)
                {
                    handler.PrepareHandleForm(submissionContext);
                }
            }
            catch (Exception ex)
            {
                Logger.Error <Submissions_Instance>(ex, PreHandlerError);

                return(new SubmissionResult()
                {
                    Success = false
                });
            }


            // Initiate form handlers on a new thread (they may take some time to complete).
            var task = new Task(() =>
            {
                foreach (var handler in enabledHandlers)
                {
                    handler.HandleForm(submissionContext);
                }
            });

            task.ContinueWith(FormHandlersExceptionHandler, TaskContinuationOptions.OnlyOnFaulted);
            task.Start();

            // Return success.
            return(new SubmissionResult()
            {
                Success = true
            });
        }
Пример #9
0
        /// <summary>
        /// Prepares an mail message (e.g., sets the sender and recipients).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="config">
        /// The configuration for preparing the email message.
        /// </param>
        /// <returns>
        /// The prepared mail message.
        /// </returns>
        protected MailMessage PrepareEmailMessage(
            FormSubmissionContext context,
            IEmailSenderRecipientConfiguration config)
        {
            // Variables.
            var data         = context.Data;
            var extraContext = context.ExtraContext;
            var extraEmails  = (AttemptGetValue(extraContext, ExtraRecipientsKey) as List <string>).MakeSafe();


            // Create message.
            var message = new MailMessage {
                From = new MailAddress(config.SenderEmail)
            };


            // Add headers to message.
            foreach (var header in Config.EmailHeaders)
            {
                message.Headers.Add(header.Name, header.Value);
            }


            // Get recipients from field values.
            var emailFieldIds = new HashSet <Guid>(config.RecipientFields);
            var fieldEmails   = data
                                .Where(x => emailFieldIds.Contains(x.FieldId)).SelectMany(x => x.FieldValues)
                                .Where(x => !string.IsNullOrWhiteSpace(x))
                                .Where(x => IsEmailInValidFormat(x))
                                .ToArray();


            // Any allowed recipients (if not, abort early)?
            var rawRecipients = config.Recipients
                                .Concat(fieldEmails)
                                .Concat(extraEmails);
            var allowedRecipients = FilterEmails(rawRecipients);

            if (!allowedRecipients.Any())
            {
                return(null);
            }

            foreach (var recipient in allowedRecipients)
            {
                if ("to".InvariantEquals(config.DeliveryType as string))
                {
                    message.To.Add(recipient);
                }
                else if ("cc".InvariantEquals(config.DeliveryType as string))
                {
                    message.CC.Add(recipient);
                }
                else
                {
                    message.Bcc.Add(recipient);
                }
            }

            // Return the mail message.
            return(message);
        }
Пример #10
0
        /// <summary>
        /// Handles a form submission (sends an email).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public virtual void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Prepare the message.
            var message = PrepareEmailMessage(context, configuration as IEmailSenderRecipientConfiguration);

            if (message == null)
            {
                return;
            }

            // Variables.
            var config          = configuration as EmailConfiguration;
            var form            = context.Form;
            var data            = context.Data;
            var dataForMessage  = data;
            var files           = context.Files;
            var filesForMessage = files;
            var payload         = context.Payload;
            var extraContext    = context.ExtraContext;
            var extraSubject    = AttemptGetValue(extraContext, ExtraSubjectKey) as string ?? string.Empty;
            var extraMessage    = AttemptGetValue(extraContext, ExtraMessageKey) as string ?? string.Empty;
            var baseMessage     = config.Message + extraMessage;
            var plainTextBody   = default(string);
            var htmlBody        = default(string);


            // Set the email subject.
            message.Subject = config.Subject + extraSubject;


            // Include only specific fields in the email message?
            if (config.FieldsToInclude.Any())
            {
                // Variables.
                var fieldIdsToInclude = new HashSet <Guid>(config.FieldsToInclude);

                // Selected server side fields.
                var serverSideFields = form.Fields
                                       .Where(x => x.IsServerSideOnly)
                                       .Where(x => fieldIdsToInclude.Contains(x.Id))
                                       .Select(x => new FieldSubmission()
                {
                    FieldId = x.Id,

                    // The values don't matter here, as the IFormFieldType.FormatValue is how server
                    // side fields return a field value.
                    FieldValues = Enumerable.Empty <string>()
                });

                // Combine submitted data and server side field data.
                var dataWithServerSideFields = data.Concat(serverSideFields);

                // Filter normal fields.
                dataForMessage = dataWithServerSideFields
                                 .Where(x => fieldIdsToInclude.Contains(x.FieldId)).ToArray();

                // Filter file fields.
                filesForMessage = files
                                  .Where(x => fieldIdsToInclude.Contains(x.FieldId)).ToArray();
            }


            // Append fields?
            if (config.AppendFields)
            {
                var chosenPayload = config.AppendPayload
                    ? payload
                    : payload.Take(0);
                htmlBody = ConstructMessage(form, dataForMessage, filesForMessage,
                                            chosenPayload, baseMessage, config.IncludeHiddenFields, config.ExcludeFieldLabels, true);
                plainTextBody = ConstructMessage(form, dataForMessage, filesForMessage,
                                                 chosenPayload, baseMessage, config.IncludeHiddenFields, config.ExcludeFieldLabels, false);
                foreach (var file in filesForMessage)
                {
                    var dataStream = new MemoryStream(file.FileData);
                    message.Attachments.Add(new Attachment(dataStream, file.FileName));
                }
            }
            else
            {
                htmlBody      = WebUtility.HtmlEncode(baseMessage);
                plainTextBody = baseMessage;
            }


            // Add plain text alternate view.
            var mimeType  = new ContentType(MediaTypeNames.Text.Plain);
            var emailView = AlternateView.CreateAlternateViewFromString(plainTextBody, mimeType);

            message.AlternateViews.Add(emailView);


            // Add HTML alternate view.
            mimeType  = new ContentType(MediaTypeNames.Text.Html);
            emailView = AlternateView.CreateAlternateViewFromString(htmlBody, mimeType);
            message.AlternateViews.Add(emailView);


            // Send email.
            using (var client = new SmtpClient())
            {
                client.Send(message);
            }
        }
Пример #11
0
 /// <summary>
 /// Prepares to handle to form submission.
 /// </summary>
 /// <param name="context">
 /// The form submission context.
 /// </param>
 /// <param name="configuration">
 /// The handler configuration.
 /// </param>
 /// <remarks>
 /// In this case, no preparation is necessary.
 /// </remarks>
 public void PrepareHandleForm(FormSubmissionContext context, object configuration)
 {
 }
Пример #12
0
 /// <summary>
 /// Prepares to handle to form submission.
 /// </summary>
 /// <param name="context">
 /// The form submission context.
 /// </param>
 /// <param name="configuration">
 /// The handler configuration.
 /// </param>
 /// <remarks>
 /// In this case, no preparation is necessary.
 /// </remarks>
 public void PrepareHandleForm(FormSubmissionContext context, object configuration)
 {
     //TODO: Should probably prepare the data to be sent here (to avoid threading issues), but then send it in HandleForm.
 }
Пример #13
0
        /// <summary>
        /// Handles a form submission (stores it).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Variables.
            var form = context.Form;
            var data = context.Data;
            var files = context.Files;
            var payload = context.Payload;
            var fieldsById = form.Fields.ToDictionary(x => x.Id, x => x);
            var db = context.UmbracoContext.Application.DatabaseContext.Database;

            // This will store the formatted values.
            var valueList = new[]
            {
                new
                {
                    FieldId = default(string),
                    // Field name is stored in case the field is deleted from the form
                    // and this stored name is all we have to go on.
                    FieldName = default(string),
                    Value = default(string)
                }
            }.Take(0).ToList();

            // Group the data values by their field ID.
            var valuesById = data.GroupBy(x => x.FieldId).Select(x => new
            {
                Id = x.Key,
                Values = x.SelectMany(y => y.FieldValues).ToList()
            }).ToDictionary(x => x.Id, x => x.Values);

            // Store the file values by their field ID.
            var filesById = files.GroupBy(x => x.FieldId).Select(x => new
            {
                Id = x.Key,
                Filename = x.Select(y => y.FileName).FirstOrDefault(),
                PathSegment = GenerateFilePathSegment(),
                FileData = x.Select(y => y.FileData).FirstOrDefault()
            }).ToDictionary(x => x.Id, x => x);

            // Normal fields.
            foreach (var key in valuesById.Keys)
            {
                var values = valuesById[key];
                var formatted = string.Join(", ", values);
                var field = default(IFormField);
                var fieldName = default(string);
                if (fieldsById.TryGetValue(key, out field))
                {
                    formatted = field.FormatValue(values, FieldPresentationFormats.Storage);
                    fieldName = field.Name;
                }
                valueList.Add(new
                {
                    FieldId = GuidHelper.GetString(key),
                    FieldName = fieldName,
                    Value = formatted
                });
            }

            // Store file information for serialization.
            var fileList = filesById.Values.Select(x => new
            {
                FieldId = x.Id,
                // Field name is stored in case the field is deleted from the form
                // and this stored name is all we have to go on.
                FieldName = GetFieldName(x.Id, fieldsById),
                PathSegment = x.PathSegment,
                Filename = x.Filename
            });

            // Store the files.
            if (files.Any())
            {

                // Ensure base path exists.
                var basePath = HostingEnvironment.MapPath(Config.FileStoreBasePath);
                if (!Directory.Exists(basePath))
                {
                    Directory.CreateDirectory(basePath);
                }

                // Create files.
                foreach(var key in filesById.Keys)
                {
                    var file = filesById[key];
                    var fullPath = Path.Combine(basePath, file.PathSegment);
                    var pathOnly = Path.GetDirectoryName(fullPath);
                    Directory.CreateDirectory(pathOnly);
                    File.WriteAllBytes(fullPath, file.FileData);
                }

            }

            // Store data to database.
            var serializedValues = JsonHelper.Serialize(valueList.ToArray());
            var serializedFiles = JsonHelper.Serialize(fileList.ToArray());
            db.Insert(new FormulateSubmission()
            {
                CreationDate = DateTime.UtcNow,
                DataValues = serializedValues,
                FileValues = serializedFiles,
                FormId = form.Id,
                GeneratedId = context.SubmissionId,
                PageId = context?.CurrentPage?.Id,
                Url = context?.CurrentPage?.Url
            });
        }
Пример #14
0
        /// <summary>
        /// Handles a form submission (sends an email).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Variables.
            var config          = configuration as EmailConfiguration;
            var form            = context.Form;
            var data            = context.Data;
            var dataForMessage  = data;
            var files           = context.Files;
            var filesForMessage = files;
            var payload         = context.Payload;
            var extraContext    = context.ExtraContext;
            var extraEmails     = (AttemptGetValue(extraContext, ExtraRecipientsKey) as List <string>).MakeSafe();
            var extraSubject    = AttemptGetValue(extraContext, ExtraSubjectKey) as string ?? string.Empty;
            var extraMessage    = AttemptGetValue(extraContext, ExtraMessageKey) as string ?? string.Empty;
            var baseMessage     = config.Message + extraMessage;
            var plainTextBody   = default(string);
            var htmlBody        = default(string);

            // Create message.
            var message = new MailMessage();

            message.From    = new MailAddress(config.SenderEmail);
            message.Subject = config.Subject + extraSubject;


            // Add headers to message.
            foreach (var header in Config.EmailHeaders)
            {
                message.Headers.Add(header.Name, header.Value);
            }


            // Get recipients from field values.
            var emailFieldIds = new HashSet <Guid>(config.RecipientFields);
            var fieldEmails   = data
                                .Where(x => emailFieldIds.Contains(x.FieldId)).SelectMany(x => x.FieldValues)
                                .Where(x => !string.IsNullOrWhiteSpace(x))
                                .Where(x => IsEmailInValidFormat(x));


            // Include only specific fields in the email message?
            if (config.FieldsToInclude.Any())
            {
                // Variables.
                var fieldIdsToInclude = new HashSet <Guid>(config.FieldsToInclude);

                // Selected server side fields.
                var serverSideFields = form.Fields
                                       .Where(x => x.IsServerSideOnly)
                                       .Where(x => fieldIdsToInclude.Contains(x.Id))
                                       .Select(x => new FieldSubmission()
                {
                    FieldId = x.Id,
                    // The values don't matter here, as the IFormFieldType.FormatValue is how server
                    // side fields return a field value.
                    FieldValues = Enumerable.Empty <string>()
                });

                // Combine submitted data and server side field data.
                var dataWithServerSideFields = data.Concat(serverSideFields);

                // Filter normal fields.
                dataForMessage = dataWithServerSideFields
                                 .Where(x => fieldIdsToInclude.Contains(x.FieldId)).ToArray();

                // Filter file fields.
                filesForMessage = files
                                  .Where(x => fieldIdsToInclude.Contains(x.FieldId)).ToArray();
            }


            // Any allowed recipients (if not, abort early)?
            var rawRecipients = config.Recipients
                                .Concat(fieldEmails)
                                .Concat(extraEmails);
            var allowedRecipients = FilterEmails(rawRecipients);

            if (!allowedRecipients.Any())
            {
                return;
            }
            foreach (var recipient in allowedRecipients)
            {
                if ("to".InvariantEquals(config.DeliveryType))
                {
                    message.To.Add(recipient);
                }
                else if ("cc".InvariantEquals(config.DeliveryType))
                {
                    message.CC.Add(recipient);
                }
                else
                {
                    message.Bcc.Add(recipient);
                }
            }


            // Append fields?
            if (config.AppendFields)
            {
                var chosenPayload = config.AppendPayload
                    ? payload
                    : payload.Take(0);
                htmlBody = ConstructMessage(form, dataForMessage, filesForMessage,
                                            chosenPayload, baseMessage, config.IncludeHiddenFields, config.ExcludeFieldLabels, true);
                plainTextBody = ConstructMessage(form, dataForMessage, filesForMessage,
                                                 chosenPayload, baseMessage, config.IncludeHiddenFields, config.ExcludeFieldLabels, false);
                foreach (var file in filesForMessage)
                {
                    var dataStream = new MemoryStream(file.FileData);
                    message.Attachments.Add(new Attachment(dataStream, file.FileName));
                }
            }
            else
            {
                htmlBody      = WebUtility.HtmlEncode(baseMessage);
                plainTextBody = baseMessage;
            }


            // Add plain text alternate view.
            var mimeType  = new ContentType(MediaTypeNames.Text.Plain);
            var emailView = AlternateView.CreateAlternateViewFromString(plainTextBody, mimeType);

            message.AlternateViews.Add(emailView);


            // Add HTML alternate view.
            mimeType  = new ContentType(MediaTypeNames.Text.Html);
            emailView = AlternateView.CreateAlternateViewFromString(htmlBody, mimeType);
            message.AlternateViews.Add(emailView);


            // Send email.
            using (var client = new SmtpClient())
            {
                client.Send(message);
            }
        }
Пример #15
0
        /// <summary>
        /// Handles a form submission (sends an email).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public override void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Prepare the message.
            var message = PrepareEmailMessage(context, configuration as IEmailSenderRecipientConfiguration);

            if (message == null)
            {
                return;
            }

            // Variables.
            var config          = configuration as DesignedEmailConfiguration;
            var form            = context.Form;
            var data            = context.Data;
            var dataForMessage  = data;
            var files           = context.Files;
            var filesForMessage = files;
            var payload         = context.Payload;
            var extraContext    = context.ExtraContext;
            var plainTextBody   = default(string);
            var htmlBody        = default(string);

            // Combine all the email recipients into a single array.
            var emailDataRecipients = message.To.ToArray()
                                      .Concat(message.CC.ToArray())
                                      .Concat(message.Bcc.ToArray())
                                      .Select(x => x.Address).Distinct()
                                      .OrderBy(x => x).ToArray();

            // Create the email data to be passed to the Razor view.
            var emailData = new EmailData(GetFormValues(context))
            {
                MailMessage     = message,
                SenderEmail     = config.SenderEmail,
                RecipientEmails = emailDataRecipients,
                Subject         = config.Subject,
                Message         = config.Message,
                Helper          = new EmailDataHelper(message)
            };

            // Generate the email subject.
            var path     = GetViewPath(config.SubjectRazorPath);
            var contents = path == null
                ? RazorViewIncorrectMarkup(config.HtmlEmailRazorPath)
                : File.ReadAllText(path);

            var templateSource = path == null
                ? null
                : new LoadedTemplateSource(contents, path);
            var key = GetViewKey(path, contents);

            message.Subject = path == null
                ? config.Subject
                : (RazorService.RunCompile(templateSource, key, emailData.GetType(), emailData) ?? "")
                              .Trim()
                              .Replace("\r", string.Empty)
                              .Replace("\n", string.Empty);

            // Generate the HTML for the message.
            path     = GetViewPath(config.HtmlEmailRazorPath);
            contents = path == null
                ? RazorViewIncorrectMarkup(config.HtmlEmailRazorPath)
                : File.ReadAllText(path);

            templateSource = new LoadedTemplateSource(contents, path);
            key            = GetViewKey(path, contents);
            htmlBody       = RazorService.RunCompile(templateSource, key, emailData.GetType(), emailData);

            // Generate the text for the message.
            path = GetViewPath(config.TextEmailRazorPath);
            if (path != null)
            {
                contents       = File.ReadAllText(path);
                templateSource = new LoadedTemplateSource(contents, path);
                key            = GetViewKey(path, contents);
                plainTextBody  = RazorService.RunCompile(templateSource, key, emailData.GetType(), emailData);
            }

            // Add plain text alternate view.
            var mimeType  = new ContentType(MediaTypeNames.Text.Plain);
            var emailView = AlternateView.CreateAlternateViewFromString(plainTextBody ?? "", mimeType);

            message.AlternateViews.Add(emailView);

            // Add HTML alternate view.
            mimeType  = new ContentType(MediaTypeNames.Text.Html);
            emailView = AlternateView.CreateAlternateViewFromString(htmlBody ?? "", mimeType);
            message.AlternateViews.Add(emailView);

            // Send email.
            using (var client = new SmtpClient())
            {
                client.Send(message);
            }
        }
Пример #16
0
        /// <summary>
        /// Handles a form submission (stores it).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Variables.
            var form       = context.Form;
            var data       = context.Data;
            var files      = context.Files;
            var payload    = context.Payload;
            var fieldsById = form.Fields.ToDictionary(x => x.Id, x => x);
            var db         = context.UmbracoContext.Application.DatabaseContext.Database;


            // This will store the formatted values.
            var valueList = new[]
            {
                new
                {
                    FieldId = default(string),
                    // Field name is stored in case the field is deleted from the form
                    // and this stored name is all we have to go on.
                    FieldName = default(string),
                    Value     = default(string)
                }
            }.Take(0).ToList();


            // Group the data values by their field ID.
            var valuesById = data.GroupBy(x => x.FieldId).Select(x => new
            {
                Id     = x.Key,
                Values = x.SelectMany(y => y.FieldValues).ToList()
            }).ToDictionary(x => x.Id, x => x.Values);


            // Store the file values by their field ID.
            var filesById = files.GroupBy(x => x.FieldId).Select(x => new
            {
                Id          = x.Key,
                Filename    = x.Select(y => y.FileName).FirstOrDefault(),
                PathSegment = GenerateFilePathSegment(),
                FileData    = x.Select(y => y.FileData).FirstOrDefault()
            }).ToDictionary(x => x.Id, x => x);


            // Normal fields.
            foreach (var key in valuesById.Keys)
            {
                var values    = valuesById[key];
                var formatted = string.Join(", ", values);
                var field     = default(IFormField);
                var fieldName = default(string);
                if (fieldsById.TryGetValue(key, out field))
                {
                    formatted = field.FormatValue(values, FieldPresentationFormats.Storage);
                    fieldName = field.Name;
                }
                valueList.Add(new
                {
                    FieldId   = GuidHelper.GetString(key),
                    FieldName = fieldName,
                    Value     = formatted
                });
            }


            // Store file information for serialization.
            var fileList = filesById.Values.Select(x => new
            {
                FieldId = GuidHelper.GetString(x.Id),
                // Field name is stored in case the field is deleted from the form
                // and this stored name is all we have to go on.
                FieldName   = GetFieldName(x.Id, fieldsById),
                PathSegment = x.PathSegment,
                Filename    = x.Filename
            });


            // Store the files.
            if (files.Any())
            {
                // Ensure base path exists.
                var basePath = HostingEnvironment.MapPath(Config.FileStoreBasePath);
                if (!Directory.Exists(basePath))
                {
                    Directory.CreateDirectory(basePath);
                }


                // Create files.
                foreach (var key in filesById.Keys)
                {
                    var file     = filesById[key];
                    var fullPath = Path.Combine(basePath, file.PathSegment);
                    var pathOnly = Path.GetDirectoryName(fullPath);
                    Directory.CreateDirectory(pathOnly);
                    File.WriteAllBytes(fullPath, file.FileData);
                }
            }


            // Store data to database.
            var serializedValues = JsonHelper.Serialize(valueList.ToArray());
            var serializedFiles  = JsonHelper.Serialize(fileList.ToArray());

            db.Insert(new FormulateSubmission()
            {
                CreationDate = DateTime.UtcNow,
                DataValues   = serializedValues,
                FileValues   = serializedFiles,
                FormId       = form.Id,
                GeneratedId  = context.SubmissionId,
                PageId       = context?.CurrentPage?.Id,
                Url          = context?.CurrentPage?.Url
            });
        }
Пример #17
0
 /// <summary>
 /// Prepares to handle to form submission.
 /// </summary>
 /// <param name="context">
 /// The form submission context.
 /// </param>
 /// <param name="configuration">
 /// The handler configuration.
 /// </param>
 /// <remarks>
 /// In this case, no preparation is necessary.
 /// </remarks>
 public void PrepareHandleForm(FormSubmissionContext context, object configuration)
 {
 }
Пример #18
0
        /// <summary>
        /// Submits a form.
        /// </summary>
        /// <param name="formId">
        /// The ID of the form to submit.
        /// </param>
        /// <param name="data">
        /// The form data to submit.
        /// </param>
        /// <param name="files">
        /// The file data to submit.
        /// </param>
        /// <param name="payload">
        /// Extra data related to the submission.
        /// </param>
        /// <param name="options">
        /// The options for this submission.
        /// </param>
        /// <param name="context">
        /// The contextual information for the form request.
        /// </param>
        /// <returns>
        /// The result of the submission.
        /// </returns>
        public static SubmissionResult SubmitForm(Guid formId,
                                                  IEnumerable <FieldSubmission> data, IEnumerable <FileFieldSubmission> files,
                                                  IEnumerable <PayloadSubmission> payload, SubmissionOptions options,
                                                  FormRequestContext context)
        {
            // Is the form ID valid?
            var form = Forms.Retrieve(formId);

            if (form == null)
            {
                return(new SubmissionResult()
                {
                    Success = false
                });
            }


            // Create submission context.
            var submissionContext = new FormSubmissionContext()
            {
                Files          = files,
                Data           = data,
                Form           = form,
                Payload        = payload,
                CurrentPage    = context.CurrentPage,
                HttpContext    = context.HttpContext,
                Services       = context.Services,
                UmbracoContext = context.UmbracoContext,
                UmbracoHelper  = context.UmbracoHelper,
                SubmissionId   = Guid.NewGuid(),
                ExtraContext   = new Dictionary <string, object>()
            };


            // Invoke submitting event (gives listeners a chance to change the submission).
            Submitting?.Invoke(submissionContext);


            // Validate?
            if (options.Validate)
            {
                var valuesById = data.GroupBy(x => x.FieldId).Select(x => new
                {
                    Id     = x.Key,
                    Values = x.SelectMany(y => y.FieldValues).ToList()
                }).ToDictionary(x => x.Id, x => x.Values);
                foreach (var field in form.Fields)
                {
                    var validations = field.Validations.Select(x => Validations.Retrieve(x)).ToList();
                    foreach (var validation in validations)
                    {
                        //TODO: var validationResult = validation.Validate(form, field, valuesById);
                    }
                }
            }


            // Prepare the form handlers.
            // This occurs on the current thread in case the handler needs information
            // only available in the current thread.
            try
            {
                foreach (var handler in form.Handlers)
                {
                    handler.PrepareHandleForm(submissionContext);
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error <Submissions_Instance>(PreHandlerError, ex);
                return(new SubmissionResult()
                {
                    Success = false
                });
            }


            // Initiate form handlers on a new thread (they may take some time to complete).
            var t = new Thread(() =>
            {
                try
                {
                    foreach (var handler in form.Handlers)
                    {
                        handler.HandleForm(submissionContext);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error <Submissions_Instance>(HandlerError, ex);
                }
            });

            t.IsBackground = true;
            t.Start();


            // Return success.
            return(new SubmissionResult()
            {
                Success = true
            });
        }
Пример #19
0
        /// <summary>
        /// Sends a web request with the data either in the query string or in the body.
        /// </summary>
        /// <param name="config">
        /// The configuration for the data to be sent (e.g., contains the URL and request method).
        /// </param>
        /// <param name="context">
        /// The context for the current form submission.
        /// </param>
        /// <param name="data">
        /// The data to send.
        /// </param>
        /// <param name="sendInBody">
        /// Send the data as part of the body (or in the query string)?
        /// </param>
        /// <param name="sendJson">
        /// Send the data as json
        /// </param>
        /// <returns>
        /// True, if the request was a success; otherwise, false.
        /// </returns>
        /// <remarks>
        /// Parts of this function are from: http://stackoverflow.com/a/9772003/2052963
        /// and http://stackoverflow.com/questions/14702902
        /// </remarks>
        private SendDataResult SendData(SendDataConfiguration config, FormSubmissionContext context,
                                        IEnumerable <KeyValuePair <string, string> > data, bool sendInBody, bool sendJson)
        {
            // Construct a URL, possibly containing the data as query string parameters.
            var sendInUrl      = !sendInBody;
            var sendDataResult = new SendDataResult();
            var uri            = new Uri(config.Url);
            var bareUrl        = uri.GetLeftPart(UriPartial.Path);
            var keyValuePairs  = data as KeyValuePair <string, string>[] ?? data.ToArray();
            var strQueryString = ConstructQueryString(uri, keyValuePairs);
            var hasQueryString = !string.IsNullOrWhiteSpace(strQueryString);
            var requestUrl     = hasQueryString && sendInUrl
                ? $"{bareUrl}?{strQueryString}"
                : config.Url;
            var enableLogging       = WebConfigurationManager.AppSettings["Formulate:EnableLogging"];
            var jsonMode            = WebConfigurationManager.AppSettings["Formulate:Send Data JSON Mode"];
            var isJsonObjectMode    = "JSON Object".InvariantEquals(jsonMode);
            var isWrappedObjectMode = "Wrap JSON Object in Array".InvariantEquals(jsonMode);


            // Attempt to send the web request.
            try
            {
                // Construct web request.
                var request = (HttpWebRequest)WebRequest.Create(requestUrl);
                request.AllowAutoRedirect = false;
                request.UserAgent         = WebUserAgent;
                request.Method            = config.Method;


                // Send an event indicating that the data is about to be sent (which allows code
                // external to Formulate to modify the request).
                var sendContext = new SendingDataContext()
                {
                    Configuration     = config,
                    Data              = keyValuePairs,
                    Request           = request,
                    SubmissionContext = context
                };
                SendingData?.Invoke(sendContext);


                // Update the key/value pairs in case they got changed in the sending data event.
                // This only updates the methods that send the data in the body (as the URL has
                // already been set on the request).
                keyValuePairs = sendContext.Data as KeyValuePair <string, string>[]
                                ?? sendContext.Data.ToArray();


                // Send the data in the body (rather than the query string)?
                if (sendInBody)
                {
                    if (sendJson)
                    {
                        // Variables.
                        var json = default(string);


                        // Send an event indicating that the data is about to be serialized to
                        // JSON (which allows code external to Formulate to modify the JSON)?
                        if (SerializingJson != null)
                        {
                            json = SerializingJson.Invoke(sendContext.Data);
                        }
                        else
                        {
                            // If sending as JSON, group duplicate keys/value pairs.
                            var grouped = keyValuePairs.GroupBy(x => x.Key).Select(x => new
                            {
                                Key   = x.Key,
                                Value = x.Select(y => y.Value)
                            }).ToDictionary(x => x.Key,
                                            x => x.Value.Count() > 1 ? x.Value.ToArray() as object : x.Value.FirstOrDefault());


                            // Convert data to JSON.
                            if (isJsonObjectMode)
                            {
                                json = JsonConvert.SerializeObject(grouped);
                            }
                            else if (isWrappedObjectMode)
                            {
                                json = JsonConvert.SerializeObject(new[] { grouped });
                            }
                            else
                            {
                                // Ideally, we can remove this "else" branch later. We never really want this
                                // mode to be used, but it's here for legacy support in case anybody managed
                                // to make use of this funky mode.
                                json = JsonConvert.SerializeObject(new[] { grouped });
                            }
                        }


                        // Log JSON being sent.
                        if (enableLogging == "true")
                        {
                            LogHelper.Info <SendDataHandler>("Sent URL: " + config.Url);
                            LogHelper.Info <SendDataHandler>("Sent Data: " + JsonHelper.FormatJsonForLogging(json));
                        }


                        // Write JSON data to the request request.
                        var postBytes = Encoding.UTF8.GetBytes(json);
                        request.ContentType   = "application/json; charset=utf-8";
                        request.ContentLength = postBytes.Length;
                        using (var postStream = request.GetRequestStream())
                        {
                            postStream.Write(postBytes, 0, postBytes.Length);
                        }
                    }
                    else
                    {
                        // Log data being sent.
                        if (enableLogging == "true")
                        {
                            LogHelper.Info <SendDataHandler>("Sent URL: " + config.Url);
                            LogHelper.Info <SendDataHandler>("Sent Data: " + strQueryString);
                        }


                        // Update the data (since the sending data event may have modified it).
                        uri            = new Uri(config.Url);
                        strQueryString = ConstructQueryString(uri, keyValuePairs);


                        // Write the data to the request stream.
                        var postBytes = Encoding.UTF8.GetBytes(strQueryString);
                        request.ContentType   = "application/x-www-form-urlencoded";
                        request.ContentLength = postBytes.Length;
                        var postStream = request.GetRequestStream();
                        postStream.Write(postBytes, 0, postBytes.Length);
                    }
                }


                // Get and retain response.
                var response = (HttpWebResponse)request.GetResponse();
                sendDataResult.HttpWebResponse = response;
                var responseStream = response.GetResponseStream();
                var reader         = new StreamReader(responseStream);
                var resultText     = reader.ReadToEnd();
                sendDataResult.ResponseText = resultText;
                sendDataResult.Success      = true;
            }
            catch (Exception ex)
            {
                LogHelper.Error <SendDataHandler>(SendDataError, ex);
                sendDataResult.ResponseError = ex;
                sendDataResult.Success       = false;
            }


            // Return the result of the request.
            return(sendDataResult);
        }
Пример #20
0
        /// <summary>
        /// Handles a form submission (sends an email).
        /// </summary>
        /// <param name="context">
        /// The form submission context.
        /// </param>
        /// <param name="configuration">
        /// The handler configuration.
        /// </param>
        public void HandleForm(FormSubmissionContext context, object configuration)
        {
            // Variables.
            var form = context.Form;
            var data = context.Data;
            var files = context.Files;
            var payload = context.Payload;

            // Create message.
            var config = configuration as EmailConfiguration;
            var message = new MailMessage()
            {
                IsBodyHtml = false
            };
            message.From = new MailAddress(config.SenderEmail);
            message.Subject = config.Subject;

            // Any allowed recipients (if not, abort early)?
            var allowedRecipients = FilterEmails(config.Recipients);
            if (!allowedRecipients.Any())
            {
                return;
            }
            foreach (var recipient in allowedRecipients)
            {
                message.To.Add(recipient);
            }

            // Append fields?
            if (config.AppendFields)
            {
                var chosenPayload = config.AppendPayload
                    ? payload
                    : payload.Take(0);
                message.Body = ConstructMessage(form, data, files, chosenPayload, config);
                foreach(var file in files)
                {
                    var dataStream = new MemoryStream(file.FileData);
                    message.Attachments.Add(new Attachment(dataStream, file.FileName));
                }
            }
            else
            {
                message.Body = config.Message;
            }

            // Send email.
            using (var client = new SmtpClient())
            {
                client.Send(message);
            }
        }