/// <summary> /// Adds the changes. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="modelType">Type of the model.</param> /// <param name="categoryGuid">The category unique identifier.</param> /// <param name="entityId">The entity identifier.</param> /// <param name="changes">The changes.</param> /// <param name="caption">The caption.</param> /// <param name="relatedModelType">Type of the related model.</param> /// <param name="relatedEntityId">The related entity identifier.</param> /// <param name="modifiedByPersonAliasId">The modified by person alias identifier.</param> public static void AddChanges(RockContext rockContext, Type modelType, Guid categoryGuid, int entityId, History.HistoryChangeList changes, string caption, Type relatedModelType, int?relatedEntityId, int?modifiedByPersonAliasId = null) { var entityType = EntityTypeCache.Get(modelType); var category = CategoryCache.Get(categoryGuid); var creationDate = RockDateTime.Now; int?relatedEntityTypeId = null; if (relatedModelType != null) { var relatedEntityType = EntityTypeCache.Get(relatedModelType); if (relatedModelType != null) { relatedEntityTypeId = relatedEntityType.Id; } } if (entityType != null && category != null) { var historyService = new HistoryService(rockContext); foreach (var historyChange in changes.Where(m => m != null)) { var history = new History(); history.EntityTypeId = entityType.Id; history.CategoryId = category.Id; history.EntityId = entityId; history.Caption = caption.Truncate(200); history.RelatedEntityTypeId = relatedEntityTypeId; history.RelatedEntityId = relatedEntityId; historyChange.CopyToHistory(history); if (modifiedByPersonAliasId.HasValue) { history.CreatedByPersonAliasId = modifiedByPersonAliasId; } // Manually set creation date on these history items so that they will be grouped together history.CreatedDateTime = creationDate; historyService.Add(history); } } }
/// <summary> /// Updates the last login. /// </summary> /// <param name="userName">Name of the user.</param> public static void UpdateLastLogin(string userName) { if (!string.IsNullOrWhiteSpace(userName) && !userName.StartsWith("rckipid=")) { using (var rockContext = new RockContext()) { var userLoginService = new UserLoginService(rockContext); var userLogin = userLoginService.GetByUserName(userName); if (userLogin != null) { userLogin.LastLoginDateTime = RockDateTime.Now; if (userLogin.PersonId.HasValue) { var summary = new System.Text.StringBuilder(); summary.AppendFormat("User logged in with <span class='field-name'>{0}</span> username", userLogin.UserName); if (HttpContext.Current != null && HttpContext.Current.Request != null) { summary.AppendFormat(", to <span class='field-value'>{0}</span>, from <span class='field-value'>{1}</span>", HttpContext.Current.Request.Url.AbsoluteUri, HttpContext.Current.Request.UserHostAddress); } summary.Append("."); var historyService = new HistoryService(rockContext); var personEntityTypeId = EntityTypeCache.Read("Rock.Model.Person").Id; var activityCategoryId = CategoryCache.Read(Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), rockContext).Id; historyService.Add(new History { EntityTypeId = personEntityTypeId, CategoryId = activityCategoryId, EntityId = userLogin.PersonId.Value, Summary = summary.ToString(), Verb = "LOGIN" }); } rockContext.SaveChanges(); } } } }
/// <summary> /// Adds the changes. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="modelType">Type of the model.</param> /// <param name="categoryGuid">The category unique identifier.</param> /// <param name="entityId">The entity identifier.</param> /// <param name="changes">The changes.</param> /// <param name="caption">The caption.</param> /// <param name="relatedModelType">Type of the related model.</param> /// <param name="relatedEntityId">The related entity identifier.</param> public static void AddChanges(RockContext rockContext, Type modelType, Guid categoryGuid, int entityId, List <string> changes, string caption, Type relatedModelType, int?relatedEntityId) { var entityType = EntityTypeCache.Read(modelType); var category = CategoryCache.Read(categoryGuid); var creationDate = RockDateTime.Now; int?relatedEntityTypeId = null; if (relatedModelType != null) { var relatedEntityType = EntityTypeCache.Read(relatedModelType); if (relatedModelType != null) { relatedEntityTypeId = relatedEntityType.Id; } } if (entityType != null && category != null) { var historyService = new HistoryService(rockContext); foreach (string message in changes.Where(m => m != null && m != "")) { var history = new History(); history.EntityTypeId = entityType.Id; history.CategoryId = category.Id; history.EntityId = entityId; history.Caption = caption.Truncate(200); history.Summary = message; history.RelatedEntityTypeId = relatedEntityTypeId; history.RelatedEntityId = relatedEntityId; // Manually set creation date on these history items so that they will be grouped together history.CreatedDateTime = creationDate; historyService.Add(history); } } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <exception cref="System.NotImplementedException"></exception> public override void Send( Rock.Model.Communication communication ) { using ( var rockContext = new RockContext() ) { // Requery the Communication object communication = new CommunicationService( rockContext ) .Queryable( "CreatedByPersonAlias.Person" ) .FirstOrDefault( c => c.Id == 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 ) ) { var currentPerson = communication.CreatedByPersonAlias.Person; var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read(); var globalConfigValues = Rock.Web.Cache.GlobalAttributesCache.GetMergeFields( currentPerson ); // From - if none is set, use the one in the Organization's GlobalAttributes. string fromAddress = communication.GetMediumDataValue( "FromAddress" ); if ( string.IsNullOrWhiteSpace( fromAddress ) ) { fromAddress = globalAttributes.GetValue( "OrganizationEmail" ); } string fromName = communication.GetMediumDataValue( "FromName" ); if ( string.IsNullOrWhiteSpace( fromName ) ) { fromName = globalAttributes.GetValue( "OrganizationName" ); } // Resolve any possible merge fields in the from address fromAddress = fromAddress.ResolveMergeFields( globalConfigValues, currentPerson ); fromName = fromName.ResolveMergeFields( globalConfigValues, currentPerson ); MailMessage message = new MailMessage(); message.From = new MailAddress( fromAddress, fromName ); // Reply To string replyTo = communication.GetMediumDataValue( "ReplyTo" ); if ( !string.IsNullOrWhiteSpace( replyTo ) ) { message.ReplyToList.Add( new MailAddress( replyTo ) ); } CheckSafeSender( message, globalAttributes ); // CC string cc = communication.GetMediumDataValue( "CC" ); if ( !string.IsNullOrWhiteSpace( cc ) ) { foreach ( string ccRecipient in cc.SplitDelimitedValues() ) { message.CC.Add( new MailAddress( ccRecipient ) ); } } // BCC string bcc = communication.GetMediumDataValue( "BCC" ); if ( !string.IsNullOrWhiteSpace( bcc ) ) { foreach ( string bccRecipient in bcc.SplitDelimitedValues() ) { message.Bcc.Add( new MailAddress( bccRecipient ) ); } } message.IsBodyHtml = true; message.Priority = MailPriority.Normal; using ( var smtpClient = GetSmtpClient() ) { // Add Attachments string attachmentIds = communication.GetMediumDataValue( "Attachments" ); if ( !string.IsNullOrWhiteSpace( attachmentIds ) ) { 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 ) { message.Attachments.Add( new Attachment( binaryFile.ContentStream, binaryFile.FileName ) ); } } } } var historyService = new HistoryService( rockContext ); var recipientService = new CommunicationRecipientService( rockContext ); var personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; var communicationEntityTypeId = EntityTypeCache.Read( "Rock.Model.Communication" ).Id; var communicationCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext ).Id; bool recipientFound = true; while ( recipientFound ) { var recipient = Rock.Model.Communication.GetNextPending( communication.Id, rockContext ); if ( recipient != null ) { if ( string.IsNullOrWhiteSpace( recipient.PersonAlias.Person.Email ) ) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "No Email Address"; } else { try { message.To.Clear(); message.Headers.Clear(); message.AlternateViews.Clear(); message.To.Add( new MailAddress( recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName ) ); // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues( globalConfigValues ); // Subject message.Subject = communication.Subject.ResolveMergeFields( mergeObjects, currentPerson ); // convert any special microsoft word characters to normal chars so they don't look funny (for example "Hey “double-quotes†from ‘single quote’") message.Subject = message.Subject.ReplaceWordChars(); // Add any additional headers that specific SMTP provider needs AddAdditionalHeaders( message, recipient ); // Add text view first as last view is usually treated as the preferred view by email readers (gmail) string plainTextBody = Rock.Communication.Medium.Email.ProcessTextBody( communication, globalAttributes, mergeObjects, currentPerson ); // convert any special microsoft word characters to normal chars so they don't look funny plainTextBody = plainTextBody.ReplaceWordChars(); if ( !string.IsNullOrWhiteSpace( plainTextBody ) ) { AlternateView plainTextView = AlternateView.CreateAlternateViewFromString( plainTextBody, new System.Net.Mime.ContentType( MediaTypeNames.Text.Plain ) ); message.AlternateViews.Add( plainTextView ); } // Add Html view string htmlBody = Rock.Communication.Medium.Email.ProcessHtmlBody( communication, globalAttributes, mergeObjects, currentPerson ); // convert any special microsoft word characters to normal chars so they don't look funny htmlBody = htmlBody.ReplaceWordChars(); if ( !string.IsNullOrWhiteSpace( htmlBody ) ) { AlternateView htmlView = AlternateView.CreateAlternateViewFromString( htmlBody, new System.Net.Mime.ContentType( MediaTypeNames.Text.Html ) ); message.AlternateViews.Add( htmlView ); } smtpClient.Send( message ); recipient.Status = CommunicationRecipientStatus.Delivered; string statusNote = StatusNote; if ( !string.IsNullOrWhiteSpace( statusNote ) ) { recipient.StatusNote = statusNote; } recipient.TransportEntityTypeName = this.GetType().FullName; historyService.Add( new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Summary = string.Format( "Sent communication from <span class='field-value'>{0}</span>.", message.From.DisplayName ), Caption = message.Subject, RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id } ); } catch ( Exception ex ) { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Exception: " + ex.Message; } } rockContext.SaveChanges(); } else { recipientFound = false; } } } } } }
/// <summary> /// Adds the changes. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="modelType">Type of the model.</param> /// <param name="categoryGuid">The category unique identifier.</param> /// <param name="entityId">The entity identifier.</param> /// <param name="changes">The changes.</param> /// <param name="caption">The caption.</param> /// <param name="relatedModelType">Type of the related model.</param> /// <param name="relatedEntityId">The related entity identifier.</param> /// <param name="modifiedByPersonAliasId">The modified by person alias identifier.</param> public static void AddChanges( RockContext rockContext, Type modelType, Guid categoryGuid, int entityId, List<string> changes, string caption, Type relatedModelType, int? relatedEntityId, int? modifiedByPersonAliasId = null ) { var entityType = EntityTypeCache.Read( modelType ); var category = CategoryCache.Read( categoryGuid ); var creationDate = RockDateTime.Now; int? relatedEntityTypeId = null; if ( relatedModelType != null ) { var relatedEntityType = EntityTypeCache.Read( relatedModelType ); if ( relatedModelType != null ) { relatedEntityTypeId = relatedEntityType.Id; } } if ( entityType != null && category != null ) { var historyService = new HistoryService( rockContext ); foreach ( string message in changes.Where( m => m != null && m != "" ) ) { var history = new History(); history.EntityTypeId = entityType.Id; history.CategoryId = category.Id; history.EntityId = entityId; history.Caption = caption.Truncate(200); history.Summary = message; history.RelatedEntityTypeId = relatedEntityTypeId; history.RelatedEntityId = relatedEntityId; if ( modifiedByPersonAliasId.HasValue ) { history.CreatedByPersonAliasId = modifiedByPersonAliasId; } // Manually set creation date on these history items so that they will be grouped together history.CreatedDateTime = creationDate; historyService.Add( history ); } } }
/// <summary> /// Job that will run quick SQL queries on a schedule. /// /// Called by the <see cref="IScheduler" /> when a /// <see cref="ITrigger" /> fires that is associated with /// the <see cref="IJob" />. /// </summary> public virtual void Execute( IJobExecutionContext context ) { JobDataMap dataMap = context.JobDetail.JobDataMap; Guid? entryWorkflowType = dataMap.GetString( "EraEntryWorkflow" ).AsGuidOrNull(); Guid? exitWorkflowType = dataMap.GetString( "EraExitWorkflow" ).AsGuidOrNull(); bool updateVisitDates = dataMap.GetBooleanValue( "SetVisitDates" ); var groupTypeList = dataMap.GetString( "GroupTypes" ); // configuration // // giving int exitGivingCount = 1; // attendance int exitAttendanceCountShort = 1; int exitAttendanceCountLong = 8; // get era dataset from stored proc var resultContext = new RockContext(); var eraAttribute = AttributeCache.Read( SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid() ); var eraStartAttribute = AttributeCache.Read( SystemGuid.Attribute.PERSON_ERA_START_DATE.AsGuid() ); var eraEndAttribute = AttributeCache.Read( SystemGuid.Attribute.PERSON_ERA_END_DATE.AsGuid() ); resultContext.Database.CommandTimeout = 3600; var results = resultContext.Database.SqlQuery<EraResult>( "spCrm_FamilyAnalyticsEraDataset" ).ToList(); int personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; int attributeEntityTypeId = EntityTypeCache.Read( "Rock.Model.Attribute" ).Id; int eraAttributeId = AttributeCache.Read( SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid() ).Id; int personAnalyticsCategoryId = CategoryCache.Read( SystemGuid.Category.HISTORY_PERSON_ANALYTICS.AsGuid() ).Id; foreach (var result in results ) { // create new rock context for each family (https://weblog.west-wind.com/posts/2014/Dec/21/Gotcha-Entity-Framework-gets-slow-in-long-Iteration-Loops) RockContext updateContext = new RockContext(); var attributeValueService = new AttributeValueService( updateContext ); var historyService = new HistoryService( updateContext ); // if era ensure it still meets requirements if ( result.IsEra ) { if (result.ExitGiftCountDuration < exitGivingCount && result.ExitAttendanceCountDurationShort < exitAttendanceCountShort && result.ExitAttendanceCountDurationLong < exitAttendanceCountLong ) { // exit era (delete attribute value from each person in family) var family = new GroupService( updateContext ).Queryable( "Members, Members.Person" ).AsNoTracking().Where( m => m.Id == result.FamilyId ).FirstOrDefault(); if ( family != null ) { foreach ( var person in family.Members.Select( m => m.Person ) ) { // remove the era flag var eraAttributeValue = attributeValueService.Queryable().Where( v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id ).FirstOrDefault(); if ( eraAttributeValue != null ) { attributeValueService.Delete( eraAttributeValue ); } // set end date var eraEndAttributeValue = attributeValueService.Queryable().Where( v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id ).FirstOrDefault(); if ( eraEndAttributeValue == null ) { eraEndAttributeValue = new AttributeValue(); eraEndAttributeValue.EntityId = person.Id; eraEndAttributeValue.AttributeId = eraEndAttribute.Id; attributeValueService.Add( eraEndAttributeValue ); } eraEndAttributeValue.Value = RockDateTime.Now.ToString(); // add a history record if ( personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0 ) { History historyRecord = new History(); historyService.Add( historyRecord ); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Summary = "Exited eRA Status"; historyRecord.Verb = "EXITED"; historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; } updateContext.SaveChanges(); } // launch exit workflow if ( exitWorkflowType.HasValue ) { LaunchWorkflow( exitWorkflowType.Value, family ); } } } } else { // entered era var family = new GroupService( updateContext ).Queryable( "Members" ).AsNoTracking().Where( m => m.Id == result.FamilyId ).FirstOrDefault(); if ( family != null ) { foreach ( var person in family.Members.Select( m => m.Person ) ) { // set era attribute to true var eraAttributeValue = attributeValueService.Queryable().Where( v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id ).FirstOrDefault(); if ( eraAttributeValue == null ) { eraAttributeValue = new AttributeValue(); eraAttributeValue.EntityId = person.Id; eraAttributeValue.AttributeId = eraAttribute.Id; attributeValueService.Add( eraAttributeValue ); } eraAttributeValue.Value = bool.TrueString; // add start date var eraStartAttributeValue = attributeValueService.Queryable().Where( v => v.AttributeId == eraStartAttribute.Id && v.EntityId == person.Id ).FirstOrDefault(); if (eraStartAttributeValue == null ) { eraStartAttributeValue = new AttributeValue(); eraStartAttributeValue.EntityId = person.Id; eraStartAttributeValue.AttributeId = eraStartAttribute.Id; attributeValueService.Add( eraStartAttributeValue ); } eraStartAttributeValue.Value = RockDateTime.Now.ToString(); // delete end date if it exists var eraEndAttributeValue = attributeValueService.Queryable().Where( v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id ).FirstOrDefault(); if ( eraEndAttributeValue != null ) { attributeValueService.Delete( eraEndAttributeValue ); } // add a history record if ( personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0 ) { History historyRecord = new History(); historyService.Add( historyRecord ); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Summary = "Entered eRA Status"; historyRecord.Verb = "ENTERED"; historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; } updateContext.SaveChanges(); } // launch entry workflow if ( entryWorkflowType.HasValue ) { LaunchWorkflow( entryWorkflowType.Value, family ); } } } // update stats } // load giving attributes resultContext.Database.ExecuteSqlCommand( "spCrm_FamilyAnalyticsGiving" ); // load attendance attributes resultContext.Database.ExecuteSqlCommand( "spCrm_FamilyAnalyticsAttendance" ); // process history for group types if (!string.IsNullOrWhiteSpace( groupTypeList ) ) { string[] groupTypeGuids = groupTypeList.Split( ',' ); var inactiveRecordValue = DefinedValueCache.Read( SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE ); var groupTypeEntityTypeId = EntityTypeCache.Read( "Rock.Model.GroupType" ).Id; foreach ( var groupTypeGuid in groupTypeGuids ) { var groupType = GroupTypeCache.Read( groupTypeGuid.AsGuid() ); if ( groupType != null ) { // if the person is in a group of that type and the last history record for that group type isn't START write a start RockContext rockContext = new RockContext(); // get history for this group type var historyRecords = new HistoryService( rockContext ).Queryable() .Where( h => h.EntityTypeId == personEntityTypeId && h.RelatedEntityTypeId == groupTypeEntityTypeId && h.RelatedEntityId == groupType.Id ) .GroupBy( h => h.EntityId ) .Select( g => g.OrderByDescending( h => h.CreatedDateTime ).Select( h => new { h.EntityId, h.Verb } ).FirstOrDefault() ) .ToList(); // get group member information var groupMemberInfo = new GroupMemberService( rockContext ).Queryable() .Where( m => m.Group.GroupTypeId == groupType.Id && m.GroupMemberStatus == GroupMemberStatus.Active && m.Group.IsActive //&& m.Person.RecordStatusValueId != inactiveRecordValue.Id ) .GroupBy( m => m.PersonId ) .Select( g => g.OrderBy( m => m.CreatedDateTime ).Select( m => new { m.PersonId, m.CreatedDateTime, PersonAliasId = m.Person.Aliases.Select( p => p.Id ).FirstOrDefault() } ).FirstOrDefault() ) .ToList(); var needsStartDate = groupMemberInfo.Where( m => !historyRecords.Any( h => h.EntityId == m.PersonId && h.Verb == "STARTED" ) ); foreach ( var startItem in needsStartDate ) { using ( RockContext updateContext = new RockContext() ) { var historyService = new HistoryService( updateContext ); History history = new History(); historyService.Add( history ); history.EntityTypeId = personEntityTypeId; history.EntityId = startItem.PersonId; history.RelatedEntityTypeId = groupTypeEntityTypeId; history.RelatedEntityId = groupType.Id; history.Caption = groupType.Name; history.Summary = "Started Membership in Group Of Type"; history.Verb = "STARTED"; history.CreatedDateTime = startItem.CreatedDateTime; history.CreatedByPersonAliasId = startItem.PersonAliasId; history.CategoryId = personAnalyticsCategoryId; updateContext.SaveChanges(); } } var needsStoppedDate = historyRecords.Where( h => h.Verb == "STARTED" && !groupMemberInfo.Any( m => m.PersonId == h.EntityId ) ); foreach ( var stopItem in needsStoppedDate ) { using ( RockContext updateContext = new RockContext() ) { var person = new PersonService( updateContext ).Get( stopItem.EntityId ); if ( person != null ) { var historyService = new HistoryService( updateContext ); History history = new History(); historyService.Add( history ); history.EntityTypeId = personEntityTypeId; history.EntityId = person.Id; history.RelatedEntityTypeId = groupTypeEntityTypeId; history.RelatedEntityId = groupType.Id; history.Caption = groupType.Name; history.Summary = "Stopped Membership in Group Of Type"; history.Verb = "STOPPED"; history.CreatedDateTime = RockDateTime.Now; history.CreatedByPersonAliasId = person.PrimaryAliasId; history.CategoryId = personAnalyticsCategoryId; updateContext.SaveChanges(); } } } } } } // process visit dates if ( updateVisitDates ) { resultContext.Database.ExecuteSqlCommand( "spCrm_FamilyAnalyticsUpdateVisitDates" ); } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <exception cref="System.NotImplementedException"></exception> public override void Send( Rock.Model.Communication communication ) { using ( var rockContext = new RockContext() ) { // Requery the Communication communication = new CommunicationService( rockContext ).Get( communication.Id ); if ( communication != null && communication.Status == CommunicationStatus.Approved && communication.Recipients.Any(r => r.Status == CommunicationRecipientStatus.Pending) && ( !communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo( RockDateTime.Now ) <= 0 ) ) { // Remove all non alpha numeric from fromValue string fromValue = communication.GetMediumDataValue( "NoReply_FromValue" ); //Ensure that the fromValue is correct fromValue = new string( fromValue.ToCharArray().Where( c => char.IsLetterOrDigit( c ) || char.IsWhiteSpace( c ) ).Take( 11 ).ToArray() ) ; string senderGuid = communication.GetMediumDataValue( "SenderGuid" ); if ( !string.IsNullOrWhiteSpace( fromValue ) && !string.IsNullOrWhiteSpace( senderGuid ) ) { string accountSid = GetAttributeValue( "SID" ); string authToken = GetAttributeValue( "Token" ); if (string.IsNullOrWhiteSpace(accountSid) || string.IsNullOrWhiteSpace(authToken)) { throw new Exception("Either SID or Token not provided"); } var twilio = new TwilioRestClient( accountSid, authToken ); var historyService = new HistoryService( rockContext ); int personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; int communicationEntityTypeId = EntityTypeCache.Read( "Rock.Model.Communication" ).Id; int communicationCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext ).Id; var sender = new PersonService( rockContext ).Get( senderGuid.AsGuid() ); var mergeFields = GlobalAttributesCache.GetMergeFields( null ); if ( sender != null ) { mergeFields.Add( "Sender", sender ); } bool recipientFound = true; while ( recipientFound ) { var recipient = Rock.Model.Communication.GetNextPending( communication.Id, rockContext ); if ( recipient != null ) { try { var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers .FirstOrDefault(p => p.IsMessagingEnabled); if ( phoneNumber != null ) { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues( mergeFields ); string message = communication.GetMediumDataValue( "NoReply_Message" ); string footer = GetAttributeValue( "footer" ); if ( communication.GetMediumDataValue( "NoReply_AppendUserInfo" ).AsBoolean() && !string.IsNullOrEmpty( footer ) ) { message += "\n " + footer; } else { message += "\n This message was sent on behalf of {{ GlobalAttribute.OrganizationName }} from a no reply number."; } message = message.ReplaceWordChars(); message = message.ResolveMergeFields( mergeObjects ); string twilioNumber = phoneNumber.Number; if ( !string.IsNullOrWhiteSpace( phoneNumber.CountryCode ) ) { twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number; } var globalAttributes = GlobalAttributesCache.Read(); if (globalAttributes == null) { throw new Exception("Error getting Global Attributes"); } string callbackUrl = globalAttributes.GetValue( "PublicApplicationRoot" ) + "Webhooks/Twilio.ashx"; var response = twilio.SendMessage( fromValue, twilioNumber, message, callbackUrl ); if (response != null) { recipient.Status = GetCommunicationRecipientStatus(response); recipient.TransportEntityTypeName = GetType().FullName; recipient.UniqueMessageId = response.Sid; try { historyService.Add(new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Summary = "Sent an alphanumeric SMS message from " + fromValue + ".", Caption = message.Truncate(200), RelatedEntityTypeId = communicationEntityTypeId, RelatedEntityId = communication.Id }); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } else { recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "No response from Twilio"; } } 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; ExceptionLogService.LogException( ex, null ); } rockContext.SaveChanges(); } else { recipientFound = false; } } } } } }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <exception cref="System.NotImplementedException"></exception> public override void Send( Rock.Model.Communication communication ) { var rockContext = new RockContext(); // Requery the Communication communication = new CommunicationService( rockContext ).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 ) ) { string fromPhone = string.Empty; string fromValue = communication.GetMediumDataValue( "FromValue" ); int fromValueId = int.MinValue; if ( int.TryParse( fromValue, out fromValueId ) ) { fromPhone = DefinedValueCache.Read( fromValueId, rockContext ).Value; } if ( !string.IsNullOrWhiteSpace( fromPhone ) ) { string accountSid = GetAttributeValue( "SID" ); string authToken = GetAttributeValue( "Token" ); var twilio = new TwilioRestClient( accountSid, authToken ); var historyService = new HistoryService( rockContext ); var recipientService = new CommunicationRecipientService( rockContext ); var personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; var communicationEntityTypeId = EntityTypeCache.Read( "Rock.Model.Communication" ).Id; var communicationCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(), rockContext ).Id; var globalConfigValues = GlobalAttributesCache.GetMergeFields( null ); bool recipientFound = true; while ( recipientFound ) { var recipient = recipientService.Get( communication.Id, CommunicationRecipientStatus.Pending ).FirstOrDefault(); if ( recipient != null ) { try { var phoneNumber = recipient.PersonAlias.Person.PhoneNumbers .Where( p => p.IsMessagingEnabled ) .FirstOrDefault(); if ( phoneNumber != null ) { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues( globalConfigValues ); string message = communication.GetMediumDataValue( "Message" ); message = message.ResolveMergeFields( mergeObjects ); string twilioNumber = phoneNumber.Number; if ( !string.IsNullOrWhiteSpace( phoneNumber.CountryCode ) ) { twilioNumber = "+" + phoneNumber.CountryCode + phoneNumber.Number; } var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read(); string callbackUrl = globalAttributes.GetValue( "PublicApplicationRoot" ) + "Webhooks/Twilio.ashx"; var response = twilio.SendMessage( fromPhone, twilioNumber, message, callbackUrl ); recipient.Status = CommunicationRecipientStatus.Delivered; recipient.TransportEntityTypeName = this.GetType().FullName; recipient.UniqueMessageId = response.Sid; try { historyService.Add( new History { CreatedByPersonAliasId = communication.SenderPersonAliasId, EntityTypeId = personEntityTypeId, CategoryId = communicationCategoryId, EntityId = recipient.PersonAlias.PersonId, Summary = "Sent 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(); } else { recipientFound = false; } } } } }
/// <summary> /// Updates the last login. /// </summary> /// <param name="userName">Name of the user.</param> public static void UpdateLastLogin( string userName ) { using ( var rockContext = new RockContext() ) { var userLoginService = new UserLoginService( rockContext ); var historyService = new HistoryService( rockContext ); var personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; var activityCategoryId = CategoryCache.Read( Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), rockContext ).Id; if ( !string.IsNullOrWhiteSpace( userName ) && !userName.StartsWith( "rckipid=" ) ) { var userLogin = userLoginService.GetByUserName( userName ); if ( userLogin != null ) { userLogin.LastLoginDateTime = RockDateTime.Now; if ( userLogin.PersonId.HasValue ) { var summary = new System.Text.StringBuilder(); summary.AppendFormat( "User logged in with <span class='field-name'>{0}</span> username", userLogin.UserName ); if ( HttpContext.Current != null && HttpContext.Current.Request != null ) { summary.AppendFormat( ", to <span class='field-value'>{0}</span>, from <span class='field-value'>{1}</span>", HttpContext.Current.Request.Url.AbsoluteUri, HttpContext.Current.Request.UserHostAddress ); } summary.Append( "." ); historyService.Add( new History { EntityTypeId = personEntityTypeId, CategoryId = activityCategoryId, EntityId = userLogin.PersonId.Value, Summary = summary.ToString() } ); } rockContext.SaveChanges(); } } } }
/// <summary> /// Updates the last login and writes to the person's history log /// </summary> /// <param name="userName">Name of the user.</param> public static void UpdateLastLogin(string userName) { if (!string.IsNullOrWhiteSpace(userName)) { using (var rockContext = new RockContext()) { int? personId = null; bool impersonated = userName.StartsWith("rckipid="); if (!impersonated) { var userLogin = new UserLoginService(rockContext).GetByUserName(userName); if (userLogin != null) { userLogin.LastLoginDateTime = RockDateTime.Now; personId = userLogin.PersonId; } } else { var impersonationToken = userName.Substring(8); personId = new PersonService(rockContext).GetByImpersonationToken(impersonationToken, false, null)?.Id; } if (personId.HasValue) { var summary = new System.Text.StringBuilder(); if (impersonated) { summary.Append("Impersonated user logged in"); var impersonatedByUser = HttpContext.Current?.Session["ImpersonatedByUser"] as UserLogin; if (impersonatedByUser != null) { summary.Append($" ( impersonated by { impersonatedByUser.Person.FullName } ) "); } } else { summary.AppendFormat("User logged in with <span class='field-name'>{0}</span> username", userName); } if (HttpContext.Current != null && HttpContext.Current.Request != null) { string cleanUrl = PersonToken.ObfuscateRockMagicToken(HttpContext.Current.Request.Url.AbsoluteUri); // obfuscate the url specified in the returnurl, just in case it contains any sensitive information (like a rckipid) Regex returnurlRegEx = new Regex(@"returnurl=([^&]*)"); cleanUrl = returnurlRegEx.Replace(cleanUrl, "returnurl=XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); summary.AppendFormat(", to <span class='field-value'>{0}</span>, from <span class='field-value'>{1}</span>", cleanUrl, HttpContext.Current.Request.UserHostAddress); } summary.Append("."); var historyService = new HistoryService(rockContext); var personEntityTypeId = EntityTypeCache.Read("Rock.Model.Person").Id; var activityCategoryId = CategoryCache.Read(Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), rockContext).Id; historyService.Add(new History { EntityTypeId = personEntityTypeId, CategoryId = activityCategoryId, EntityId = personId.Value, Summary = summary.ToString(), Verb = "LOGIN" }); } rockContext.SaveChanges(); } } }