void lbIgnore_Click(object sender, EventArgs e) { // Get the suggestion ids that were selected var itemsSelected = new List <int>(); gSuggestions.SelectedKeys.ToList().ForEach(f => itemsSelected.Add(f.ToString().AsInteger())); // If any items were selected if (itemsSelected.Any()) { using (var rockContext = new RockContext()) { // Update the status of each suggestion to be ignored var followingSuggestedService = new FollowingSuggestedService(rockContext); foreach (var suggestion in followingSuggestedService.Queryable() .Where(f => itemsSelected.Contains(f.Id))) { suggestion.Status = FollowingSuggestedStatus.Ignored; } rockContext.SaveChanges(); } } BindGrid(); }
/// <summary> /// Handles the Click event of the lbUnfollow control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> void lbFollow_Click(object sender, EventArgs e) { // Get the suggestion ids that were selected var itemsSelected = new List <int>(); gSuggestions.SelectedKeys.ToList().ForEach(f => itemsSelected.Add(f.ToString().AsInteger())); // Get the personAlias entity type var personAliasEntityType = EntityTypeCache.Get(typeof(Rock.Model.PersonAlias)); // If we have a valid current person and items were selected if (personAliasEntityType != null && CurrentPersonAliasId.HasValue && itemsSelected.Any()) { using (var rockContext = new RockContext()) { // Get all the person alias id's that were selected var followingSuggestedService = new FollowingSuggestedService(rockContext); var selectedPersonAliasIds = followingSuggestedService .Queryable() .Where(f => itemsSelected.Contains(f.Id)) .Select(f => f.EntityId) .Distinct() .ToList(); // Find any of the selected person alias ids that current person is already following var followingService = new FollowingService(rockContext); var alreadyFollowing = followingService .Queryable() .Where(f => f.EntityTypeId == personAliasEntityType.Id && f.PersonAliasId == CurrentPersonAliasId.Value && string.IsNullOrEmpty(f.PurposeKey) && selectedPersonAliasIds.Contains(f.EntityId)) .Select(f => f.EntityId) .Distinct() .ToList(); // For each selected person alias id that the current person is not already following foreach (var personAliasId in selectedPersonAliasIds.Where(p => !alreadyFollowing.Contains(p))) { // Add a following record var following = new Following(); following.EntityTypeId = personAliasEntityType.Id; following.EntityId = personAliasId; following.PersonAliasId = CurrentPersonAliasId.Value; followingService.Add(following); } rockContext.SaveChanges(); } } BindGrid(); }
/// <summary> /// Executes the specified context. /// </summary> /// <param name="context">The context.</param> public void Execute(IJobExecutionContext context) { var exceptionMsgs = new List <string>(); JobDataMap dataMap = context.JobDetail.JobDataMap; Guid? groupGuid = dataMap.GetString("EligibleFollowers").AsGuidOrNull(); Guid? systemEmailGuid = dataMap.GetString("EmailTemplate").AsGuidOrNull(); int followingSuggestionsEmailsSent = 0; int followingSuggestionsSuggestionsTotal = 0; if (groupGuid.HasValue && systemEmailGuid.HasValue) { using (var rockContext = new RockContext()) { var followingService = new FollowingService(rockContext); // The people who are eligible to get following suggestions based on the group type setting for this job var eligiblePersonIds = new GroupMemberService(rockContext) .Queryable().AsNoTracking() .Where(m => m.Group != null && m.Group.Guid.Equals(groupGuid.Value) && m.GroupMemberStatus == GroupMemberStatus.Active && m.Person != null && m.Person.Email != null && m.Person.Email != "") .Select(m => m.PersonId) .Distinct(); // check to see if there are any event types that require notification var followerPersonIds = new List <int>(); if (new FollowingEventTypeService(rockContext) .Queryable().AsNoTracking() .Any(e => e.IsNoticeRequired)) { // if so, include all eligible people followerPersonIds = eligiblePersonIds.ToList(); } else { // if not, filter the list of eligible people down to only those that actually have subscribed to one or more following events followerPersonIds = new FollowingEventSubscriptionService(rockContext) .Queryable().AsNoTracking() .Where(f => eligiblePersonIds.Contains(f.PersonAlias.PersonId)) .Select(f => f.PersonAlias.PersonId) .Distinct() .ToList(); } if (followerPersonIds.Any()) { // Get the primary person alias id for each of the followers var primaryAliasIds = new Dictionary <int, int>(); new PersonAliasService(rockContext) .Queryable().AsNoTracking() .Where(a => followerPersonIds.Contains(a.PersonId) && a.PersonId == a.AliasPersonId) .ToList() .ForEach(a => primaryAliasIds.AddOrIgnore(a.PersonId, a.Id)); // Get current date/time. var timestamp = RockDateTime.Now; var suggestionTypes = new FollowingSuggestionTypeService(rockContext) .Queryable().AsNoTracking() .Where(s => s.IsActive) .OrderBy(s => s.Name) .ToList(); var components = new Dictionary <int, SuggestionComponent>(); var suggestedEntities = new Dictionary <int, Dictionary <int, IEntity> >(); foreach (var suggestionType in suggestionTypes) { try { // Get the suggestion type component var suggestionComponent = suggestionType.GetSuggestionComponent(); if (suggestionComponent != null) { components.Add(suggestionType.Id, suggestionComponent); // Get the entitytype for this suggestion type var suggestionEntityType = EntityTypeCache.Read(suggestionComponent.FollowedType); if (suggestionEntityType != null) { var entityIds = new List <int>(); // Call the components method to return all of it's suggestions var personEntitySuggestions = suggestionComponent.GetSuggestions(suggestionType, followerPersonIds); // If any suggestions were returned by the component if (personEntitySuggestions.Any()) { int entityTypeId = suggestionEntityType.Id; string reasonNote = suggestionType.ReasonNote; // Get the existing followings for any of the followers var existingFollowings = new Dictionary <int, List <int> >(); foreach (var following in followingService.Queryable("PersonAlias").AsNoTracking() .Where(f => f.EntityTypeId == entityTypeId && followerPersonIds.Contains(f.PersonAlias.PersonId))) { existingFollowings.AddOrIgnore(following.PersonAlias.PersonId, new List <int>()); existingFollowings[following.PersonAlias.PersonId].Add(following.EntityId); } // Loop through each follower foreach (var followerPersonId in personEntitySuggestions .Select(s => s.PersonId) .Distinct()) { using (var suggestionContext = new RockContext()) { var followingSuggestedService = new FollowingSuggestedService(suggestionContext); // Read all the existing suggestions for this type and the returned followers var existingSuggestions = followingSuggestedService .Queryable("PersonAlias") .Where(s => s.SuggestionTypeId == suggestionType.Id && s.PersonAlias.PersonId == followerPersonId) .ToList(); // Look through the returned suggestions foreach (var followedEntityId in personEntitySuggestions .Where(s => s.PersonId == followerPersonId) .Select(s => s.EntityId)) { // Make sure person isn't already following this entity if (!existingFollowings.ContainsKey(followerPersonId) || !existingFollowings[followerPersonId].Contains(followedEntityId)) { // If this person had a primary alias id if (primaryAliasIds.ContainsKey(followerPersonId)) { entityIds.Add(followedEntityId); // Look for existing suggestion for this person and entity var suggestion = existingSuggestions .Where(s => s.EntityId == followedEntityId) .OrderByDescending(s => s.StatusChangedDateTime) .FirstOrDefault(); // If not found, add one if (suggestion == null) { suggestion = new FollowingSuggested(); suggestion.EntityTypeId = entityTypeId; suggestion.EntityId = followedEntityId; suggestion.PersonAliasId = primaryAliasIds[followerPersonId]; suggestion.SuggestionTypeId = suggestionType.Id; suggestion.Status = FollowingSuggestedStatus.PendingNotification; suggestion.StatusChangedDateTime = timestamp; followingSuggestedService.Add(suggestion); } else { // If found, and it has not been ignored, and it's time to promote again, update the promote date if (suggestion.Status != FollowingSuggestedStatus.Ignored && ( !suggestionType.ReminderDays.HasValue || !suggestion.LastPromotedDateTime.HasValue || suggestion.LastPromotedDateTime.Value.AddDays(suggestionType.ReminderDays.Value) <= timestamp )) { if (suggestion.Status != FollowingSuggestedStatus.PendingNotification) { suggestion.StatusChangedDateTime = timestamp; suggestion.Status = FollowingSuggestedStatus.PendingNotification; } } } } } } // Save the suggestions for this type suggestionContext.SaveChanges(); } } } // If any entities are being suggested for this type, query database for them and save to dictionary if (entityIds.Any()) { if (suggestionEntityType.AssemblyName != null) { // get the actual type of what is being followed Type entityType = suggestionEntityType.GetEntityType(); if (entityType != null) { // Get generic queryable method and query all the entities that are being followed Type[] modelType = { entityType }; Type genericServiceType = typeof(Rock.Data.Service <>); Type modelServiceType = genericServiceType.MakeGenericType(modelType); Rock.Data.IService serviceInstance = Activator.CreateInstance(modelServiceType, new object[] { rockContext }) as IService; MethodInfo qryMethod = serviceInstance.GetType().GetMethod("Queryable", new Type[] { }); var entityQry = qryMethod.Invoke(serviceInstance, new object[] { }) as IQueryable <IEntity>; var entityList = entityQry.AsNoTracking().Where(q => entityIds.Contains(q.Id)).ToList(); if (entityList != null && entityList.Any()) { var entities = new Dictionary <int, IEntity>(); entityList.ForEach(e => entities.Add(e.Id, e)); suggestedEntities.Add(suggestionType.Id, entities); } } } } } } } catch (Exception ex) { exceptionMsgs.Add(string.Format("An exception occurred calculating suggestions for the '{0}' suggestion type:{1} {2}", suggestionType.Name, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + " "))); ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); } } var allSuggestions = new FollowingSuggestedService(rockContext) .Queryable("PersonAlias") .Where(s => s.Status == FollowingSuggestedStatus.PendingNotification) .ToList(); var suggestionPersonIds = allSuggestions .Where(s => followerPersonIds.Contains(s.PersonAlias.PersonId)) .Select(s => s.PersonAlias.PersonId) .Distinct() .ToList(); var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read(rockContext).GetValue("ExternalApplicationRoot"); foreach (var person in new PersonService(rockContext) .Queryable().AsNoTracking() .Where(p => suggestionPersonIds.Contains(p.Id)) .ToList()) { try { var personSuggestionNotices = new List <FollowingSuggestionNotices>(); foreach (var suggestionType in suggestionTypes) { var component = components.ContainsKey(suggestionType.Id) ? components[suggestionType.Id] : null; if (component != null && suggestedEntities.ContainsKey(suggestionType.Id)) { var entities = new List <IEntity>(); foreach (var suggestion in allSuggestions .Where(s => s.PersonAlias.PersonId == person.Id && s.SuggestionTypeId == suggestionType.Id) .ToList()) { if (suggestedEntities[suggestionType.Id].ContainsKey(suggestion.EntityId)) { entities.Add(suggestedEntities[suggestionType.Id][suggestion.EntityId]); suggestion.LastPromotedDateTime = timestamp; suggestion.Status = FollowingSuggestedStatus.Suggested; } } var notices = new List <string>(); foreach (var entity in component.SortEntities(entities)) { notices.Add(component.FormatEntityNotification(suggestionType, entity)); } if (notices.Any()) { personSuggestionNotices.Add(new FollowingSuggestionNotices(suggestionType, notices)); } } } if (personSuggestionNotices.Any()) { // Send the notice var recipients = new List <RecipientData>(); var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Person", person); mergeFields.Add("Suggestions", personSuggestionNotices.OrderBy(s => s.SuggestionType.Order).ToList()); recipients.Add(new RecipientData(person.Email, mergeFields)); Email.Send(systemEmailGuid.Value, recipients, appRoot); followingSuggestionsEmailsSent += recipients.Count(); followingSuggestionsSuggestionsTotal += personSuggestionNotices.Count(); } rockContext.SaveChanges(); } catch (Exception ex) { exceptionMsgs.Add(string.Format("An exception occurred sending suggestions to '{0}':{1} {2}", person.FullName, Environment.NewLine, ex.Messages().AsDelimited(Environment.NewLine + " "))); ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); } } } } } context.Result = string.Format("A total of {0} following suggestions sent to {1} people", followingSuggestionsSuggestionsTotal, followingSuggestionsEmailsSent); if (exceptionMsgs.Any()) { throw new Exception("One or more exceptions occurred calculating suggestions..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine)); } }
/// <summary> /// Binds the grid. /// </summary> private void BindGrid() { var personAliasEntityType = EntityTypeCache.Read("Rock.Model.PersonAlias"); if (personAliasEntityType != null && CurrentPersonAlias != null) { var rockContext = new RockContext(); // PersonAlias query for joining the followed entity id to var personAliasQry = new PersonAliasService(rockContext).Queryable(); // Get all the people that the current person currently follows var followedPersonIds = new FollowingService(rockContext).Queryable() .Where(f => f.EntityTypeId == personAliasEntityType.Id && f.PersonAliasId == CurrentPersonAlias.Id) .Join(personAliasQry, s => s.EntityId, p => p.Id, (s, p) => p.PersonId) .Distinct(); // Get all the person suggestions for the current person that they are not already following var qry = new FollowingSuggestedService(rockContext) .Queryable("SuggestionType") .Where(s => s.SuggestionType != null && s.EntityTypeId == personAliasEntityType.Id && s.PersonAliasId == CurrentPersonAlias.Id) .Join(personAliasQry, s => s.EntityId, p => p.Id, (s, p) => new { s, p }) .Where(j => !followedPersonIds.Contains(j.p.PersonId)) .Select(j => new { j.s.Id, j.s.LastPromotedDateTime, j.s.StatusChangedDateTime, j.s.SuggestionType.ReasonNote, j.s.Status, Person = j.p.Person, LastName = j.p.Person.LastName, NickName = j.p.Person.NickName }); // Sort the result SortProperty sortProperty = gSuggestions.SortProperty; if (sortProperty == null) { sortProperty = new SortProperty(new GridViewSortEventArgs("LastName,NickName", SortDirection.Ascending)); } // Bind grid to the query gSuggestions.DataSource = qry.Sort(sortProperty) .Select(s => new { s.Id, s.LastPromotedDateTime, s.StatusChangedDateTime, s.ReasonNote, s.Status, StatusLabel = s.Status == FollowingSuggestedStatus.Ignored ? "<span class='label label-warning'>Ignored</span>" : "<span class='label label-success'>Suggested</span>", s.Person, s.LastName, s.NickName }) .ToList(); gSuggestions.DataBind(); } }
/// <summary> /// Checks to see if the PersonAlias entity should be added to the FollowingSuggestion table. If the entity is not a PersonAlias then addSuggestion will be true. /// If the Entity is a PersonAlias then this method will check if the associated Person has another PersonAlias that is being followed. /// If there is another PersonAlias being followed then the Following and FollowingSuggestion are updated with this EntityId (PersonAliasId) /// which is the PrimaryPersonAliasId. /// </summary> /// <param name="followerPersonId">The follower person identifier.</param> /// <param name="suggestionTypeComponent">The suggestion type component.</param> /// <param name="entityIdToBeSavedAsSuggestions">The entity ids.</param> /// <param name="entityTypeId">The entity type identifier.</param> /// <param name="suggestionContext">The suggestion context.</param> /// <param name="followedEntityId">The followed entity identifier.</param> /// <param name="addSuggestion">if set to <c>true</c> then the suggestion should be inserted.</param> /// <returns> /// True if the PersonAlias following suggestion should be inserted or if the EntityType is not a PersonAlias. /// </returns> private void ProcessFollowingSuggestionAndPersonAliasEntity(int followerPersonId, SuggestionTypeComponent suggestionTypeComponent, List <int> entityIdToBeSavedAsSuggestions, int entityTypeId, RockContext suggestionContext, int followedEntityId, out bool addSuggestion) { addSuggestion = true; // If the Entity is not a PersonAlias no other checks are needed just return with addSuggestion = true if (!IsEntityTypePersonAlias(entityTypeId)) { return; } // since this is a person alias see if a different alias is being used to follow var followedPersonId = new PersonAliasService(suggestionContext).Get(followedEntityId).PersonId; var followedPersonAliases = new PersonAliasService(suggestionContext) .Queryable() .Where(a => a.PersonId == followedPersonId && a.Id != followedEntityId) .Select(a => a.Id) .ToList(); if (!followedPersonAliases.Any()) { // There are no alternate person alias' there is nothing else to check so just return with addSuggestion = true return; } int existingFollowingPersonAliasId = suggestionTypeComponent.ExistingFollowings .GetValueOrDefault(followerPersonId, new List <int>()) .Where(f => followedPersonAliases.Contains(f)) .FirstOrDefault(); // Update the existing following record to use the primary PersonAlias ID and remove it from the list. if (existingFollowingPersonAliasId != 0) { var personAliasEntityTypeId = EntityTypeCache.GetId(Rock.SystemGuid.EntityType.PERSON_ALIAS) ?? 0; addSuggestion = false; entityIdToBeSavedAsSuggestions.Remove(followedEntityId); using (var followingContext = new RockContext()) { var following = new FollowingService(followingContext) .GetByEntityAndPerson(personAliasEntityTypeId, existingFollowingPersonAliasId, followerPersonId) .FirstOrDefault(); following.EntityId = followedEntityId; var suggested = new FollowingSuggestedService(followingContext) .GetByEntityAndPerson(personAliasEntityTypeId, existingFollowingPersonAliasId, followerPersonId) .FirstOrDefault(); if (suggested != null) { // Get the Followed Person's Primary PersonAliasId from FollowingSuggestions if it exists, PersonEntitySuggestions is already filtered for EntityType int existingFollowingSuggestedPrimaryPersonAliasId = suggestionTypeComponent.PersonEntitySuggestions .Where(s => s.PersonId == followerPersonId && s.EntityId == followedEntityId) .Select(s => s.EntityId) .FirstOrDefault(); if (existingFollowingSuggestedPrimaryPersonAliasId != 0) { // Since the Primary PersonAlias is already in FollowingSuggestions then just delete this one as a duplicate new FollowingSuggestedService(followingContext).Delete(suggested); } else { // Update the outdated PersonAliasId to the primary PersonAliasId which is the followedEntityId suggested.EntityId = followedEntityId; } } followingContext.SaveChanges(); } } }
/// <summary> /// Processes the follower PersonId for the SuggestionType /// </summary> /// <param name="followerPersonId">The follower person identifier.</param> /// <param name="suggestionTypeComponent">The suggestion type component.</param> /// <param name="primaryAliasIds">The primary alias ids.</param> /// <param name="entityIds">The entity ids.</param> /// <param name="entityTypeId">The entity type identifier.</param> /// <param name="timestamp">The timestamp.</param> private void ProcessFollowerPersonId(int followerPersonId, SuggestionTypeComponent suggestionTypeComponent, Dictionary <int, int> primaryAliasIds, List <int> entityIds, int entityTypeId, DateTime timestamp) { using (var suggestionContext = new RockContext()) { var followingSuggestedService = new FollowingSuggestedService(suggestionContext); // Read all the existing suggestions for this type and the returned followers var existingSuggestions = followingSuggestedService .Queryable("PersonAlias") .Where(s => s.SuggestionTypeId == suggestionTypeComponent.FollowingSuggestionType.Id && s.PersonAlias.PersonId == followerPersonId) .ToList(); // Look through the returned suggestions foreach (var followedEntityId in suggestionTypeComponent.PersonEntitySuggestions.Where(s => s.PersonId == followerPersonId).Select(s => s.EntityId)) { // Make sure person isn't already following this entity if (!suggestionTypeComponent.ExistingFollowings.ContainsKey(followerPersonId) || !suggestionTypeComponent.ExistingFollowings[followerPersonId].Contains(followedEntityId)) { // If this person had a primary alias id if (primaryAliasIds.ContainsKey(followerPersonId)) { entityIds.Add(followedEntityId); // Look for existing suggestion for this person and entity var suggestion = existingSuggestions .Where(s => s.EntityId == followedEntityId) .OrderByDescending(s => s.StatusChangedDateTime) .FirstOrDefault(); // If not found add it if needed if (suggestion == null) { bool addSuggestion; ProcessFollowingSuggestionAndPersonAliasEntity(followerPersonId, suggestionTypeComponent, entityIds, entityTypeId, suggestionContext, followedEntityId, out addSuggestion); if (addSuggestion) { // This is a new entity ID so insert it suggestion = new FollowingSuggested { EntityTypeId = entityTypeId, EntityId = followedEntityId, PersonAliasId = primaryAliasIds[followerPersonId], SuggestionTypeId = suggestionTypeComponent.FollowingSuggestionType.Id, Status = FollowingSuggestedStatus.PendingNotification, StatusChangedDateTime = timestamp }; followingSuggestedService.Add(suggestion); } } else { ProcessFollowingSuggestionAndPersonAliasEntity(followerPersonId, suggestionTypeComponent, entityIds, entityTypeId, suggestionContext, followedEntityId); // If found, and it has not been ignored, and it's time to promote again, update the promote date if (suggestion.Status != FollowingSuggestedStatus.Ignored && suggestionTypeComponent.FollowingSuggestionType.ReminderDays.HasValue && ( !suggestion.LastPromotedDateTime.HasValue || suggestion.LastPromotedDateTime.Value.AddDays(suggestionTypeComponent.FollowingSuggestionType.ReminderDays.Value) <= timestamp )) { if (suggestion.Status != FollowingSuggestedStatus.PendingNotification) { suggestion.StatusChangedDateTime = timestamp; suggestion.Status = FollowingSuggestedStatus.PendingNotification; } } } } } } // Save the suggestions for this type suggestionContext.SaveChanges(); } }
/// <summary> /// Executes the specified context. /// </summary> /// <param name="context">The context.</param> public void Execute( IJobExecutionContext context ) { var exceptionMsgs = new List<string>(); JobDataMap dataMap = context.JobDetail.JobDataMap; Guid? groupGuid = dataMap.GetString( "EligibleFollowers" ).AsGuidOrNull(); Guid? systemEmailGuid = dataMap.GetString( "EmailTemplate" ).AsGuidOrNull(); int followingSuggestionsEmailsSent = 0; int followingSuggestionsSuggestionsTotal = 0; if ( groupGuid.HasValue && systemEmailGuid.HasValue ) { using ( var rockContext = new RockContext() ) { var followingService = new FollowingService( rockContext ); // The people who are eligible to get following suggestions based on the group type setting for this job var eligiblePersonIds = new GroupMemberService( rockContext ) .Queryable().AsNoTracking() .Where( m => m.Group != null && m.Group.Guid.Equals( groupGuid.Value ) && m.GroupMemberStatus == GroupMemberStatus.Active && m.Person != null && m.Person.Email != null && m.Person.Email != "" ) .Select( m => m.PersonId ) .Distinct(); // check to see if there are any event types that require notification var followerPersonIds = new List<int>(); if ( new FollowingEventTypeService( rockContext ) .Queryable().AsNoTracking() .Any( e => e.IsNoticeRequired ) ) { // if so, include all eligible people followerPersonIds = eligiblePersonIds.ToList(); } else { // if not, filter the list of eligible people down to only those that actually have subscribed to one or more following events followerPersonIds = new FollowingEventSubscriptionService( rockContext ) .Queryable().AsNoTracking() .Where( f => eligiblePersonIds.Contains( f.PersonAlias.PersonId ) ) .Select( f => f.PersonAlias.PersonId ) .Distinct() .ToList(); } if ( followerPersonIds.Any() ) { // Get the primary person alias id for each of the followers var primaryAliasIds = new Dictionary<int, int>(); new PersonAliasService( rockContext ) .Queryable().AsNoTracking() .Where( a => followerPersonIds.Contains( a.PersonId ) && a.PersonId == a.AliasPersonId ) .ToList() .ForEach( a => primaryAliasIds.AddOrIgnore( a.PersonId, a.Id ) ); // Get current date/time. var timestamp = RockDateTime.Now; var suggestionTypes = new FollowingSuggestionTypeService( rockContext ) .Queryable().AsNoTracking() .Where( s => s.IsActive ) .OrderBy( s => s.Name ) .ToList(); var components = new Dictionary<int, SuggestionComponent>(); var suggestedEntities = new Dictionary<int, Dictionary<int, IEntity>>(); foreach ( var suggestionType in suggestionTypes ) { try { // Get the suggestion type component var suggestionComponent = suggestionType.GetSuggestionComponent(); if ( suggestionComponent != null ) { components.Add( suggestionType.Id, suggestionComponent ); // Get the entitytype for this suggestion type var suggestionEntityType = EntityTypeCache.Read( suggestionComponent.FollowedType ); if ( suggestionEntityType != null ) { var entityIds = new List<int>(); // Call the components method to return all of it's suggestions var personEntitySuggestions = suggestionComponent.GetSuggestions( suggestionType, followerPersonIds ); // If any suggestions were returned by the component if ( personEntitySuggestions.Any() ) { int entityTypeId = suggestionEntityType.Id; string reasonNote = suggestionType.ReasonNote; // Get the existing followings for any of the followers var existingFollowings = new Dictionary<int, List<int>>(); foreach( var following in followingService.Queryable( "PersonAlias" ).AsNoTracking() .Where( f => f.EntityTypeId == entityTypeId && followerPersonIds.Contains( f.PersonAlias.PersonId ) ) ) { existingFollowings.AddOrIgnore( following.PersonAlias.PersonId, new List<int>() ); existingFollowings[ following.PersonAlias.PersonId].Add( following.EntityId ); } // Loop through each follower foreach ( var followerPersonId in personEntitySuggestions .Select( s => s.PersonId ) .Distinct() ) { using ( var suggestionContext = new RockContext() ) { var followingSuggestedService = new FollowingSuggestedService( suggestionContext ); // Read all the existing suggestions for this type and the returned followers var existingSuggestions = followingSuggestedService .Queryable( "PersonAlias" ) .Where( s => s.SuggestionTypeId == suggestionType.Id && s.PersonAlias.PersonId == followerPersonId ) .ToList(); // Look through the returned suggestions foreach ( var followedEntityId in personEntitySuggestions .Where( s => s.PersonId == followerPersonId ) .Select( s => s.EntityId ) ) { // Make sure person isn't already following this entity if ( !existingFollowings.ContainsKey( followerPersonId ) || !existingFollowings[followerPersonId].Contains( followedEntityId ) ) { // If this person had a primary alias id if ( primaryAliasIds.ContainsKey( followerPersonId ) ) { entityIds.Add( followedEntityId ); // Look for existing suggestion for this person and entity var suggestion = existingSuggestions .Where( s => s.EntityId == followedEntityId ) .OrderByDescending( s => s.StatusChangedDateTime ) .FirstOrDefault(); // If not found, add one if ( suggestion == null ) { suggestion = new FollowingSuggested(); suggestion.EntityTypeId = entityTypeId; suggestion.EntityId = followedEntityId; suggestion.PersonAliasId = primaryAliasIds[followerPersonId]; suggestion.SuggestionTypeId = suggestionType.Id; suggestion.Status = FollowingSuggestedStatus.PendingNotification; suggestion.StatusChangedDateTime = timestamp; followingSuggestedService.Add( suggestion ); } else { // If found, and it has not been ignored, and it's time to promote again, update the promote date if ( suggestion.Status != FollowingSuggestedStatus.Ignored && ( !suggestionType.ReminderDays.HasValue || !suggestion.LastPromotedDateTime.HasValue || suggestion.LastPromotedDateTime.Value.AddDays( suggestionType.ReminderDays.Value ) <= timestamp ) ) { if ( suggestion.Status != FollowingSuggestedStatus.PendingNotification ) { suggestion.StatusChangedDateTime = timestamp; suggestion.Status = FollowingSuggestedStatus.PendingNotification; } } } } } } // Save the suggestions for this type suggestionContext.SaveChanges(); } } } // If any entities are being suggested for this type, query database for them and save to dictionary if ( entityIds.Any() ) { if ( suggestionEntityType.AssemblyName != null ) { // get the actual type of what is being followed Type entityType = suggestionEntityType.GetEntityType(); if ( entityType != null ) { // Get generic queryable method and query all the entities that are being followed Type[] modelType = { entityType }; Type genericServiceType = typeof( Rock.Data.Service<> ); Type modelServiceType = genericServiceType.MakeGenericType( modelType ); Rock.Data.IService serviceInstance = Activator.CreateInstance( modelServiceType, new object[] { rockContext } ) as IService; MethodInfo qryMethod = serviceInstance.GetType().GetMethod( "Queryable", new Type[] { } ); var entityQry = qryMethod.Invoke( serviceInstance, new object[] { } ) as IQueryable<IEntity>; var entityList = entityQry.AsNoTracking().Where( q => entityIds.Contains( q.Id ) ).ToList(); if ( entityList != null && entityList.Any() ) { var entities = new Dictionary<int, IEntity>(); entityList.ForEach( e => entities.Add( e.Id, e ) ); suggestedEntities.Add( suggestionType.Id, entities ); } } } } } } } catch ( Exception ex ) { exceptionMsgs.Add( string.Format( "An exception occurred calculating suggestions for the '{0}' suggestion type:{1} {2}", suggestionType.Name, Environment.NewLine, ex.Messages().AsDelimited( Environment.NewLine + " " ) ) ); ExceptionLogService.LogException( ex, System.Web.HttpContext.Current ); } } var allSuggestions = new FollowingSuggestedService( rockContext ) .Queryable( "PersonAlias" ) .Where( s => s.Status == FollowingSuggestedStatus.PendingNotification ) .ToList(); var suggestionPersonIds = allSuggestions .Where( s => followerPersonIds.Contains( s.PersonAlias.PersonId ) ) .Select( s => s.PersonAlias.PersonId ) .Distinct() .ToList(); var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read( rockContext ).GetValue( "PublicApplicationRoot" ); foreach ( var person in new PersonService( rockContext ) .Queryable().AsNoTracking() .Where( p => suggestionPersonIds.Contains( p.Id ) ) .ToList() ) { try { var personSuggestionNotices = new List<FollowingSuggestionNotices>(); foreach ( var suggestionType in suggestionTypes ) { var component = components.ContainsKey( suggestionType.Id ) ? components[suggestionType.Id] : null; if ( component != null && suggestedEntities.ContainsKey( suggestionType.Id ) ) { var entities = new List<IEntity>(); foreach ( var suggestion in allSuggestions .Where( s => s.PersonAlias.PersonId == person.Id && s.SuggestionTypeId == suggestionType.Id ) .ToList() ) { if ( suggestedEntities[suggestionType.Id].ContainsKey( suggestion.EntityId ) ) { entities.Add( suggestedEntities[suggestionType.Id][suggestion.EntityId] ); suggestion.LastPromotedDateTime = timestamp; suggestion.Status = FollowingSuggestedStatus.Suggested; } } var notices = new List<string>(); foreach ( var entity in component.SortEntities( entities ) ) { notices.Add( component.FormatEntityNotification( suggestionType, entity ) ); } if ( notices.Any() ) { personSuggestionNotices.Add( new FollowingSuggestionNotices( suggestionType, notices ) ); } } } if ( personSuggestionNotices.Any() ) { // Send the notice var recipients = new List<RecipientData>(); var mergeFields = new Dictionary<string, object>(); mergeFields.Add( "Person", person ); mergeFields.Add( "Suggestions", personSuggestionNotices.OrderBy( s => s.SuggestionType.Order ).ToList() ); recipients.Add( new RecipientData( person.Email, mergeFields ) ); Email.Send( systemEmailGuid.Value, recipients, appRoot ); followingSuggestionsEmailsSent += recipients.Count(); followingSuggestionsSuggestionsTotal += personSuggestionNotices.Count(); } rockContext.SaveChanges(); } catch ( Exception ex ) { exceptionMsgs.Add( string.Format( "An exception occurred sending suggestions to '{0}':{1} {2}", person.FullName, Environment.NewLine, ex.Messages().AsDelimited( Environment.NewLine + " " ) ) ); ExceptionLogService.LogException( ex, System.Web.HttpContext.Current ); } } } } } context.Result = string.Format( "A total of {0} following suggestions sent to {1} people", followingSuggestionsSuggestionsTotal, followingSuggestionsEmailsSent ); if ( exceptionMsgs.Any() ) { throw new Exception( "One or more exceptions occurred calculating suggestions..." + Environment.NewLine + exceptionMsgs.AsDelimited( Environment.NewLine ) ); } }
void lbIgnore_Click( object sender, EventArgs e ) { // Get the suggestion ids that were selected var itemsSelected = new List<int>(); gSuggestions.SelectedKeys.ToList().ForEach( f => itemsSelected.Add( f.ToString().AsInteger() ) ); // If any items were selected if ( itemsSelected.Any() ) { using ( var rockContext = new RockContext() ) { // Update the status of each suggestion to be ignored var followingSuggestedService = new FollowingSuggestedService( rockContext ); foreach ( var suggestion in followingSuggestedService.Queryable() .Where( f => itemsSelected.Contains( f.Id ) ) ) { suggestion.Status = FollowingSuggestedStatus.Ignored; } rockContext.SaveChanges(); } } BindGrid(); }
/// <summary> /// Handles the Click event of the lbUnfollow control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> void lbFollow_Click( object sender, EventArgs e ) { // Get the suggestion ids that were selected var itemsSelected = new List<int>(); gSuggestions.SelectedKeys.ToList().ForEach( f => itemsSelected.Add( f.ToString().AsInteger() ) ); // Get the personAlias entity type var personAliasEntityType = EntityTypeCache.Read( typeof( Rock.Model.PersonAlias )); // If we have a valid current person and items were selected if ( personAliasEntityType != null && CurrentPersonAliasId.HasValue && itemsSelected.Any() ) { using ( var rockContext = new RockContext() ) { // Get all the person alias id's that were selected var followingSuggestedService = new FollowingSuggestedService( rockContext ); var selectedPersonAliasIds = followingSuggestedService .Queryable() .Where( f => itemsSelected.Contains( f.Id ) ) .Select( f => f.EntityId ) .Distinct() .ToList(); // Find any of the selected person alias ids that current person is already following var followingService = new FollowingService( rockContext ); var alreadyFollowing = followingService .Queryable() .Where( f => f.EntityTypeId == personAliasEntityType.Id && f.PersonAliasId == CurrentPersonAliasId.Value && selectedPersonAliasIds.Contains( f.EntityId ) ) .Select( f => f.EntityId ) .Distinct() .ToList(); // For each selected person alias id that the current person is not already following foreach ( var personAliasId in selectedPersonAliasIds.Where( p => !alreadyFollowing.Contains( p ) ) ) { // Add a following record var following = new Following(); following.EntityTypeId = personAliasEntityType.Id; following.EntityId = personAliasId; following.PersonAliasId = CurrentPersonAliasId.Value; followingService.Add( following ); } rockContext.SaveChanges(); } } BindGrid(); }
/// <summary> /// Binds the grid. /// </summary> private void BindGrid() { var personAliasEntityType = EntityTypeCache.Read( "Rock.Model.PersonAlias" ); if ( personAliasEntityType != null && CurrentPersonAlias != null ) { var rockContext = new RockContext(); // PersonAlias query for joining the followed entity id to var personAliasQry = new PersonAliasService( rockContext ).Queryable(); // Get all the people that the current person currently follows var followedPersonIds = new FollowingService( rockContext ).Queryable() .Where( f => f.EntityTypeId == personAliasEntityType.Id && f.PersonAliasId == CurrentPersonAlias.Id ) .Join( personAliasQry, s => s.EntityId, p => p.Id, ( s, p ) => p.PersonId ) .Distinct(); // Get all the person suggestions for the current person that they are not already following var qry = new FollowingSuggestedService( rockContext ) .Queryable("SuggestionType") .Where( s => s.SuggestionType != null && s.EntityTypeId == personAliasEntityType.Id && s.PersonAliasId == CurrentPersonAlias.Id ) .Join( personAliasQry, s => s.EntityId, p => p.Id, ( s, p ) => new { s, p } ) .Where( j => !followedPersonIds.Contains( j.p.PersonId ) ) .Select( j => new { j.s.Id, j.s.LastPromotedDateTime, j.s.StatusChangedDateTime, j.s.SuggestionType.ReasonNote, j.s.Status, Person = j.p.Person, LastName = j.p.Person.LastName, NickName = j.p.Person.NickName } ); // Sort the result SortProperty sortProperty = gSuggestions.SortProperty; if ( sortProperty == null ) { sortProperty = new SortProperty( new GridViewSortEventArgs( "LastName,NickName", SortDirection.Ascending ) ); } // Bind grid to the query gSuggestions.DataSource = qry.Sort( sortProperty ) .Select( s => new { s.Id, s.LastPromotedDateTime, s.StatusChangedDateTime, s.ReasonNote, s.Status, StatusLabel = s.Status == FollowingSuggestedStatus.Ignored ? "<span class='label label-warning'>Ignored</span>" : "<span class='label label-success'>Suggested</span>", s.Person, s.LastName, s.NickName } ) .ToList(); gSuggestions.DataBind(); } }