Example #1
0
        /// <summary>
        /// Gets the HTML preview.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="person">The person.</param>
        /// <returns></returns>
        public override string GetHtmlPreview(Model.Communication communication, Person person)
        {
            var rockContext = new RockContext();

            // Requery the Communication object
            communication = new CommunicationService(rockContext).Get(communication.Id);

            var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read();
            var mergeValues      = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields(null);

            if (person != null)
            {
                mergeValues.Add("Person", person);

                var recipient = communication.Recipients.Where(r => r.PersonAlias != null && r.PersonAlias.PersonId == person.Id).FirstOrDefault();
                if (recipient != null)
                {
                    // Add any additional merge fields created through a report
                    foreach (var mergeField in recipient.AdditionalMergeValues)
                    {
                        if (!mergeValues.ContainsKey(mergeField.Key))
                        {
                            mergeValues.Add(mergeField.Key, mergeField.Value);
                        }
                    }
                }
            }

            string message = communication.GetMediumDataValue("Message");

            return(message.ResolveMergeFields(mergeValues));
        }
Example #2
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        public override void Send(Model.Communication communication)
        {
            var rockContext          = new RockContext();
            var communicationService = new CommunicationService(rockContext);

            communication = communicationService.Get(communication.Id);

            if (communication != null &&
                communication.Status == Model.CommunicationStatus.Approved &&
                communication.Recipients.Where(r => r.Status == Model.CommunicationRecipientStatus.Pending).Any() &&
                (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
            {
                // Update any recipients that should not get sent the communication
                var recipientService = new CommunicationRecipientService(rockContext);
                foreach (var recipient in recipientService.Queryable("PersonAlias.Person")
                         .Where(r =>
                                r.CommunicationId == communication.Id &&
                                r.Status == CommunicationRecipientStatus.Pending)
                         .ToList())
                {
                    var person = recipient.PersonAlias.Person;
                    if (person.IsDeceased ?? false)
                    {
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "Person is deceased!";
                    }
                }

                rockContext.SaveChanges();
            }

            base.Send(communication);
        }
Example #3
0
        /// <summary>
        /// Sends the asynchronous.
        /// </summary>
        /// <param name="communication">The communication.</param>
        public virtual async Task SendAsync(Model.Communication communication)
        {
            if (this.IsActive)
            {
                // Get the Medium's Entity Type Id
                int mediumEntityTypeId = EntityTypeCache.Get(this.GetType()).Id;

                // Add the Medium's settings as attributes for the Transport to use.
                var mediumAttributes = GetMediumAttributes();

                // Use the transport to send communication
                var transport = Transport;
                if (transport != null && transport.IsActive)
                {
                    var asyncTransport = transport as IAsyncTransport;

                    if (asyncTransport == null)
                    {
                        transport.Send(communication, mediumEntityTypeId, mediumAttributes);
                    }
                    else
                    {
                        await asyncTransport.SendAsync(communication, mediumEntityTypeId, mediumAttributes).ConfigureAwait(false);
                    }
                }
            }
        }
Example #4
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        public virtual void Send(Model.Communication communication)
        {
            if (this.IsActive)
            {
                // Get the Medium's Entity Type Id
                int mediumEntityTypeId = EntityTypeCache.Read(this.GetType()).Id;

                // Add the Medium's settings as attributes for the Transport to use.
                var mediumAttributes = new Dictionary <string, string>();
                foreach (var attr in this.Attributes.Select(a => a.Value))
                {
                    string value = this.GetAttributeValue(attr.Key);
                    if (value.IsNotNullOrWhitespace())
                    {
                        mediumAttributes.Add(attr.Key, GetAttributeValue(attr.Key));
                    }
                }

                // Use the transport to send communication
                var transport = Transport;
                if (transport != null && transport.IsActive)
                {
                    transport.Send(communication, mediumEntityTypeId, mediumAttributes);
                }
            }
        }
Example #5
0
        private async Task SendToCommunicationRecipient(Model.Communication communication, string fromPhone, Dictionary <string, object> mergeFields, Person currentPerson, List <Uri> attachmentMediaUrls, int personEntityTypeId, int communicationCategoryId, int communicationEntityTypeId, string publicAppRoot, string callbackUrl, CommunicationRecipient recipient)
        {
            using (var rockContext = new RockContext())
            {
                try
                {
                    recipient = new CommunicationRecipientService(rockContext).Get(recipient.Id);
                    var twilioNumber = recipient.PersonAlias.Person.PhoneNumbers.GetFirstSmsNumber();
                    if (!string.IsNullOrWhiteSpace(twilioNumber))
                    {
                        // Create merge field dictionary
                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                        string message = ResolveText(communication.SMSMessage, currentPerson, recipient, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                        var response = await SendToTwilioAsync(fromPhone, callbackUrl, attachmentMediaUrls, message, twilioNumber).ConfigureAwait(false);

                        recipient.Status                  = CommunicationRecipientStatus.Delivered;
                        recipient.SendDateTime            = RockDateTime.Now;
                        recipient.TransportEntityTypeName = this.GetType().FullName;
                        recipient.UniqueMessageId         = response.Sid;

                        try
                        {
                            var historyService = new HistoryService(rockContext);
                            historyService.Add(new History
                            {
                                CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                EntityTypeId           = personEntityTypeId,
                                CategoryId             = communicationCategoryId,
                                EntityId            = recipient.PersonAlias.PersonId,
                                Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                ChangeType          = History.HistoryChangeType.Record.ToString(),
                                ValueName           = "SMS message",
                                Caption             = message.Truncate(200),
                                RelatedEntityTypeId = communicationEntityTypeId,
                                RelatedEntityId     = communication.Id
                            });
                        }
                        catch (Exception ex)
                        {
                            ExceptionLogService.LogException(ex, null);
                        }
                    }
                    else
                    {
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "No Phone Number with Messaging Enabled";
                    }
                }
                catch (Exception ex)
                {
                    recipient.Status     = CommunicationRecipientStatus.Failed;
                    recipient.StatusNote = "Twilio Exception: " + ex.Message;
                }

                rockContext.SaveChanges();
            }
        }
Example #6
0
        /// <summary>
        /// Gets the read-only message details.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <returns></returns>
        public override string GetMessageDetails(Model.Communication communication)
        {
            StringBuilder sb = new StringBuilder();

            AppendMediumData(communication, sb, "FromValue");
            AppendMediumData(communication, sb, "Message");

            return(sb.ToString());
        }
Example #7
0
        private void AppendMediumData(Model.Communication communication, StringBuilder sb, string key)
        {
            string value = communication.GetMediumDataValue(key);

            if (!string.IsNullOrWhiteSpace(value))
            {
                AppendMediumData(sb, key, value);
            }
        }
Example #8
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        public virtual void Send(Model.Communication communication)
        {
            if (this.IsActive)
            {
                // Get the Medium's Entity Type Id
                int mediumEntityTypeId = EntityTypeCache.Get(this.GetType()).Id;

                // Add the Medium's settings as attributes for the Transport to use.
                var mediumAttributes = GetMediumAttributes();

                // Use the transport to send communication
                if (Transport != null && Transport.IsActive)
                {
                    Transport.Send(communication, mediumEntityTypeId, mediumAttributes);
                }
            }
        }
Example #9
0
        private RockEmailMessage GetTemplateRockEmailMessage(Model.Communication communication, Dictionary <string, object> mergeFields, GlobalAttributesCache globalAttributes)
        {
            var resultEmailMessage = new RockEmailMessage();

            var publicAppRoot      = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
            var cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false;

            resultEmailMessage.AppRoot             = publicAppRoot;
            resultEmailMessage.CssInliningEnabled  = cssInliningEnabled;
            resultEmailMessage.CurrentPerson       = communication.CreatedByPersonAlias?.Person;
            resultEmailMessage.EnabledLavaCommands = communication.EnabledLavaCommands;
            resultEmailMessage.FromEmail           = communication.FromEmail;
            resultEmailMessage.FromName            = communication.FromName;

            var fromAddress = GetFromAddress(resultEmailMessage, mergeFields, globalAttributes);
            var fromName    = GetFromName(resultEmailMessage, mergeFields, globalAttributes);

            resultEmailMessage.FromEmail = fromAddress;
            resultEmailMessage.FromName  = fromName;

            // Reply To
            var replyToEmail = "";

            if (communication.ReplyToEmail.IsNotNullOrWhiteSpace())
            {
                // Resolve any possible merge fields in the replyTo address
                replyToEmail = communication.ReplyToEmail.ResolveMergeFields(mergeFields, resultEmailMessage.CurrentPerson);
            }
            resultEmailMessage.ReplyToEmail = replyToEmail;

            // Attachments
            resultEmailMessage.Attachments = communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile).ToList();
            // Load up the content stream while the context is still active.
            for (int i = 0; i < resultEmailMessage.Attachments.Count; i++)
            {
                var _ = resultEmailMessage.Attachments[i].ContentStream;
            }

            return(resultEmailMessage);
        }
Example #10
0
        /// <summary>
        /// Gets the read-only message details.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <returns></returns>
        public override string GetMessageDetails(Model.Communication communication)
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendLine("<div class='row'>");
            sb.AppendLine("<div class='col-md-6'>");

            AppendMediumData(communication, sb, "FromName");
            AppendMediumData(communication, sb, "FromAddress");
            AppendMediumData(communication, sb, "ReplyTo");
            AppendMediumData(communication, sb, "Subject");

            sb.AppendLine("</div>");
            sb.AppendLine("<div class='col-md-6'>");
            AppendAttachmentData(sb, communication.GetMediumDataValue("Attachments"));
            sb.AppendLine("</div>");
            sb.AppendLine("</div>");

            string value = communication.GetMediumDataValue("HtmlMessage");

            if (!string.IsNullOrWhiteSpace(value))
            {
                AppendMediumData(sb, "HtmlMessage", string.Format(@"
                        <iframe id='js-email-body-iframe' class='email-body'></iframe>
                        <script id='email-body' type='text/template'>{0}</script>
                        <script type='text/javascript'>
                            var doc = document.getElementById('js-email-body-iframe').contentWindow.document;
                            doc.open();
                            doc.write('<html><head><title></title></head><body>' +  $('#email-body').html() + '</body></html>');
                            doc.close();
                        </script>
                    ", value));
            }

            AppendMediumData(communication, sb, "TextMessage");

            return(sb.ToString());
        }
Example #11
0
        /// <summary>
        /// Sends the communication asynchronous.
        /// </summary>
        /// <param name="comm">The comm.</param>
        /// <param name="mutex">The mutex.</param>
        /// <returns></returns>
        private async Task <SendCommunicationAsyncResult> SendCommunicationAsync(Model.Communication comm, SemaphoreSlim mutex)
        {
            var communicationResult = new SendCommunicationAsyncResult
            {
                Communication = comm
            };

            var communicationStopWatch = Stopwatch.StartNew();

            RockLogger.Log.Debug(RockLogDomains.Jobs, "{0}: Starting to send {1}.", nameof(SendCommunicationAsync), comm.Name);
            try
            {
                await Model.Communication.SendAsync(comm).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                communicationResult.Exception = ex;
            }

            RockLogger.Log.Information(RockLogDomains.Jobs, "{0}: {1} took {2} ms", nameof(SendCommunications), comm.Name, communicationStopWatch.ElapsedMilliseconds);
            mutex.Release();
            return(communicationResult);
        }
Example #12
0
        public override void Send(Model.Communication communication)
        {
            int mediumEntityId = EntityTypeCache.Get(Rock.SystemGuid.EntityType.COMMUNICATION_MEDIUM_EMAIL.AsGuid())?.Id ?? 0;

            Send(communication, mediumEntityId, null);
        }
Example #13
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext).Get(communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    string fromPhone = communication.SMSFromDefinedValue?.Value;
                    if (string.IsNullOrWhiteSpace(fromPhone))
                    {
                        // just in case we got this far without a From Number, throw an exception
                        throw new Exception("A From Number was not provided for communication: " + communication.Id.ToString());
                    }

                    if (!string.IsNullOrWhiteSpace(fromPhone))
                    {
                        int?throttlingWaitTimeMS = null;
                        if (this.IsLongCodePhoneNumber(fromPhone))
                        {
                            throttlingWaitTimeMS = this.GetAttributeValue("Long-CodeThrottling").AsIntegerOrNull();
                        }

                        string accountSid = GetAttributeValue("SID");
                        string authToken  = GetAttributeValue("Token");
                        TwilioClient.Init(accountSid, authToken);

                        var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                        var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                        var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                        string callbackUrl = publicAppRoot + "Webhooks/Twilio.ashx";

                        var        smsAttachmentsBinaryFileIdList = communication.GetAttachmentBinaryFileIds(CommunicationType.SMS);
                        List <Uri> attachmentMediaUrls            = new List <Uri>();
                        if (smsAttachmentsBinaryFileIdList.Any())
                        {
                            attachmentMediaUrls = this.GetAttachmentMediaUrls(new BinaryFileService(communicationRockContext).GetByIds(smsAttachmentsBinaryFileIdList));
                        }

                        bool recipientFound = true;
                        while (recipientFound)
                        {
                            // make a new rockContext per recipient
                            var recipientRockContext = new RockContext();
                            var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                            if (recipient != null)
                            {
                                if (ValidRecipient(recipient, communication.IsBulkCommunication))
                                {
                                    try
                                    {
                                        var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers
                                                          .Where(p => p.IsMessagingEnabled)
                                                          .FirstOrDefault();

                                        if (phoneNumber != null)
                                        {
                                            // Create merge field dictionary
                                            var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                            string message = ResolveText(communication.SMSMessage, currentPerson, recipient, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                            string twilioNumber = phoneNumber.Number;
                                            if (!string.IsNullOrWhiteSpace(phoneNumber.CountryCode))
                                            {
                                                twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number;
                                            }

                                            MessageResource response = SendToTwilio(fromPhone, callbackUrl, attachmentMediaUrls, message, twilioNumber);

                                            recipient.Status                  = CommunicationRecipientStatus.Delivered;
                                            recipient.SendDateTime            = RockDateTime.Now;
                                            recipient.TransportEntityTypeName = this.GetType().FullName;
                                            recipient.UniqueMessageId         = response.Sid;

                                            try
                                            {
                                                var historyService = new HistoryService(recipientRockContext);
                                                historyService.Add(new History
                                                {
                                                    CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                    EntityTypeId           = personEntityTypeId,
                                                    CategoryId             = communicationCategoryId,
                                                    EntityId            = recipient.PersonAlias.PersonId,
                                                    Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                    ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                    ValueName           = "SMS message",
                                                    Caption             = message.Truncate(200),
                                                    RelatedEntityTypeId = communicationEntityTypeId,
                                                    RelatedEntityId     = communication.Id
                                                });
                                            }
                                            catch (Exception ex)
                                            {
                                                ExceptionLogService.LogException(ex, null);
                                            }
                                        }
                                        else
                                        {
                                            recipient.Status     = CommunicationRecipientStatus.Failed;
                                            recipient.StatusNote = "No Phone Number with Messaging Enabled";
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "Twilio Exception: " + ex.Message;
                                    }
                                }

                                recipientRockContext.SaveChanges();

                                if (throttlingWaitTimeMS.HasValue)
                                {
                                    System.Threading.Tasks.Task.Delay(throttlingWaitTimeMS.Value).Wait();
                                }
                            }
                            else
                            {
                                recipientFound = false;
                            }
                        }
                    }
                }
            }
        }
Example #14
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable().Include(a => a.CreatedByPersonAlias.Person).Include(a => a.CommunicationTemplate)
                                .FirstOrDefault(c => c.Id == communication.Id);

                // If there are no pending recipients than just exit the method
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    if (!qryRecipients
                        .Where(r =>
                               r.CommunicationId == communication.Id &&
                               r.Status == Model.CommunicationRecipientStatus.Pending &&
                               r.MediumEntityTypeId.HasValue &&
                               r.MediumEntityTypeId.Value == mediumEntityTypeId)
                        .Any())
                    {
                        return;
                    }
                }

                var    currentPerson      = communication.CreatedByPersonAlias?.Person;
                var    globalAttributes   = GlobalAttributesCache.Get();
                string publicAppRoot      = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                var    mergeFields        = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);
                var    cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false;

                string fromAddress = string.IsNullOrWhiteSpace(communication.FromEmail) ? globalAttributes.GetValue("OrganizationEmail") : communication.FromEmail;
                string fromName    = string.IsNullOrWhiteSpace(communication.FromName) ? globalAttributes.GetValue("OrganizationName") : communication.FromName;

                // Resolve any possible merge fields in the from address
                fromAddress = fromAddress.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);
                fromName    = fromName.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands);
                Parameter replyTo = new Parameter();

                // Reply To
                if (communication.ReplyToEmail.IsNotNullOrWhiteSpace())
                {
                    // Resolve any possible merge fields in the replyTo address
                    replyTo.Name  = "h:Reply-To";
                    replyTo.Type  = ParameterType.GetOrPost;
                    replyTo.Value = communication.ReplyToEmail.ResolveMergeFields(mergeFields, currentPerson);
                }

                var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                var communicationCategoryGuid = Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid();

                RestRequest restRequest = null;

                // Loop through recipients and send the email
                bool recipientFound = true;
                while (recipientFound)
                {
                    var recipientRockContext = new RockContext();
                    var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);

                    // This means we are done, break the loop
                    if (recipient == null)
                    {
                        recipientFound = false;
                        break;
                    }

                    // Not valid save the obj with the status messages then go to the next one
                    if (!ValidRecipient(recipient, communication.IsBulkCommunication))
                    {
                        recipientRockContext.SaveChanges();
                        continue;
                    }

                    try
                    {
                        // Create merge field dictionary
                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                        // Create the request obj
                        restRequest = new RestRequest(GetAttributeValue("Resource"), Method.POST);
                        restRequest.AddParameter("domian", GetAttributeValue("Domain"), ParameterType.UrlSegment);

                        // ReplyTo
                        if (communication.ReplyToEmail.IsNotNullOrWhiteSpace())
                        {
                            restRequest.AddParameter(replyTo);
                        }

                        // From
                        restRequest.AddParameter("from", new MailAddress(fromAddress, fromName).ToString());

                        // To
                        restRequest.AddParameter("to", new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName).ToString());

                        // Safe sender checks
                        CheckSafeSender(restRequest, fromAddress, globalAttributes.GetValue("OrganizationEmail"));

                        // CC
                        if (communication.CCEmails.IsNotNullOrWhiteSpace())
                        {
                            string[] ccRecipients = communication.CCEmails.ResolveMergeFields(mergeObjects, currentPerson).Replace(";", ",").Split(',');
                            foreach (var ccRecipient in ccRecipients)
                            {
                                restRequest.AddParameter("cc", ccRecipient);
                            }
                        }

                        // BCC
                        if (communication.BCCEmails.IsNotNullOrWhiteSpace())
                        {
                            string[] bccRecipients = communication.BCCEmails.ResolveMergeFields(mergeObjects, currentPerson).Replace(";", ",").Split(',');
                            foreach (var bccRecipient in bccRecipients)
                            {
                                restRequest.AddParameter("bcc", bccRecipient);
                            }
                        }

                        // Subject
                        string subject = ResolveText(communication.Subject, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                        restRequest.AddParameter("subject", subject);

                        // Body Plain Text
                        if (mediumAttributes.ContainsKey("DefaultPlainText"))
                        {
                            string plainText = ResolveText(mediumAttributes["DefaultPlainText"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                            if (!string.IsNullOrWhiteSpace(plainText))
                            {
                                AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainText, new ContentType(MediaTypeNames.Text.Plain));
                                restRequest.AddParameter("text", plainTextView);
                            }
                        }

                        // Body HTML
                        string htmlBody = communication.Message;

                        // Get the unsubscribe content and add a merge field for it
                        if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML"))
                        {
                            string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                            mergeObjects.AddOrReplace("UnsubscribeOption", unsubscribeHtml);
                            htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                            // Resolve special syntax needed if option was included in global attribute
                            if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]"))
                            {
                                htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml);
                            }

                            // Add the unsubscribe option at end if it wasn't included in content
                            if (!htmlBody.Contains(unsubscribeHtml))
                            {
                                htmlBody += unsubscribeHtml;
                            }
                        }
                        else
                        {
                            htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                            htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty);
                        }

                        if (!string.IsNullOrWhiteSpace(htmlBody))
                        {
                            if (cssInliningEnabled)
                            {
                                // move styles inline to help it be compatible with more email clients
                                htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes();
                            }

                            // add the main Html content to the email
                            restRequest.AddParameter("html", htmlBody);
                        }

                        // Headers
                        AddAdditionalHeaders(restRequest, new Dictionary <string, string>()
                        {
                            { "communication_recipient_guid", recipient.Guid.ToString() }
                        });

                        // Attachments
                        foreach (var attachment in communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile))
                        {
                            MemoryStream ms = new MemoryStream();
                            attachment.ContentStream.CopyTo(ms);
                            restRequest.AddFile("attachment", ms.ToArray(), attachment.FileName);
                        }

                        // Send the email
                        // Send it
                        RestClient restClient = new RestClient
                        {
                            BaseUrl       = new Uri(GetAttributeValue("BaseURL")),
                            Authenticator = new HttpBasicAuthenticator("api", GetAttributeValue("APIKey"))
                        };

                        // Call the API and get the response
                        Response = restClient.Execute(restRequest);

                        // Update recipient status and status note
                        recipient.Status     = Response.StatusCode == HttpStatusCode.OK ? CommunicationRecipientStatus.Delivered : CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = Response.StatusDescription;
                        recipient.TransportEntityTypeName = this.GetType().FullName;

                        // Log it
                        try
                        {
                            var historyChangeList = new History.HistoryChangeList();
                            historyChangeList.AddChange(
                                History.HistoryVerb.Sent,
                                History.HistoryChangeType.Record,
                                $"Communication")
                            .SetRelatedData(fromName, communicationEntityTypeId, communication.Id)
                            .SetCaption(subject);

                            HistoryService.SaveChanges(recipientRockContext, typeof(Rock.Model.Person), communicationCategoryGuid, recipient.PersonAlias.PersonId, historyChangeList, false, communication.SenderPersonAliasId);
                        }
                        catch (Exception ex)
                        {
                            ExceptionLogService.LogException(ex, null);
                        }
                    }
                    catch (Exception ex)
                    {
                        ExceptionLogService.LogException(ex);
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => ");
                    }

                    recipientRockContext.SaveChanges();
                }
            }
        }
Example #15
0
 public override string GetMessageDetails(Model.Communication communication)
 {
     throw new NotSupportedException();
 }
Example #16
0
 public override string GetHtmlPreview(Model.Communication communication, Person person)
 {
     throw new NotSupportedException();
 }
Example #17
0
 /// <summary>
 /// Sends the specified communication.
 /// </summary>
 /// <param name="communication">The communication.</param>
 /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
 /// <param name="mediumAttributes">The medium attributes.</param>
 public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
 {
     AsyncHelper.RunSync(() => SendAsync(communication, mediumEntityTypeId, mediumAttributes));
 }
Example #18
0
        /// <summary>
        /// Gets the HTML preview.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="person">The person.</param>
        /// <returns></returns>
        public override string GetHtmlPreview(Model.Communication communication, Person person)
        {
            var rockContext = new RockContext();

            StringBuilder sbContent = new StringBuilder();

            var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read();
            var mergeFields      = Rock.Lava.LavaHelper.GetCommonMergeFields(null);

            // Requery the Communication object
            communication = new CommunicationService(rockContext).Get(communication.Id);
            mergeFields.Add("Communication", communication);

            if (person != null)
            {
                mergeFields.Add("Person", person);

                var recipient = new CommunicationRecipientService(rockContext).Queryable().Where(a => a.CommunicationId == communication.Id).Where(r => r.PersonAlias != null && r.PersonAlias.PersonId == person.Id).FirstOrDefault();
                if (recipient != null)
                {
                    // Add any additional merge fields created through a report
                    foreach (var mergeField in recipient.AdditionalMergeValues)
                    {
                        if (!mergeFields.ContainsKey(mergeField.Key))
                        {
                            mergeFields.Add(mergeField.Key, mergeField.Value);
                        }
                    }
                }
            }

            // Body
            string htmlContent = communication.GetMediumDataValue("HtmlMessage");

            sbContent.Append(Email.ProcessHtmlBody(communication, globalAttributes, mergeFields));

            // Attachments
            StringBuilder sbAttachments = new StringBuilder();
            string        attachmentIds = communication.GetMediumDataValue("Attachments");

            if (!string.IsNullOrWhiteSpace(attachmentIds))
            {
                sbContent.Append("<br/><br/>");

                var binaryFileService = new BinaryFileService(rockContext);

                foreach (string idVal in attachmentIds.SplitDelimitedValues())
                {
                    int binaryFileId = int.MinValue;
                    if (int.TryParse(idVal, out binaryFileId))
                    {
                        var binaryFile = binaryFileService.Get(binaryFileId);
                        if (binaryFile != null)
                        {
                            sbContent.AppendFormat("<a target='_blank' href='{0}GetFile.ashx?id={1}'>{2}</a><br/>",
                                                   System.Web.VirtualPathUtility.ToAbsolute("~"), binaryFile.Id, binaryFile.FileName);
                        }
                    }
                }
            }

            return(sbContent.ToString());
        }
Example #19
0
        /// <summary>
        /// Sends the asynchronous.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <returns></returns>
        /// <exception cref="System.NotImplementedException"></exception>
        public async Task SendAsync(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            var    fromPhone = string.Empty;
            var    unprocessedRecipientCount = 0;
            var    mergeFields               = new Dictionary <string, object>();
            Person currentPerson             = null;
            var    attachmentMediaUrls       = new List <Uri>();
            var    personEntityTypeId        = 0;
            var    communicationCategoryId   = 0;
            var    communicationEntityTypeId = 0;

            using (var rockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(rockContext).Get(communication.Id);

                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(rockContext).Queryable();
                    unprocessedRecipientCount = qryRecipients
                                                .Where(r =>
                                                       r.CommunicationId == communication.Id &&
                                                       r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                       r.MediumEntityTypeId.HasValue &&
                                                       r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                                .Count();
                }

                if (unprocessedRecipientCount == 0)
                {
                    return;
                }

                fromPhone = communication.SMSFromDefinedValue?.Value;
                if (string.IsNullOrWhiteSpace(fromPhone))
                {
                    // just in case we got this far without a From Number, throw an exception
                    throw new Exception("A From Number was not provided for communication: " + communication.Id.ToString());
                }

                currentPerson = communication.CreatedByPersonAlias?.Person;
                mergeFields   = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                personEntityTypeId        = EntityTypeCache.Get <Person>().Id;
                communicationEntityTypeId = EntityTypeCache.Get <Model.Communication>().Id;
                communicationCategoryId   = CategoryCache.Get(SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext).Id;
                var smsAttachmentsBinaryFileIdList = communication.GetAttachmentBinaryFileIds(CommunicationType.SMS);

                if (smsAttachmentsBinaryFileIdList.Any())
                {
                    attachmentMediaUrls = this.GetAttachmentMediaUrls(new BinaryFileService(rockContext).GetByIds(smsAttachmentsBinaryFileIdList));
                }
            }

            int?throttlingWaitTimeMS = null;

            if (this.IsLongCodePhoneNumber(fromPhone))
            {
                throttlingWaitTimeMS = GetAttributeValue(TwilioAttributeKey.LongCodeThrottling).AsIntegerOrNull();
            }

            var    globalAttributes = GlobalAttributesCache.Get();
            string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot");
            var    callbackUrl      = publicAppRoot + "Webhooks/Twilio.ashx";

            var accountSid = GetAttributeValue(TwilioAttributeKey.Sid);
            var authToken  = GetAttributeValue(TwilioAttributeKey.AuthToken);

            TwilioClient.Init(accountSid, authToken);

            if (throttlingWaitTimeMS.HasValue)
            {
                // If throttlingWaitTime has a value we need to send all text synchronously so that the throttle is respected.
                var recipientFound = true;
                while (recipientFound)
                {
                    // make a new rockContext per recipient
                    var recipient = GetNextPending(communication.Id, mediumEntityTypeId, communication.IsBulkCommunication);

                    // This means we are done, break the loop
                    if (recipient == null)
                    {
                        recipientFound = false;
                        continue;
                    }

                    await SendToCommunicationRecipient(communication, fromPhone, mergeFields, currentPerson, attachmentMediaUrls, personEntityTypeId, communicationCategoryId, communicationEntityTypeId, publicAppRoot, callbackUrl, recipient).ConfigureAwait(false);

                    await Task.Delay(throttlingWaitTimeMS.Value).ConfigureAwait(false);
                }
            }
            else
            {
                var sendingTask        = new List <Task>(unprocessedRecipientCount);
                var asyncTransport     = this as IAsyncTransport;
                var maxParallelization = asyncTransport?.MaxParallelization ?? 10;

                using (var mutex = new SemaphoreSlim(maxParallelization))
                {
                    var recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipient = GetNextPending(communication.Id, mediumEntityTypeId, communication.IsBulkCommunication);

                        // This means we are done, break the loop
                        if (recipient == null)
                        {
                            recipientFound = false;
                            continue;
                        }

                        await mutex.WaitAsync().ConfigureAwait(false);

                        sendingTask.Add(ThrottleHelper.ThrottledExecute(() => SendToCommunicationRecipient(communication, fromPhone, mergeFields, currentPerson, attachmentMediaUrls, personEntityTypeId, communicationCategoryId, communicationEntityTypeId, publicAppRoot, callbackUrl, recipient), mutex));
                    }

                    /*
                     * Now that we have fired off all of the task, we need to wait for them to complete.
                     * Once all of the task have been completed we can continue.
                     */
                    while (sendingTask.Count > 0)
                    {
                        var completedTask = await Task.WhenAny(sendingTask).ConfigureAwait(false);

                        sendingTask.Remove(completedTask);
                    }
                }
            }
        }
Example #20
0
        /// <summary>
        /// Sends the specified communication from the Communication Wizard in Rock.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();
                    var    mergeFields      = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                if (recipient.PersonAliasId.HasValue)
                                {
                                    try
                                    {
                                        var             mergeObjects = recipient.CommunicationMergeValues(mergeFields);
                                        var             message      = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var             title        = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var             sound        = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var             data         = ResolveText(communication.PushData, currentPerson, communication.EnabledLavaCommands, mergeFields, publicAppRoot);
                                        var             jsonData     = Newtonsoft.Json.JsonConvert.DeserializeObject <PushData>(data);
                                        var             url          = jsonData.Url;
                                        string          appId        = GetAttributeValue("AppId");
                                        string          restApiKey   = GetAttributeValue("RestAPIKey");
                                        OneSignalClient client       = new OneSignalClient(restApiKey);

                                        var options = new NotificationCreateOptions
                                        {
                                            AppId = new Guid(appId),
                                            IncludeExternalUserIds = new List <string> {
                                                recipient.PersonAliasId.ToString()
                                            }
                                        };

                                        options.Headings.Add(LanguageCodes.English, title);
                                        options.Contents.Add(LanguageCodes.English, message);
                                        options.Url = url;
                                        NotificationCreateResult response = client.Notifications.Create(options);

                                        bool failed = !string.IsNullOrWhiteSpace(response.Error);

                                        var status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered;

                                        if (failed)
                                        {
                                            recipient.StatusNote = "OneSignal failed to notify devices";
                                        }
                                        else
                                        {
                                            recipient.SendDateTime = RockDateTime.Now;
                                        }

                                        recipient.Status = status;
                                        recipient.TransportEntityTypeName = this.GetType().FullName;
                                        recipient.UniqueMessageId         = response.Id;

                                        try
                                        {
                                            var historyService = new HistoryService(recipientRockContext);
                                            historyService.Add(new History
                                            {
                                                CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                EntityTypeId           = personEntityTypeId,
                                                CategoryId             = communicationCategoryId,
                                                EntityId            = recipient.PersonAlias.PersonId,
                                                Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                ValueName           = "Push Notification",
                                                Caption             = message.Truncate(200),
                                                RelatedEntityTypeId = communicationEntityTypeId,
                                                RelatedEntityId     = communication.Id
                                            });
                                        }
                                        catch (Exception ex)
                                        {
                                            ExceptionLogService.LogException(ex, null);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "OneSignal Exception: " + ex.Message;
                                    }
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
Example #21
0
 public abstract string GetHtmlPreview(Model.Communication communication, Person person);
Example #22
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        public override void Send(Model.Communication communication)
        {
            var rockContext          = new RockContext();
            var communicationService = new CommunicationService(rockContext);

            communication = communicationService.Queryable()
                            .FirstOrDefault(t => t.Id == communication.Id);

            if (communication != null &&
                communication.Status == Model.CommunicationStatus.Approved &&
                communication.HasPendingRecipients(rockContext) &&
                (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
            {
                // Update any recipients that should not get sent the communication
                var recipientService = new CommunicationRecipientService(rockContext);
                foreach (var recipient in recipientService.Queryable("PersonAlias.Person")
                         .Where(r =>
                                r.CommunicationId == communication.Id &&
                                r.Status == CommunicationRecipientStatus.Pending)
                         .ToList())
                {
                    var person = recipient.PersonAlias.Person;
                    if (!person.IsEmailActive)
                    {
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "Email is not active!";
                    }
                    if (person.IsDeceased)
                    {
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "Person is deceased!";
                    }
                    if (person.EmailPreference == Model.EmailPreference.DoNotEmail)
                    {
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "Email Preference of 'Do Not Email!'";
                    }
                    else if (person.EmailPreference == Model.EmailPreference.NoMassEmails && communication.IsBulkCommunication)
                    {
                        recipient.Status     = CommunicationRecipientStatus.Failed;
                        recipient.StatusNote = "Email Preference of 'No Mass Emails!'";
                    }
                }

                // If an unsubscribe value has been entered, and this is a bulk email, add the text
                if (communication.IsBulkCommunication)
                {
                    string unsubscribeHtml = GetAttributeValue("UnsubscribeHTML");
                    if (!string.IsNullOrWhiteSpace(unsubscribeHtml))
                    {
                        communication.SetMediumDataValue("UnsubscribeHTML", unsubscribeHtml);
                    }
                }

                string defaultPlainText = GetAttributeValue("DefaultPlainText");
                if (!string.IsNullOrWhiteSpace(defaultPlainText))
                {
                    communication.SetMediumDataValue("DefaultPlainText", defaultPlainText);
                }

                rockContext.SaveChanges();
            }

            base.Send(communication);
        }
Example #23
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            var pushData = communication.PushData.FromJsonOrNull <PushData>();

            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable("CreatedByPersonAlias.Person")
                                .FirstOrDefault(c => c.Id == communication.Id);

                bool hasPendingRecipients;
                if (communication != null &&
                    communication.Status == Model.CommunicationStatus.Approved &&
                    (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0))
                {
                    var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable();
                    hasPendingRecipients = qryRecipients
                                           .Where(r =>
                                                  r.CommunicationId == communication.Id &&
                                                  r.Status == Model.CommunicationRecipientStatus.Pending &&
                                                  r.MediumEntityTypeId.HasValue &&
                                                  r.MediumEntityTypeId.Value == mediumEntityTypeId)
                                           .Any();
                }
                else
                {
                    hasPendingRecipients = false;
                }

                if (hasPendingRecipients)
                {
                    var    currentPerson    = communication.CreatedByPersonAlias?.Person;
                    var    globalAttributes = GlobalAttributesCache.Get();
                    string publicAppRoot    = globalAttributes.GetValue("PublicApplicationRoot");
                    var    mergeFields      = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson);

                    string serverKey = GetAttributeValue("ServerKey");
                    var    sender    = new Sender(serverKey);

                    var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                    var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                    var communicationCategoryId   = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), communicationRockContext).Id;

                    bool recipientFound = true;
                    while (recipientFound)
                    {
                        // make a new rockContext per recipient
                        var recipientRockContext = new RockContext();
                        var recipient            = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);
                        if (recipient != null)
                        {
                            if (ValidRecipient(recipient, communication.IsBulkCommunication))
                            {
                                try
                                {
                                    var           siteId  = pushData?.MobileApplicationId;
                                    List <string> devices = null;

                                    if (recipient.PersonAliasId.HasValue)
                                    {
                                        int personAliasId = recipient.PersonAliasId.Value;
                                        var service       = new PersonalDeviceService(recipientRockContext);

                                        devices = service.Queryable()
                                                  .Where(p => p.PersonAliasId.HasValue && p.PersonAliasId.Value == personAliasId && p.NotificationsEnabled && !string.IsNullOrEmpty(p.DeviceRegistrationId))
                                                  .Where(p => !siteId.HasValue || siteId.Value == p.SiteId)
                                                  .Select(p => p.DeviceRegistrationId)
                                                  .ToList();
                                    }
                                    else if (!string.IsNullOrEmpty(recipient.PersonalDevice?.DeviceRegistrationId))
                                    {
                                        devices = new List <string> {
                                            recipient.PersonalDevice?.DeviceRegistrationId
                                        };
                                    }

                                    if (devices != null && devices.Any())
                                    {
                                        // Create merge field dictionary
                                        var mergeObjects = recipient.CommunicationMergeValues(mergeFields);

                                        var message = ResolveText(communication.PushMessage, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var title   = ResolveText(communication.PushTitle, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);
                                        var sound   = ResolveText(communication.PushSound, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot);

                                        var notification = new Message
                                        {
                                            RegistrationIds = devices.Distinct().ToList(),
                                            Notification    = new FCM.Net.Notification
                                            {
                                                Title = title,
                                                Body  = message,
                                                Sound = sound,
                                            },
                                            Data = GetPushNotificationData(communication.PushOpenAction, pushData, recipient)
                                        };

                                        ResponseContent response = Utility.AsyncHelpers.RunSync(() => sender.SendAsync(notification));

                                        bool failed = response.MessageResponse.Failure == devices.Count || response.MessageResponse.Success == 0;
                                        var  status = failed ? CommunicationRecipientStatus.Failed : CommunicationRecipientStatus.Delivered;

                                        if (failed)
                                        {
                                            recipient.StatusNote = "Firebase failed to notify devices";
                                        }
                                        else
                                        {
                                            recipient.SendDateTime = RockDateTime.Now;
                                        }

                                        recipient.Status = status;
                                        recipient.TransportEntityTypeName = this.GetType().FullName;
                                        recipient.UniqueMessageId         = response.MessageResponse.MulticastId;

                                        if (recipient.PersonAlias != null)
                                        {
                                            try
                                            {
                                                var historyService = new HistoryService(recipientRockContext);
                                                historyService.Add(new History
                                                {
                                                    CreatedByPersonAliasId = communication.SenderPersonAliasId,
                                                    EntityTypeId           = personEntityTypeId,
                                                    CategoryId             = communicationCategoryId,
                                                    EntityId            = recipient.PersonAlias.PersonId,
                                                    Verb                = History.HistoryVerb.Sent.ConvertToString().ToUpper(),
                                                    ChangeType          = History.HistoryChangeType.Record.ToString(),
                                                    ValueName           = "Push Notification",
                                                    Caption             = message.Truncate(200),
                                                    RelatedEntityTypeId = communicationEntityTypeId,
                                                    RelatedEntityId     = communication.Id
                                                });
                                            }
                                            catch (Exception ex)
                                            {
                                                ExceptionLogService.LogException(ex, null);
                                            }
                                        }
                                    }
                                    else
                                    {
                                        recipient.Status     = CommunicationRecipientStatus.Failed;
                                        recipient.StatusNote = "No Personal Devices with Messaging Enabled";
                                    }
                                }
                                catch (Exception ex)
                                {
                                    recipient.Status     = CommunicationRecipientStatus.Failed;
                                    recipient.StatusNote = "Firebase Exception: " + ex.Message;
                                }
                            }

                            recipientRockContext.SaveChanges();
                        }
                        else
                        {
                            recipientFound = false;
                        }
                    }
                }
            }
        }
Example #24
0
        private RockEmailMessage GetRecipientRockEmailMessage(RockEmailMessage emailMessage, Model.Communication communication, CommunicationRecipient communicationRecipient, Dictionary <string, object> mergeFields, string organizationEmail, Dictionary <string, string> mediumAttributes)
        {
            var recipientEmail = new RockEmailMessage();

            recipientEmail.CurrentPerson       = emailMessage.CurrentPerson;
            recipientEmail.EnabledLavaCommands = emailMessage.EnabledLavaCommands;
            recipientEmail.AppRoot             = emailMessage.AppRoot;
            recipientEmail.CssInliningEnabled  = emailMessage.CssInliningEnabled;

            // CC
            if (communication.CCEmails.IsNotNullOrWhiteSpace())
            {
                string[] ccRecipients = communication
                                        .CCEmails
                                        .ResolveMergeFields(mergeFields, emailMessage.CurrentPerson)
                                        .Replace(";", ",")
                                        .Split(',');

                foreach (var ccRecipient in ccRecipients)
                {
                    recipientEmail.CCEmails.Add(ccRecipient);
                }
            }

            // BCC
            if (communication.BCCEmails.IsNotNullOrWhiteSpace())
            {
                string[] bccRecipients = communication
                                         .BCCEmails
                                         .ResolveMergeFields(mergeFields, emailMessage.CurrentPerson)
                                         .Replace(";", ",")
                                         .Split(',');

                foreach (var bccRecipient in bccRecipients)
                {
                    recipientEmail.BCCEmails.Add(bccRecipient);
                }
            }

            // Attachments
            recipientEmail.Attachments = emailMessage.Attachments;

            // Communication record for tracking opens & clicks
            recipientEmail.MessageMetaData = new Dictionary <string, string>(emailMessage.MessageMetaData);

            // To
            var toEmailAddress = new RockEmailMessageRecipient(null, null)
            {
                To   = communicationRecipient.PersonAlias.Person.Email,
                Name = communicationRecipient.PersonAlias.Person.FullName
            };

            recipientEmail.SetRecipients(new List <RockEmailMessageRecipient> {
                toEmailAddress
            });

            var fromMailAddress = new MailAddress(emailMessage.FromEmail, emailMessage.FromName);
            var checkResult     = CheckSafeSender(new List <string> {
                toEmailAddress.EmailAddress
            }, fromMailAddress, organizationEmail);

            // Reply To
            recipientEmail.ReplyToEmail = GetRecipientReplyToAddress(emailMessage, mergeFields, checkResult);

            // From
            if (checkResult.IsUnsafeDomain && checkResult.SafeFromAddress != null)
            {
                recipientEmail.FromName  = checkResult.SafeFromAddress.DisplayName;
                recipientEmail.FromEmail = checkResult.SafeFromAddress.Address;
            }
            else
            {
                recipientEmail.FromName  = fromMailAddress.DisplayName;
                recipientEmail.FromEmail = fromMailAddress.Address;
            }

            // Subject
            var subject = ResolveText(communication.Subject, emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot);

            recipientEmail.Subject = subject;

            // Body Plain Text
            if (mediumAttributes.ContainsKey("DefaultPlainText"))
            {
                var plainText = ResolveText(mediumAttributes["DefaultPlainText"],
                                            emailMessage.CurrentPerson,
                                            communication.EnabledLavaCommands,
                                            mergeFields,
                                            emailMessage.AppRoot);

                if (!string.IsNullOrWhiteSpace(plainText))
                {
                    recipientEmail.PlainTextMessage = plainText;
                }
            }

            // Body (HTML)
            string htmlBody = communication.Message;

            // Get the unsubscribe content and add a merge field for it
            if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML"))
            {
                string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"],
                                                     emailMessage.CurrentPerson,
                                                     communication.EnabledLavaCommands,
                                                     mergeFields,
                                                     emailMessage.AppRoot);

                mergeFields.AddOrReplace("UnsubscribeOption", unsubscribeHtml);

                htmlBody = ResolveText(htmlBody, emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot);

                // Resolve special syntax needed if option was included in global attribute
                if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]"))
                {
                    htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml);
                }

                // Add the unsubscribe option at end if it wasn't included in content
                if (!htmlBody.Contains(unsubscribeHtml))
                {
                    htmlBody += unsubscribeHtml;
                }
            }
            else
            {
                htmlBody = ResolveText(htmlBody, emailMessage.CurrentPerson, communication.EnabledLavaCommands, mergeFields, emailMessage.AppRoot);
                htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty);
            }

            if (!string.IsNullOrWhiteSpace(htmlBody))
            {
                if (emailMessage.CssInliningEnabled)
                {
                    // move styles inline to help it be compatible with more email clients
                    htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes();
                }

                // add the main Html content to the email
                recipientEmail.Message = htmlBody;
            }

            recipientEmail.MessageMetaData["communication_recipient_guid"] = communicationRecipient.Guid.ToString();

            return(recipientEmail);
        }
Example #25
0
 /// <summary>
 /// Sends the specified communication.
 /// </summary>
 /// <param name="communication">The communication.</param>
 /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
 /// <param name="mediumAttributes">The medium attributes.</param>
 public abstract void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes);
Example #26
0
 public abstract void Send(Model.Communication communication);
Example #27
0
 public abstract string GetMessageDetails(Model.Communication communication);
Example #28
0
        /// <summary>
        /// Sends the specified communication.
        /// </summary>
        /// <param name="communication">The communication.</param>
        /// <param name="mediumEntityTypeId">The medium entity type identifier.</param>
        /// <param name="mediumAttributes">The medium attributes.</param>
        public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes)
        {
            using (var communicationRockContext = new RockContext())
            {
                // Requery the Communication
                communication = new CommunicationService(communicationRockContext)
                                .Queryable()
                                .Include(a => a.CreatedByPersonAlias.Person)
                                .Include(a => a.CommunicationTemplate)
                                .FirstOrDefault(c => c.Id == communication.Id);

                var isApprovedCommunication = communication != null && communication.Status == Model.CommunicationStatus.Approved;
                var isReadyToSend           = communication != null &&
                                              (!communication.FutureSendDateTime.HasValue ||
                                               communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0);

                if (!isApprovedCommunication || !isReadyToSend)
                {
                    return;
                }

                // If there are no pending recipients than just exit the method
                var communicationRecipientService = new CommunicationRecipientService(communicationRockContext);

                var hasUnprocessedRecipients = communicationRecipientService
                                               .Queryable()
                                               .ByCommunicationId(communication.Id)
                                               .ByStatus(CommunicationRecipientStatus.Pending)
                                               .ByMediumEntityTypeId(mediumEntityTypeId)
                                               .Any();

                if (!hasUnprocessedRecipients)
                {
                    return;
                }

                var currentPerson = communication.CreatedByPersonAlias?.Person;
                var mergeFields   = GetAllMergeFields(currentPerson, communication.AdditionalLavaFields);

                var globalAttributes = GlobalAttributesCache.Get();

                var templateEmailMessage = GetTemplateRockEmailMessage(communication, mergeFields, globalAttributes);
                var organizationEmail    = globalAttributes.GetValue("OrganizationEmail");

                var publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash();

                var cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false;

                var personEntityTypeId        = EntityTypeCache.Get("Rock.Model.Person").Id;
                var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id;
                var communicationCategoryGuid = Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid();

                // Loop through recipients and send the email
                var recipientFound = true;
                while (recipientFound)
                {
                    using (var recipientRockContext = new RockContext())
                    {
                        var recipient = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext);

                        // This means we are done, break the loop
                        if (recipient == null)
                        {
                            recipientFound = false;
                            break;
                        }

                        // Not valid save the obj with the status messages then go to the next one
                        if (!ValidRecipient(recipient, communication.IsBulkCommunication))
                        {
                            recipientRockContext.SaveChanges();
                            continue;
                        }

                        try
                        {
                            // Create merge field dictionary
                            var mergeObjects          = recipient.CommunicationMergeValues(mergeFields);
                            var recipientEmailMessage = GetRecipientRockEmailMessage(templateEmailMessage, communication, recipient, mergeObjects, organizationEmail, mediumAttributes);

                            var result = SendEmail(recipientEmailMessage);

                            // Update recipient status and status note
                            recipient.Status     = result.Status;
                            recipient.StatusNote = result.StatusNote;
                            recipient.TransportEntityTypeName = this.GetType().FullName;

                            // Log it
                            try
                            {
                                var historyChangeList = new History.HistoryChangeList();
                                historyChangeList.AddChange(
                                    History.HistoryVerb.Sent,
                                    History.HistoryChangeType.Record,
                                    $"Communication")
                                .SetRelatedData(recipientEmailMessage.FromName, communicationEntityTypeId, communication.Id)
                                .SetCaption(recipientEmailMessage.Subject);

                                HistoryService.SaveChanges(recipientRockContext, typeof(Rock.Model.Person), communicationCategoryGuid, recipient.PersonAlias.PersonId, historyChangeList, false, communication.SenderPersonAliasId);
                            }
                            catch (Exception ex)
                            {
                                ExceptionLogService.LogException(ex, null);
                            }
                        }
                        catch (Exception ex)
                        {
                            ExceptionLogService.LogException(ex);
                            recipient.Status     = CommunicationRecipientStatus.Failed;
                            recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => ");
                        }

                        recipientRockContext.SaveChanges();
                    }
                }
            }
        }