protected void btnLookup_Click(object sender, EventArgs e) { if (!Page.IsValid) { return; } var ipLimit = GetAttributeValue(AttributeKey.IpThrottleLimit).AsInteger(); var messageTemplate = GetAttributeValue(AttributeKey.TextMessageTemplate); var fromNumber = GetAttributeValue(AttributeKey.SmsNumber); var phoneNumber = pbPhoneNumberLookup.Number; try { using (var rockContext = new RockContext()) { var identityVerificationService = new IdentityVerificationService(rockContext); var identityVerification = identityVerificationService.CreateIdentityVerificationRecord(Request.UserHostAddress, ipLimit, phoneNumber); var smsMessage = new RockSMSMessage { FromNumber = DefinedValueCache.Get(fromNumber), Message = messageTemplate, }; var mergeObjects = LavaHelper.GetCommonMergeFields(this.RockPage); mergeObjects.Add("ConfirmationCode", identityVerification.IdentityVerificationCode.Code); smsMessage.SetRecipients(new List <RockSMSMessageRecipient> { RockSMSMessageRecipient.CreateAnonymous(phoneNumber, mergeObjects) }); var errorList = new List <string>(); if (smsMessage.Send(out errorList)) { IdentityVerificationId = identityVerification.Id; ShowVerificationPage(); } else { ShowWarningMessage("Verification text message failed to send."); } } } catch (Exception ex) { ShowWarningMessage(ex.Message); RockLogger.Log.Error(RockLogDomains.Core, ex); ExceptionLogService.LogException(ex); } }
/// <summary> /// Sends an RSVP reminder email to an individual attendee. /// </summary> /// <param name="person">The <see cref="Person"/>.</param> /// <param name="reminder">The <see cref="SystemCommunication"/> to be sent as a reminder.</param> /// <param name="lavaMergeFields">A dictionary containing Lava merge fields.</param> /// <param name="smsNumber">The correctly formatted SMS Number for SMS communications.</param> /// <returns>1 if the communication was successfully sent, otherwise 0.</returns> private int SendReminderSMS(Person person, SystemCommunication reminder, Dictionary <string, object> lavaMergeFields, string smsNumber) { var recipient = new RockSMSMessageRecipient(person, smsNumber, lavaMergeFields); var message = new RockSMSMessage(reminder); message.SetRecipients(new List <RockSMSMessageRecipient>() { recipient }); message.Send(out List <string> smsErrors); if (!smsErrors.Any()) { return(1); // No error, this should be counted as a sent reminder. } return(0); }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public override bool Execute(RockContext rockContext, WorkflowAction action, object entity, out List <string> errorMessages) { errorMessages = new List <string>(); var mergeFields = GetMergeFields(action); // Get the From value int? fromId = null; Guid?fromGuid = GetAttributeValue(action, AttributeKey.FromFromDropDown).AsGuidOrNull(); if (fromGuid.HasValue) { var fromValue = DefinedValueCache.Get(fromGuid.Value, rockContext); if (fromValue != null) { fromId = fromValue.Id; } } if (!fromId.HasValue) { Guid fromGuidFromAttribute = GetAttributeValue(action, AttributeKey.FromFromAttribute).AsGuid(); fromGuid = action.GetWorkflowAttributeValue(fromGuidFromAttribute).AsGuidOrNull(); var fromValue = DefinedValueCache.Get(fromGuid.Value, rockContext); if (fromValue != null) { fromId = fromValue.Id; } } var smsFromDefinedValues = DefinedTypeCache.Get(SystemGuid.DefinedType.COMMUNICATION_SMS_FROM.AsGuid()).DefinedValues; // Now can we do our final check to ensure the guid is a valid SMS From Defined Value if (!fromId.HasValue || !smsFromDefinedValues.Any(a => a.Id == fromId)) { var msg = string.Format($"'From' could not be found for selected value ('{fromGuid}')"); errorMessages.Add(msg); action.AddLogEntry(msg, true); return(false); } // Get the recipients var recipients = new List <RockSMSMessageRecipient>(); string toValue = GetAttributeValue(action, "To"); Guid guid = toValue.AsGuid(); if (!guid.IsEmpty()) { var attribute = AttributeCache.Get(guid, rockContext); if (attribute != null) { string toAttributeValue = action.GetWorkflowAttributeValue(guid); if (!string.IsNullOrWhiteSpace(toAttributeValue)) { switch (attribute.FieldType.Class) { case "Rock.Field.Types.TextFieldType": { var smsNumber = toAttributeValue; recipients.Add(RockSMSMessageRecipient.CreateAnonymous(smsNumber, mergeFields)); break; } case "Rock.Field.Types.PersonFieldType": { Guid personAliasGuid = toAttributeValue.AsGuid(); if (!personAliasGuid.IsEmpty()) { var phoneNumber = new PersonAliasService(rockContext).Queryable() .Where(a => a.Guid.Equals(personAliasGuid)) .SelectMany(a => a.Person.PhoneNumbers) .Where(p => p.IsMessagingEnabled) .FirstOrDefault(); if (phoneNumber == null) { action.AddLogEntry("Invalid Recipient: Person or valid SMS phone number not found", true); } else { var person = new PersonAliasService(rockContext).GetPerson(personAliasGuid); var recipient = new RockSMSMessageRecipient(person, phoneNumber.ToSmsNumber(), mergeFields); recipients.Add(recipient); recipient.MergeFields.Add(recipient.PersonMergeFieldKey, person); } } break; } case "Rock.Field.Types.GroupFieldType": case "Rock.Field.Types.SecurityRoleFieldType": { int? groupId = toAttributeValue.AsIntegerOrNull(); Guid?groupGuid = toAttributeValue.AsGuidOrNull(); IQueryable <GroupMember> qry = null; // Handle situations where the attribute value is the ID if (groupId.HasValue) { qry = new GroupMemberService(rockContext).GetByGroupId(groupId.Value); } else if (groupGuid.HasValue) { // Handle situations where the attribute value stored is the Guid qry = new GroupMemberService(rockContext).GetByGroupGuid(groupGuid.Value); } else { action.AddLogEntry("Invalid Recipient: No valid group id or Guid", true); } if (qry != null) { foreach (var person in qry .Where(m => m.GroupMemberStatus == GroupMemberStatus.Active) .Select(m => m.Person)) { var phoneNumber = person.PhoneNumbers .Where(p => p.IsMessagingEnabled) .FirstOrDefault(); if (phoneNumber != null) { var recipientMergeFields = new Dictionary <string, object>(mergeFields); var recipient = new RockSMSMessageRecipient(person, phoneNumber.ToSmsNumber(), recipientMergeFields); recipients.Add(recipient); recipient.MergeFields.Add(recipient.PersonMergeFieldKey, person); } } } break; } } } } } else { if (!string.IsNullOrWhiteSpace(toValue)) { recipients.Add(RockSMSMessageRecipient.CreateAnonymous(toValue.ResolveMergeFields(mergeFields), mergeFields)); } } // Get the message from the Message attribute. // NOTE: Passing 'true' as the checkWorkflowAttributeValue will also check the workflow AttributeValue // which allows us to remove the unneeded code. string message = GetAttributeValue(action, "Message", checkWorkflowAttributeValue: true); // Add the attachment (if one was specified) var attachmentBinaryFileGuid = GetAttributeValue(action, "Attachment", true).AsGuidOrNull(); BinaryFile binaryFile = null; if (attachmentBinaryFileGuid.HasValue && attachmentBinaryFileGuid != Guid.Empty) { binaryFile = new BinaryFileService(rockContext).Get(attachmentBinaryFileGuid.Value); } // Send the message if (recipients.Any() && (!string.IsNullOrWhiteSpace(message) || binaryFile != null)) { var smsMessage = new RockSMSMessage(); smsMessage.SetRecipients(recipients); smsMessage.FromNumber = DefinedValueCache.Get(fromId.Value); smsMessage.Message = message; smsMessage.CreateCommunicationRecord = GetAttributeValue(action, "SaveCommunicationHistory").AsBoolean(); smsMessage.CommunicationName = action.ActionTypeCache.Name; if (binaryFile != null) { smsMessage.Attachments.Add(binaryFile); } smsMessage.Send(); } else { action.AddLogEntry("Warning: No text or attachment was supplied so nothing was sent.", true); } return(true); }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages) { errorMessages = new List <string>(); var mergeFields = GetMergeFields(action); // Get the From value. Can be in the form of Text, Phone Number, Person or Defined type string fromValue = string.Empty; int? fromId = null; fromValue = GetAttributeValue(action, "From", true); if (!string.IsNullOrWhiteSpace(fromValue)) { Guid?fromGuid = fromValue.AsGuidOrNull(); DefinedTypeCache smsPhoneNumbers = DefinedTypeCache.Get(Rock.SystemGuid.DefinedType.COMMUNICATION_SMS_FROM); // If fromGuid is null but fromValue is not, then this is a phone number (match it up with the value from the DefinedType) if (fromGuid == null) { try { fromValue = PhoneNumber.CleanNumber(fromValue); fromGuid = smsPhoneNumbers.DefinedValues.Where(dv => dv.Value.Right(10) == fromValue.Right(10)).Select(dv => dv.Guid).FirstOrDefault(); if (fromGuid == Guid.Empty) { action.AddLogEntry("Invalid sending number: Person or valid SMS phone number not found", true); } } catch (Exception e) { action.AddLogEntry("Invalid sending number: Person or valid SMS phone number not found", true); } } // At this point, fromGuid should either be a Person or a DefinedValue if (fromGuid.HasValue) { fromId = smsPhoneNumbers.DefinedValues.Where(dv => dv.Guid == fromGuid || dv.GetAttributeValue("ResponseRecipient") == fromGuid.ToString()).Select(dv => dv.Id).FirstOrDefault(); } } else { // The From number is required and was not entered action.AddLogEntry("Invalid sending number: Person or valid SMS phone number not found", true); } // Get the recipients, Can be in the form of Text, Phone Number, Person, Group or Security role var recipients = new List <RockSMSMessageRecipient>(); string toValue = GetAttributeValue(action, "To"); Guid guid = toValue.AsGuid(); if (!guid.IsEmpty()) { var attribute = AttributeCache.Get(guid, rockContext); if (attribute != null) { string toAttributeValue = action.GetWorklowAttributeValue(guid); if (!string.IsNullOrWhiteSpace(toAttributeValue)) { switch (attribute.FieldType.Class) { case "Rock.Field.Types.TextFieldType": case "Rock.Field.Types.PhoneNumberFieldType": { var smsNumber = toAttributeValue; smsNumber = PhoneNumber.CleanNumber(smsNumber); recipients.Add(RockSMSMessageRecipient.CreateAnonymous(smsNumber, mergeFields)); break; } case "Rock.Field.Types.PersonFieldType": { Guid personAliasGuid = toAttributeValue.AsGuid(); if (!personAliasGuid.IsEmpty()) { var phoneNumber = new PersonAliasService(rockContext).Queryable() .Where(a => a.Guid.Equals(personAliasGuid)) .SelectMany(a => a.Person.PhoneNumbers) .Where(p => p.IsMessagingEnabled) .FirstOrDefault(); if (phoneNumber == null) { action.AddLogEntry("Invalid Recipient: Person or valid SMS phone number not found", true); } else { var person = new PersonAliasService(rockContext).GetPerson(personAliasGuid); var recipient = new RockSMSMessageRecipient(person, phoneNumber.ToSmsNumber(), mergeFields); recipients.Add(recipient); recipient.MergeFields.Add(recipient.PersonMergeFieldKey, person); } } break; } case "Rock.Field.Types.GroupFieldType": case "Rock.Field.Types.SecurityRoleFieldType": { int? groupId = toAttributeValue.AsIntegerOrNull(); Guid?groupGuid = toAttributeValue.AsGuidOrNull(); IQueryable <GroupMember> qry = null; // Handle situations where the attribute value is the ID if (groupId.HasValue) { qry = new GroupMemberService(rockContext).GetByGroupId(groupId.Value); } // Handle situations where the attribute value stored is the Guid else if (groupGuid.HasValue) { qry = new GroupMemberService(rockContext).GetByGroupGuid(groupGuid.Value); } else { action.AddLogEntry("Invalid Recipient: No valid group id or Guid", true); } if (qry != null) { foreach (var person in qry .Where(m => m.GroupMemberStatus == GroupMemberStatus.Active) .Select(m => m.Person)) { var phoneNumber = person.PhoneNumbers .Where(p => p.IsMessagingEnabled) .FirstOrDefault(); if (phoneNumber != null) { var recipientMergeFields = new Dictionary <string, object>(mergeFields); var recipient = new RockSMSMessageRecipient(person, phoneNumber.ToSmsNumber(), recipientMergeFields); recipients.Add(recipient); recipient.MergeFields.Add(recipient.PersonMergeFieldKey, person); } } } break; } } } } } else { if (!string.IsNullOrWhiteSpace(toValue)) { recipients.Add(RockSMSMessageRecipient.CreateAnonymous(toValue.ResolveMergeFields(mergeFields), mergeFields)); } } // Get the message from the Message attribute. // NOTE: Passing 'true' as the checkWorkflowAttributeValue will also check the workflow AttributeValue // which allows us to remove the unneeded code. string message = GetAttributeValue(action, "Message", checkWorkflowAttributeValue: true); // Add the attachment (if one was specified) var attachmentBinaryFileGuid = GetAttributeValue(action, "Attachment", true).AsGuidOrNull(); BinaryFile binaryFile = null; if (attachmentBinaryFileGuid.HasValue && attachmentBinaryFileGuid != Guid.Empty) { binaryFile = new BinaryFileService(rockContext).Get(attachmentBinaryFileGuid.Value); } // Send the message if (recipients.Any() && (!string.IsNullOrWhiteSpace(message) || binaryFile != null)) { var smsMessage = new RockSMSMessage(); smsMessage.SetRecipients(recipients); smsMessage.FromNumber = DefinedValueCache.Get(fromId.Value); smsMessage.Message = message; smsMessage.CreateCommunicationRecord = GetAttributeValue(action, "SaveCommunicationHistory").AsBoolean(); smsMessage.communicationName = action.ActionTypeCache.Name; if (binaryFile != null) { smsMessage.Attachments.Add(binaryFile); } smsMessage.Send(); } else { action.AddLogEntry("Warning: No text or attachment was supplied so nothing was sent.", true); } return(true); }
protected void btnGenerate_Click(object sender, EventArgs e) { if (!Page.IsValid) { return; } pnlPhoneNumber.Visible = false; RockContext rockContext = new RockContext(); PhoneNumberService phoneNumberService = new PhoneNumberService(rockContext); var numberOwners = phoneNumberService.Queryable() .Where(pn => pn.Number == PhoneNumber) .Select(pn => pn.Person) .DistinctBy(p => p.Id) .ToList(); if (numberOwners.Count == 0) { lbNoNumber.Text = GetAttributeValue("NoNumberMessage"); pnlNoNumber.Visible = true; return; } if (numberOwners.Count > 1) { if (GetAttributeValue("DuplicateNumberPage").AsGuidOrNull() == null) { btnResolution.Visible = false; } lbDuplicateNumber.Text = GetAttributeValue("DuplicateMessage"); pnlDuplicateNumber.Visible = true; return; } var person = numberOwners.FirstOrDefault(); UserLoginService userLoginService = new UserLoginService(rockContext); var userLogin = userLoginService.Queryable() .Where(u => u.UserName == ("__PHONENUMBER__" + PhoneNumber)) .FirstOrDefault(); if (userLogin == null) { var entityTypeId = EntityTypeCache.Get("Avalanche.Security.Authentication.PhoneNumber").Id; userLogin = new UserLogin() { UserName = "******" + PhoneNumber, EntityTypeId = entityTypeId, }; userLoginService.Add(userLogin); } userLogin.PersonId = person.Id; userLogin.LastPasswordChangedDateTime = Rock.RockDateTime.Now; userLogin.FailedPasswordAttemptWindowStartDateTime = Rock.RockDateTime.Now; userLogin.FailedPasswordAttemptCount = 0; userLogin.IsConfirmed = true; userLogin.Password = new Random().Next(100000, 999999).ToString(); rockContext.SaveChanges(); var recipients = new List <RockMessageRecipient>(); recipients.Add(RockSMSMessageRecipient.CreateAnonymous(PhoneNumber, null)); var smsMessage = new RockSMSMessage(); smsMessage.SetRecipients(recipients); // Get the From value Guid?fromGuid = GetAttributeValue("From").AsGuidOrNull(); if (fromGuid.HasValue) { var fromValue = DefinedValueCache.Get(fromGuid.Value, rockContext); if (fromValue != null) { smsMessage.FromNumber = DefinedValueCache.Get(fromValue.Id); } } var mergeObjects = new Dictionary <string, object> { { "password", userLogin.Password } }; var message = GetAttributeValue("Message").ResolveMergeFields(mergeObjects, null); smsMessage.Message = message; var ipAddress = GetIpAddress(); if (SMSRecords.ReserveItems(ipAddress, PhoneNumber)) { pnlCode.Visible = true; var delay = SMSRecords.GetDelay(ipAddress, PhoneNumber); Task.Run(() => { SendSMS(smsMessage, ipAddress, PhoneNumber, delay); }); } else { LogException(new Exception(string.Format("Unable to reserve for SMS message: IP: {0} PhoneNumber: {1}", ipAddress, PhoneNumber))); pnlRateLimited.Visible = true; } }
/// <summary> /// Creates the user login for the SMS message and send the text message with the code /// </summary> /// <param name="phoneNumber"></param> /// <returns></returns> public bool SendSMSAuthentication(string phoneNumber) { RockContext rockContext = new RockContext(); string error; var person = GetNumberOwner(phoneNumber, rockContext, out error); if (person == null) { return(false); } UserLoginService userLoginService = new UserLoginService(rockContext); var userLogin = userLoginService.Queryable() .Where(u => u.UserName == ("SMS_" + person.Id.ToString())) .FirstOrDefault(); //Create user login if does not exist if (userLogin == null) { var entityTypeId = EntityTypeCache.Get("Rock.Security.ExternalAuthentication.SMSAuthentication").Id; userLogin = new UserLogin() { UserName = "******" + person.Id.ToString(), EntityTypeId = entityTypeId, }; userLoginService.Add(userLogin); } //Update user login userLogin.PersonId = person.Id; userLogin.LastPasswordChangedDateTime = Rock.RockDateTime.Now; userLogin.FailedPasswordAttemptWindowStartDateTime = Rock.RockDateTime.Now; userLogin.FailedPasswordAttemptCount = 0; userLogin.IsConfirmed = true; var password = new Random().Next(100000, 999999).ToString(); userLogin.Password = EncodeBcrypt(password); rockContext.SaveChanges(); var recipients = new List <RockSMSMessageRecipient>(); recipients.Add(RockSMSMessageRecipient.CreateAnonymous(phoneNumber, null)); var smsMessage = new RockSMSMessage { CreateCommunicationRecord = false }; smsMessage.SetRecipients(recipients); // Get the From value Guid?fromGuid = GetAttributeValue("From").AsGuidOrNull(); if (fromGuid.HasValue) { var fromValue = DefinedValueCache.Get(fromGuid.Value, rockContext); if (fromValue != null) { smsMessage.FromNumber = DefinedValueCache.Get(fromValue.Id, rockContext); } } smsMessage.AdditionalMergeFields = new Dictionary <string, object> { { "password", password } }; smsMessage.Message = GetAttributeValue("Message"); var ipAddress = GetIpAddress(); //Reserve items rate limits the text messages if (SMSRecords.ReserveItems(ipAddress, phoneNumber)) { var delay = SMSRecords.GetDelay(ipAddress, phoneNumber); Task.Run(() => { SendSMS(smsMessage, ipAddress, phoneNumber, delay); }); } else { ExceptionLogService.LogException(new Exception(string.Format("Rate limiting reached for SMS authentication: IP: {0} PhoneNumber: {1}", ipAddress, phoneNumber))); } return(true); }