/// <summary> /// Updates the Connection Requests to us the new To person /// </summary> protected void UpdateConnectionRequests() { //Get the selected people FromPersonId = ppFrom.PersonId; ToPersonId = ppTo.PersonId; // Create Needed Services ConnectionRequestService connectionRequestService = new ConnectionRequestService(rockContext); //Get Connection Requests from From person var assigned = connectionRequestService.Queryable().Where(a => a.ConnectorPersonAliasId == FromPersonId); //Set each Connection Request in From person to To person foreach (var x in assigned) { x.ConnectorPersonAliasId = ToPersonId; x.ModifiedDateTime = DateTime.Now; x.ModifiedByPersonAliasId = CurrentPersonAliasId; } //Save changes rockContext.SaveChanges(); //Update UI nbSuccess.Visible = true; }
/// <summary> /// Creates a Linq Expression that can be applied to an IQueryable to filter the result set. /// </summary> /// <param name="entityType">The type of entity in the result set.</param> /// <param name="serviceInstance">A service instance that can be queried to obtain the result set.</param> /// <param name="parameterExpression">The input parameter that will be injected into the filter expression.</param> /// <param name="selection">A formatted string representing the filter settings.</param> /// <returns> /// A Linq Expression that can be used to filter an IQueryable. /// </returns> /// <exception cref="System.Exception">Filter issue(s): + errorMessages.AsDelimited( ; )</exception> public override Expression GetExpression(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, string selection) { var settings = new FilterSettings(selection); var context = ( RockContext )serviceInstance.Context; // Get the Connection Request Data View. var dataView = DataComponentSettingsHelper.GetDataViewForFilterComponent(settings.DataViewGuid, context); // Evaluate the Data View that defines the Person's Connection Request. var connectionRequestService = new ConnectionRequestService(context); var connectionRequestQuery = connectionRequestService.Queryable(); if (dataView != null) { connectionRequestQuery = DataComponentSettingsHelper.FilterByDataView(connectionRequestQuery, dataView, connectionRequestService); } var connectionRequestPersonsKey = connectionRequestQuery.Select(a => a.PersonAliasId); // Get all of the Person corresponding to the qualifying Benevolence Requests. var qry = new PersonService(context).Queryable() .Where(g => g.Aliases.Any(k => connectionRequestPersonsKey.Contains(k.Id))); // Retrieve the Filter Expression. var extractedFilterExpression = FilterExpressionExtractor.Extract <Model.Person>(qry, parameterExpression, "g"); return(extractedFilterExpression); }
public void ConnectionRequestDateKeyJoinsCorrectly() { var expectedRecordCount = 15; var year = 2015; using (var rockContext = new RockContext()) { var connectionRequestService = new ConnectionRequestService(rockContext); var minDateValue = TestDataHelper.GetAnalyticsSourceMinDateForYear(rockContext, year); var maxDateValue = TestDataHelper.GetAnalyticsSourceMaxDateForYear(rockContext, year); for (var i = 0; i < 15; i++) { var connectionRequest = BuildConnectionRequest(rockContext, TestDataHelper.GetRandomDateInRange(minDateValue, maxDateValue)); connectionRequestService.Add(connectionRequest); } rockContext.SaveChanges(); } using (var rockContext = new RockContext()) { var connectionRequestService = new ConnectionRequestService(rockContext); var connectionRequests = connectionRequestService. Queryable(). Where(i => i.ForeignKey == connectionRequestForeignKey). Where(i => i.CreatedSourceDate.CalendarYear == year); Assert.AreEqual(expectedRecordCount, connectionRequests.Count()); Assert.IsNotNull(connectionRequests.First().CreatedSourceDate); } }
/// <summary> /// Handles the ItemDataBound event of the rConnectionTypes control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RepeaterItemEventArgs"/> instance containing the event data.</param> protected void rConnectionTypes_ItemDataBound(object sender, RepeaterItemEventArgs e) { var lConnectionOpportunityList = e.Item.FindControl("lConnectionOpportunityList") as Literal; if (lConnectionOpportunityList != null) { var connectionType = e.Item.DataItem as ConnectionType; var pageGuid = this.GetAttributeValue("ConnectionRequestDetail").AsGuidOrNull(); PageReference connectionRequestDetailPage = null; if (pageGuid.HasValue) { connectionRequestDetailPage = new PageReference(pageGuid.Value.ToString()); } if (connectionType != null && this.Person != null) { using (var rockContext = new RockContext()) { int personId = this.Person.Id; var connectionRequestService = new ConnectionRequestService(rockContext); var connectionRequestList = connectionRequestService.Queryable().Where(a => a.PersonAlias.PersonId == personId && a.ConnectionOpportunity.ConnectionTypeId == connectionType.Id).OrderBy(a => a.ConnectionOpportunity.Name).AsNoTracking().ToList(); string listHtml = string.Empty; foreach (var connectionRequest in connectionRequestList) { string connectionNameHtml; string connectionName; if (connectionRequest.CampusId.HasValue) { connectionName = string.Format("{0} ({1})", connectionRequest.ConnectionOpportunity, CampusCache.Read(connectionRequest.CampusId.Value)); } else { connectionName = string.Format("{0}", connectionRequest.ConnectionOpportunity); } if (connectionRequestDetailPage != null && connectionRequestDetailPage.PageId > 0) { connectionRequestDetailPage.Parameters = new System.Collections.Generic.Dictionary <string, string>(); connectionRequestDetailPage.Parameters.Add("ConnectionRequestId", connectionRequest.Id.ToString()); connectionRequestDetailPage.Parameters.Add("ConnectionOpportunityId", connectionRequest.ConnectionOpportunityId.ToString()); connectionNameHtml = string.Format("<a href='{0}'>{1}</a>", connectionRequestDetailPage.BuildUrl(), connectionName); } else { connectionNameHtml = connectionName; } listHtml += string.Format( "<li {0}>{1} - <small>{2}</small></li>", (connectionRequest.ConnectionState == ConnectionState.Connected || connectionRequest.ConnectionState == ConnectionState.Inactive) ? "class='is-inactive'" : string.Empty, connectionNameHtml, connectionRequest.ConnectionState == ConnectionState.Connected ? "Connected" : connectionRequest.ConnectionStatus.ToString()); } lConnectionOpportunityList.Text = listHtml; } } } }
/// <summary> /// Get the connector based on entity Item and campaign configuration. /// </summary> /// <param name="campaignItem">The campaign item.</param> /// <param name="connectionOpportunity">The connection opportunity.</param> /// <param name="eligibleConnectors">The eligible connectors.</param> /// <param name="entityItemPersonAlias">The entity set item person alias.</param> /// <param name="rockContext">The rock context.</param> /// <returns></returns> private int?GetConnector(CampaignItem campaignItem, ConnectionOpportunity connectionOpportunity, List <ConnectionConnector> eligibleConnectors, PersonAlias entityItemPersonAlias, RockContext rockContext) { int?connectorPersonId = null; var dayofWeek = RockDateTime.Now.DayOfWeek; var connectionRequestService = new ConnectionRequestService(rockContext); var defaultCampus = entityItemPersonAlias.Person.GetCampus(); if (campaignItem.PreferPreviousConnector) { var personIds = eligibleConnectors .Where(a => a.Limit - a.Current > 0 && (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) && (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value))) .Select(a => a.PersonId) .ToList(); if (personIds.Any()) { var person = connectionRequestService .Queryable() .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id && a.PersonAlias.PersonId == entityItemPersonAlias.PersonId && a.ConnectionState == ConnectionState.Connected && a.ConnectorPersonAliasId.HasValue && personIds.Contains(a.ConnectorPersonAlias.PersonId) && a.ModifiedDateTime.HasValue) .OrderByDescending(a => a.ModifiedDateTime) .Select(a => a.ConnectorPersonAlias.Person) .FirstOrDefault(); if (person != null) { connectorPersonId = person.Id; } } } if (!connectorPersonId.HasValue) { var eligibleConnector = eligibleConnectors .Where(a => a.Limit - a.Current > 0 && (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) && (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value))) .OrderBy(a => a.Current) // order from least assigned to most assigned .ThenBy(x => Guid.NewGuid()) // and then randomize .FirstOrDefault(); if (eligibleConnector != null) { connectorPersonId = eligibleConnector.PersonId; } } return(connectorPersonId); }
/// <summary> /// Gets both the opportunity request counts (TotalCount and AssignedToYouCount) for the /// given opportunities. The Person the service was initialized with is used to calculate /// <see cref="ConnectionRequestCountsViewModel.AssignedToYouCount"/>. /// </summary> /// <remarks>This method does not check security, it is assumed you have already done so.</remarks> /// <param name="connectionOpportunityIds">The connection opportunity identifiers.</param> /// <returns>A dictionary of connection request count objects.</returns> public Dictionary <int, ConnectionRequestCountsViewModel> GetOpportunityRequestCounts(IEnumerable <int> connectionOpportunityIds) { var connectionRequestService = new ConnectionRequestService(RockContext); // Create all counts as initially empty, this method must always return // a value for each opportunity id. var requestCounts = connectionOpportunityIds.ToDictionary(id => id, _ => new ConnectionRequestCountsViewModel()); // Find all the connection requests assigned to the person. var activeConnectionRequestQry = connectionRequestService.Queryable() .Where(r => connectionOpportunityIds.Contains(r.ConnectionOpportunityId) && r.ConnectionState == ConnectionState.Active); // Group them by the connection opportunity and get the counts for // each opportunity. if (Person != null) { // If we have a Person (Person.Id) count their requests into the AssignedToYouCount along with the TotalCount. activeConnectionRequestQry .GroupBy(r => r.ConnectionOpportunityId) .Select(g => new { Id = g.Key, Count = g.Count(r => r.ConnectorPersonAliasId.HasValue && r.ConnectorPersonAlias.PersonId == Person.Id), TotalCount = g.Count() }) .ToList() .ForEach(o => { requestCounts[o.Id].AssignedToYouCount = o.Count; requestCounts[o.Id].TotalCount = o.TotalCount; }); } else { // Otherwise, we can only count the total into the TotalCount. activeConnectionRequestQry .GroupBy(r => r.ConnectionOpportunityId) .Select(g => new { Id = g.Key, TotalCount = g.Count() }) .ToList() .ForEach(o => requestCounts[o.Id].TotalCount = o.TotalCount); } return(requestCounts); }
/// <summary> /// Gets any (active or past due FutureFollowUp) connection requests that don't have a connector /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="selectedCampaignItem">The selected campaign item.</param> /// <param name="connectorPerson">The connector person.</param> /// <returns></returns> public static IQueryable <ConnectionRequest> GetConnectionRequestsWithoutConnectorQuery(RockContext rockContext, CampaignItem selectedCampaignItem, Person connectorPerson) { var connectionRequestService = new ConnectionRequestService(rockContext); var currentDate = RockDateTime.Today; var connectorCampusIds = GetConnectorCampusIds(selectedCampaignItem, connectorPerson); // first, get any (active or past due FutureFollowUp) connection requests that don't have a connector var connectionRequestsWithoutConnectorQuery = connectionRequestService.Queryable() .Where(a => a.ConnectionOpportunity.Guid == selectedCampaignItem.OpportunityGuid && a.ConnectorPersonAliasId == null && (a.ConnectionState == ConnectionState.Active || (a.ConnectionState == ConnectionState.FutureFollowUp && a.FollowupDate < currentDate))) // only include pending connection requests that have a null campus, or the campus matches the connector's campus .Where(a => (a.CampusId == null) || connectorCampusIds.Any(connectorCampusId => connectorCampusId == null || a.CampusId.Value == connectorCampusId)); return(connectionRequestsWithoutConnectorQuery); }
/// <summary> /// Get's all of the (get connected/ follow up) *requests* for a given person /// </summary> /// <param name="currentPerson">The leader</param> /// <returns></returns> public static IQueryable <ConnectionRequest> GetPeopleInLineFollowUpRequests(Person currentPerson) { if (currentPerson == null) { return(new List <ConnectionRequest>().AsQueryable()); } var rockContext = new RockContext(); var connectionRequestService = new ConnectionRequestService(rockContext); int getConnectedOpportunityId = new ConnectionOpportunityService(rockContext).Get( SystemGuid.ConnectionOpportunity.GET_CONNECTED.AsGuid()).Id; var connectionRequests = connectionRequestService .Queryable() .Where(c => c.ConnectionOpportunityId == getConnectedOpportunityId && c.ConnectorPersonAliasId == currentPerson.PrimaryAliasId && c.ConnectionState == ConnectionState.Active); return(connectionRequests); }
/// <summary> /// Gets the opportunity request counts for the given opportunities. The /// Person the service was initialized with is used to calculate /// <see cref="ConnectionRequestCountsViewModel.AssignedToYouCount"/>. /// </summary> /// <remarks>This method does not check security, it is assumed you have already done so.</remarks> /// <param name="connectionOpportunityIds">The connection opportunity identifiers.</param> /// <returns>A dictionary of connection request count objects.</returns> public Dictionary <int, ConnectionRequestCountsViewModel> GetOpportunityRequestCounts(IEnumerable <int> connectionOpportunityIds) { var connectionRequestService = new ConnectionRequestService(RockContext); // Create all counts as initially empty, this method must always return // a value for each opportunity id. var requestCounts = connectionOpportunityIds.ToDictionary(id => id, _ => new ConnectionRequestCountsViewModel()); // Fast out, if there is no logged in person then just return a // bunch of zeros for now. Later if we add other counts we might // need more complex logic. if (Person == null) { return(requestCounts); } // Find all the connection requests assigned to the person. var assignedToYouRequestQry = connectionRequestService.Queryable() .Where(r => connectionOpportunityIds.Contains(r.ConnectionOpportunityId) && r.ConnectionState == ConnectionState.Active && r.ConnectorPersonAliasId.HasValue && r.ConnectorPersonAlias.PersonId == Person.Id); // Group them by the connection opportunity and get the counts for // each opportunity. assignedToYouRequestQry .GroupBy(r => r.ConnectionOpportunityId) .Select(g => new { Id = g.Key, Count = g.Count() }) .ToList() .ForEach(o => requestCounts[o.Id].AssignedToYouCount = o.Count); return(requestCounts); }
public void Execute(IJobExecutionContext context) { JobDataMap dataMap = context.JobDetail.JobDataMap; var rockContext = new RockContext(); var connectionOpportunities = dataMap.GetString("ConnectionOpportunities").SplitDelimitedValues(); var systemEmail = dataMap.GetString("Email").AsGuidOrNull(); if (!systemEmail.HasValue) { throw new Exception("System Email is required!"); } // get job type id int jobId = Convert.ToInt16(context.JobDetail.Description); var jobService = new ServiceJobService(rockContext); var job = jobService.Get(jobId); DateTime _midnightToday = RockDateTime.Today.AddDays(1); var currentDateTime = RockDateTime.Now; var recipients = new List <RockEmailMessageRecipient>(); ConnectionRequestService connectionRequestService = new ConnectionRequestService(rockContext); PersonService personService = new PersonService(rockContext); var connectionRequestsQry = connectionRequestService.Queryable().Where(cr => connectionOpportunities.Contains(cr.ConnectionOpportunity.Guid.ToString()) && cr.ConnectorPersonAliasId != null && ( cr.ConnectionState == ConnectionState.Active || (cr.ConnectionState == ConnectionState.FutureFollowUp && cr.FollowupDate.HasValue && cr.FollowupDate.Value < _midnightToday) )); var connectionRequestGroups = connectionRequestsQry.GroupBy(cr => cr.ConnectorPersonAlias.PersonId); foreach (var group in connectionRequestGroups) { Person person = personService.Get(group.Key); List <ConnectionOpportunity> opportunities = group.Select(a => a.ConnectionOpportunity).Distinct().ToList(); var newConnectionRequests = group.Where(cr => cr.CreatedDateTime >= job.LastRunDateTime).GroupBy(cr => cr.ConnectionOpportunityId).ToList(); // Get all the idle connections var idleConnectionRequests = group .Where(cr => ( (cr.ConnectionRequestActivities.Any() && cr.ConnectionRequestActivities.Max(ra => ra.CreatedDateTime) < currentDateTime.AddDays(-cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle))) || (!cr.ConnectionRequestActivities.Any() && cr.CreatedDateTime < currentDateTime.AddDays(-cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle)) ) .Select(a => new { ConnectionOpportunityId = a.ConnectionOpportunityId, Id = a.Id }) .GroupBy(cr => cr.ConnectionOpportunityId).ToList(); // get list of requests that have a status that is considered critical. var criticalConnectionRequests = group .Where(r => r.ConnectionStatus.IsCritical ) .Select(a => new { ConnectionOpportunityId = a.ConnectionOpportunityId, Id = a.Id }) .GroupBy(cr => cr.ConnectionOpportunityId).ToList(); var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null); mergeFields.Add("ConnectionOpportunities", opportunities); mergeFields.Add("ConnectionRequests", group.GroupBy(cr => cr.ConnectionOpportunity).ToList()); mergeFields.Add("NewConnectionRequests", newConnectionRequests); mergeFields.Add("IdleConnectionRequestIds", idleConnectionRequests); mergeFields.Add("CriticalConnectionRequestIds", criticalConnectionRequests); mergeFields.Add("Person", person); mergeFields.Add("LastRunDate", job.LastRunDateTime); recipients.Add(new RockEmailMessageRecipient(person, mergeFields)); } var emailMessage = new RockEmailMessage(systemEmail.Value); emailMessage.SetRecipients(recipients); emailMessage.CreateCommunicationRecord = dataMap.GetString("SaveCommunicationHistory").AsBoolean(); emailMessage.Send(); context.Result = string.Format("Sent " + recipients.Count + " connection digest emails."); }
/// <summary> /// Deletes the family's addresses, phone numbers, photos, viewed records, and people. /// TODO: delete attendance codes for attendance data that's about to be deleted when /// we delete the person record. /// </summary> /// <param name="families">The families.</param> /// <param name="rockContext">The rock context.</param> private void DeleteExistingFamilyData( XElement families, RockContext rockContext ) { PersonService personService = new PersonService( rockContext ); PhoneNumberService phoneNumberService = new PhoneNumberService( rockContext ); PersonViewedService personViewedService = new PersonViewedService( rockContext ); PageViewService pageViewService = new PageViewService( rockContext ); BinaryFileService binaryFileService = new BinaryFileService( rockContext ); PersonAliasService personAliasService = new PersonAliasService( rockContext ); PersonDuplicateService personDuplicateService = new PersonDuplicateService( rockContext ); NoteService noteService = new NoteService( rockContext ); AuthService authService = new AuthService( rockContext ); CommunicationService communicationService = new CommunicationService( rockContext ); CommunicationRecipientService communicationRecipientService = new CommunicationRecipientService( rockContext ); FinancialBatchService financialBatchService = new FinancialBatchService( rockContext ); FinancialTransactionService financialTransactionService = new FinancialTransactionService( rockContext ); PersonPreviousNameService personPreviousNameService = new PersonPreviousNameService( rockContext ); ConnectionRequestService connectionRequestService = new ConnectionRequestService( rockContext ); ConnectionRequestActivityService connectionRequestActivityService = new ConnectionRequestActivityService( rockContext ); // delete the batch data List<int> imageIds = new List<int>(); foreach ( var batch in financialBatchService.Queryable().Where( b => b.Name.StartsWith( "SampleData" ) ) ) { imageIds.AddRange( batch.Transactions.SelectMany( t => t.Images ).Select( i => i.BinaryFileId ).ToList() ); financialTransactionService.DeleteRange( batch.Transactions ); financialBatchService.Delete( batch ); } // delete all transaction images foreach ( var image in binaryFileService.GetByIds( imageIds ) ) { binaryFileService.Delete( image ); } foreach ( var elemFamily in families.Elements( "family" ) ) { Guid guid = elemFamily.Attribute( "guid" ).Value.Trim().AsGuid(); GroupService groupService = new GroupService( rockContext ); Group family = groupService.Get( guid ); if ( family != null ) { var groupMemberService = new GroupMemberService( rockContext ); var members = groupMemberService.GetByGroupId( family.Id, true ); // delete the people records string errorMessage; List<int> photoIds = members.Select( m => m.Person ).Where( p => p.PhotoId != null ).Select( a => (int)a.PhotoId ).ToList(); foreach ( var person in members.Select( m => m.Person ) ) { person.GivingGroup = null; person.GivingGroupId = null; person.PhotoId = null; // delete phone numbers foreach ( var phone in phoneNumberService.GetByPersonId( person.Id ) ) { if ( phone != null ) { phoneNumberService.Delete( phone ); } } // delete communication recipient foreach ( var recipient in communicationRecipientService.Queryable().Where( r => r.PersonAlias.PersonId == person.Id ) ) { communicationRecipientService.Delete( recipient ); } // delete communication foreach ( var communication in communicationService.Queryable().Where( c => c.SenderPersonAliasId == person.PrimaryAlias.Id ) ) { communicationService.Delete( communication ); } // delete person viewed records foreach ( var view in personViewedService.GetByTargetPersonId( person.Id ) ) { personViewedService.Delete( view ); } // delete page viewed records foreach ( var view in pageViewService.GetByPersonId( person.Id ) ) { pageViewService.Delete( view ); } // delete notes created by them or on their record. foreach ( var note in noteService.Queryable().Where ( n => n.CreatedByPersonAlias.PersonId == person.Id || (n.NoteType.EntityTypeId == _personEntityTypeId && n.EntityId == person.Id ) ) ) { noteService.Delete( note ); } // delete previous names on their records foreach ( var previousName in personPreviousNameService.Queryable().Where( r => r.PersonAlias.PersonId == person.Id ) ) { personPreviousNameService.Delete( previousName ); } // delete any GroupMember records they have foreach ( var groupMember in groupMemberService.Queryable().Where( gm => gm.PersonId == person.Id ) ) { groupMemberService.Delete( groupMember ); } //// delete any Authorization data //foreach ( var auth in authService.Queryable().Where( a => a.PersonId == person.Id ) ) //{ // authService.Delete( auth ); //} // delete their aliases foreach ( var alias in personAliasService.Queryable().Where( a => a.PersonId == person.Id ) ) { foreach ( var duplicate in personDuplicateService.Queryable().Where( d => d.DuplicatePersonAliasId == alias.Id ) ) { personDuplicateService.Delete( duplicate ); } personAliasService.Delete( alias ); } // delete any connection requests tied to them foreach ( var request in connectionRequestService.Queryable().Where( r => r.PersonAlias.PersonId == person.Id || r.ConnectorPersonAlias.PersonId == person.Id ) ) { connectionRequestActivityService.DeleteRange( request.ConnectionRequestActivities ); connectionRequestService.Delete( request ); } // Save these changes so the CanDelete passes the check... //rockContext.ChangeTracker.DetectChanges(); rockContext.SaveChanges( disablePrePostProcessing: true ); if ( personService.CanDelete( person, out errorMessage ) ) { personService.Delete( person ); //rockContext.ChangeTracker.DetectChanges(); //rockContext.SaveChanges( disablePrePostProcessing: true ); } else { throw new Exception( string.Format( "Trying to delete {0}, but: {1}", person.FullName, errorMessage ) ); } } //rockContext.ChangeTracker.DetectChanges(); rockContext.SaveChanges( disablePrePostProcessing: true ); // delete all member photos foreach ( var photo in binaryFileService.GetByIds( photoIds ) ) { binaryFileService.Delete( photo ); } DeleteGroupAndMemberData( family, rockContext ); } } }
/// <summary> /// Returns the number of Workflows and Connection Requests for the selected Fron person, then populates grids. /// </summary> protected void UpdateUi() { // Get the selected person FromPersonId = ppFrom.PersonId; // Construct List var workflowResultList = new List <WorkflowActivity>(); var connectionRequestResultList = new List <ConnectionRequest>(); // Create Needed Services WorkflowActivityService workflowActivityService = new WorkflowActivityService(rockContext); ConnectionRequestService connectionRequestService = new ConnectionRequestService(rockContext); // Get Workflows from From person var assignedWorkflows = workflowActivityService.Queryable() .Where( a => a.AssignedPersonAliasId == FromPersonId && a.CompletedDateTime == null && a.Workflow.CompletedDateTime == null); // Get Connection Requests from From person var assignedConnectionRequests = connectionRequestService.Queryable() .Where( b => b.ConnectorPersonAliasId == FromPersonId && b.ConnectionState != ConnectionState.Connected && b.ConnectionState != ConnectionState.Inactive); // UI Updates if (ppFrom.PersonId != null) { foreach (var workflow in assignedWorkflows) { workflowResultList.Add(workflow); } foreach (var connectionRequest in assignedConnectionRequests) { connectionRequestResultList.Add(connectionRequest); } lbCount.Text = assignedWorkflows.Count() + " open workflows assigned to this person.<br />" + assignedConnectionRequests.Count() + " open Connection Requests assigned to this person."; gWorkflows.DataSource = workflowResultList; gWorkflows.DataBind(); gConnections.DataSource = connectionRequestResultList; gConnections.DataBind(); if (assignedWorkflows.Any()) { btnSaveWorkflows.Visible = true; ppTo.Visible = true; } if (assignedConnectionRequests.Any()) { btnSaveConnections.Visible = true; ppTo.Visible = true; } } else { nbSuccess.Visible = false; nbWarningMessage.Visible = false; } }
/// <summary> /// Processes the connection type. /// </summary> /// <param name="connectionTypeView">The connection type view.</param> /// <param name="updatedResults">The updated results.</param> /// <param name="errorMessages">The error message.</param> private void ProcessConnectionType( ConnectionTypeView connectionTypeView, ConcurrentBag <int> updatedResults, out List <string> errorMessages) { errorMessages = new List <string>(); var groupViews = new List <GroupView>(); foreach (var connectionStatus in connectionTypeView.ConnectionStatuses) { foreach (var connectionStatusAutomation in connectionStatus.ConnectionStatusAutomations) { var rockContext = new RockContext(); var connectionRequestService = new ConnectionRequestService(rockContext); var connectionRequestQry = connectionRequestService.Queryable().Include(a => a.AssignedGroup.Members).Where(a => a.ConnectionStatusId == connectionStatus.Id); if (connectionStatusAutomation.DataViewId.HasValue) { // Get the dataview configured for the connection request var dataViewService = new DataViewService(rockContext); var dataview = dataViewService.Get(connectionStatusAutomation.DataViewId.Value); if (dataview == null) { errorMessages.Add($"The dataview {connectionStatusAutomation.DataViewId} for Connection Type {connectionTypeView.ConnectionTypeId} did not resolve"); continue; } // Now we'll filter our connection request query to only include the ones that are in the configured data view. var dataViewGetQueryArgs = new DataViewGetQueryArgs { DbContext = rockContext }; IQueryable <ConnectionRequest> dataviewQuery; try { dataviewQuery = dataview.GetQuery(dataViewGetQueryArgs) as IQueryable <ConnectionRequest>; } catch (Exception ex) { errorMessages.Add(ex.Message); ExceptionLogService.LogException(ex); continue; } if (dataviewQuery == null) { errorMessages.Add($"Generating a query for dataview {connectionStatusAutomation.DataViewId} for Status {connectionStatus.Id} in Connection Type {connectionTypeView.ConnectionTypeId} was not successful"); continue; } connectionRequestQry = connectionRequestQry.Where(a => dataviewQuery.Any(b => b.Id == a.Id)); } var eligibleConnectionRequests = new List <ConnectionRequest>(); if (connectionStatusAutomation.GroupRequirementsFilter != GroupRequirementsFilter.Ignore) { var connectionRequests = connectionRequestQry.ToList(); foreach (var connectionRequest in connectionRequests) { // Group Requirement can't be met when either placement group or placement group role id is missing if (connectionRequest.AssignedGroupId.HasValue && connectionRequest.AssignedGroupMemberRoleId.HasValue) { var groupView = GetGroupView(connectionRequest, groupViews, rockContext); if (groupView != null && groupView.HasGroupRequirement) { var isRequirementMet = IsGroupRequirementMet(connectionRequest, groupView, rockContext); // connection request based on if group requirement is met or not is added to list for status update if ((connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.DoesNotMeet && !isRequirementMet) || (connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.MustMeet && isRequirementMet)) { eligibleConnectionRequests.Add(connectionRequest); } } } } } else { eligibleConnectionRequests = connectionRequestQry.ToList(); } var updatedCount = 0; foreach (var connectionRequest in eligibleConnectionRequests) { connectionRequest.ConnectionStatusId = connectionStatusAutomation.DestinationStatusId; updatedCount++; } rockContext.SaveChanges(); updatedResults.Add(updatedCount); } } }
/// <summary> /// Processes the connection type. /// </summary> /// <param name="connectionTypeView">The connection type view.</param> /// <param name="updatedResults">The updated results.</param> /// <param name="errorMessages">The error message.</param> private void ProcessConnectionType( ConnectionTypeView connectionTypeView, ConcurrentBag <int> updatedResults, out List <string> errorMessages) { errorMessages = new List <string>(); var groupViews = new List <GroupView>(); foreach (var connectionStatus in connectionTypeView.ConnectionStatuses) { foreach (var connectionStatusAutomation in connectionStatus.ConnectionStatusAutomations.OrderBy(a => a.AutomationName)) { var rockContext = new RockContext(); rockContext.Database.CommandTimeout = commandTimeout; var connectionRequestService = new ConnectionRequestService(rockContext); var destinationStatusId = connectionStatusAutomation.DestinationStatusId; // Limit to connection requests that don't already have the same connection status that this automation sets it to var connectionRequestQry = connectionRequestService.Queryable() .Where(a => a.ConnectionStatusId == connectionStatus.Id && a.ConnectionStatusId != connectionStatusAutomation.DestinationStatusId) .Include(a => a.ConnectionOpportunity).Include(a => a.PersonAlias); if (connectionStatusAutomation.GroupRequirementsFilter != GroupRequirementsFilter.Ignore) { // if we need to process GroupRequirements, include AssignedGroup.Members to avoid some lazy loading. connectionRequestQry = connectionRequestQry.Include(a => a.AssignedGroup.Members); } if (connectionStatusAutomation.DataViewId.HasValue) { // Get the dataview configured for the connection request var dataViewService = new DataViewService(rockContext); var dataview = dataViewService.Get(connectionStatusAutomation.DataViewId.Value); if (dataview == null) { errorMessages.Add($"The dataview {connectionStatusAutomation.DataViewId} for Connection Type {connectionTypeView.ConnectionTypeId} did not resolve"); continue; } IQueryable <ConnectionRequest> dataviewQuery; try { dataviewQuery = connectionRequestService.GetQueryUsingDataView(dataview); } catch (Exception ex) { errorMessages.Add(ex.Message); ExceptionLogService.LogException(ex); continue; } if (dataviewQuery == null) { errorMessages.Add($"Generating a query for dataview {connectionStatusAutomation.DataViewId} for Status {connectionStatus.Id} in Connection Type {connectionTypeView.ConnectionTypeId} was not successful"); continue; } connectionRequestQry = connectionRequestQry.Where(a => dataviewQuery.Any(b => b.Id == a.Id)); } var eligibleConnectionRequests = new List <ConnectionRequest>(); if (connectionStatusAutomation.GroupRequirementsFilter != GroupRequirementsFilter.Ignore) { var connectionRequests = connectionRequestQry.ToList(); foreach (var connectionRequest in connectionRequests) { // Group Requirement can't be met when either placement group or placement group role id is missing if (connectionRequest.AssignedGroupId.HasValue && connectionRequest.AssignedGroupMemberRoleId.HasValue) { var groupView = GetGroupView(connectionRequest, groupViews, rockContext); if (groupView != null && groupView.HasGroupRequirement) { var isRequirementMet = IsGroupRequirementMet(connectionRequest, groupView, rockContext); // connection request based on if group requirement is met or not is added to list for status update if ((connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.DoesNotMeet && !isRequirementMet) || (connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.MustMeet && isRequirementMet)) { eligibleConnectionRequests.Add(connectionRequest); } } } } } else { eligibleConnectionRequests = connectionRequestQry.ToList(); } var updatedCount = 0; foreach (var connectionRequest in eligibleConnectionRequests) { if (connectionRequest.ConnectionStatusId == connectionStatusAutomation.DestinationStatusId) { continue; } connectionRequest.SetConnectionStatusFromAutomationLoop(connectionStatusAutomation); updatedCount++; } if (updatedCount > 0) { rockContext.SaveChanges(); updatedResults.Add(updatedCount); } } } }
public void Execute(IJobExecutionContext context) { var rockContext = new RockContext(); var dataMap = context.JobDetail.JobDataMap; var systemEmailGuid = dataMap.GetString("Email").AsGuidOrNull(); string appRoot = Rock.Web.Cache.GlobalAttributesCache.Read().GetValue("PublicApplicationRoot"); if (appRoot.IsNullOrWhiteSpace()) { throw new Exception("Couldn't fetch application root!"); } if (systemEmailGuid == null) { throw new Exception("A system email template needs to be set."); } var systemEmailTemplate = new SystemEmailService(rockContext).Get(systemEmailGuid.Value); if (systemEmailTemplate == null) { throw new Exception("The system email template setting is not a valid system email template."); } var cutOffHours = dataMap.GetString("ExcludeHours").AsIntegerOrNull(); if (!cutOffHours.HasValue) { throw new Exception("A cutoff period needs to be set."); } var cutoff = RockDateTime.Now.AddHours(-1 * cutOffHours.Value); var connectionRequestService = new ConnectionRequestService(rockContext); var midnightToday = new DateTime(RockDateTime.Now.Year, RockDateTime.Now.Month, RockDateTime.Now.Day); var currentDateTime = RockDateTime.Now; var openConnectionRequests = connectionRequestService.Queryable() .AsNoTracking() .Where(cr => cr.CreatedDateTime < cutoff && (cr.ConnectionState == ConnectionState.Active || (cr.ConnectionState == ConnectionState.FutureFollowUp && cr.FollowupDate.HasValue && cr.FollowupDate.Value < midnightToday))); if (!openConnectionRequests.Any()) { context.Result = "There are no open and assigned connection requests to send reminders for"; return; } int totalCriticalCount = openConnectionRequests.Count(cr => cr.ConnectionStatus.IsCritical); int totalIdleCount = openConnectionRequests .Count(cr => (cr.ConnectionRequestActivities.Any() && cr.ConnectionRequestActivities.Max(ra => ra.CreatedDateTime) < SqlFunctions.DateAdd("day", -cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle, currentDateTime)) || (!cr.ConnectionRequestActivities.Any() && cr.CreatedDateTime < SqlFunctions.DateAdd("day", -cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle, currentDateTime)) ); var groupedRequests = openConnectionRequests .Where(cr => cr.ConnectorPersonAliasId != null) .GroupBy(cr => cr.ConnectorPersonAlias); int mailedCount = 0; foreach (var connectionRequestGrouping in groupedRequests) { var connectionRequests = connectionRequestGrouping.ToList(); var mergeFields = new Dictionary <string, object> { { "ConnectionRequests", connectionRequests }, { "Person", connectionRequestGrouping.Key.Person }, { "CriticalCount", connectionRequests.Count(cr => cr.ConnectionStatus.IsCritical) }, { "IdleCount", connectionRequests.Count(cr => { var idleDate = currentDateTime.AddDays(-cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle); return(cr.ConnectionRequestActivities.Any() && cr.ConnectionRequestActivities.Max(ra => ra.CreatedDateTime) < idleDate || (!cr.ConnectionRequestActivities.Any() && cr.CreatedDateTime < idleDate)); }) }, { "TotalIdleCount", totalIdleCount }, { "TotalCriticalCount", totalCriticalCount } }; var recipients = new List <string> { connectionRequestGrouping.Key.Person.Email }; Email.Send(systemEmailTemplate.From.ResolveMergeFields(mergeFields), systemEmailTemplate.FromName.ResolveMergeFields(mergeFields), systemEmailTemplate.Subject.ResolveMergeFields(mergeFields), recipients, systemEmailTemplate.Body.ResolveMergeFields(mergeFields), appRoot, null, null); mailedCount++; } context.Result = string.Format("{0} reminders were sent ", mailedCount); }
/// <summary> /// Trigger Future Followup Workflow /// </summary> /// <param name="context">The context.</param> /// <param name="futureFollowupDateWorkflows">The future follow-up date workflows.</param> /// <returns></returns> private string TriggerFutureFollowupWorkFlow(IJobExecutionContext context, List <ConnectionWorkflow> futureFollowupDateWorkflows) { try { JobDataMap dataMap = context.JobDetail.JobDataMap; context.UpdateLastStatusMessage($"Processing future follow-up workFlows."); int recordsUpdated = 0; int triggerWorkflow = 0; int recordsWithError = 0; var rockContext = new RockContext(); DateTime midnightToday = RockDateTime.Today.AddDays(1); var connectionRequestService = new ConnectionRequestService(rockContext); var eligibleConnectionRequests = connectionRequestService .Queryable("ConnectionRequestWorkflows") .AsNoTracking() .Where(c => c.ConnectionState == ConnectionState.FutureFollowUp && c.FollowupDate.HasValue && c.FollowupDate < midnightToday) .ToList(); foreach (var connectionRequest in eligibleConnectionRequests) { try { using (var updateRockContext = new RockContext()) { // increase the timeout just in case. updateRockContext.Database.CommandTimeout = 180; updateRockContext.SourceOfChange = SOURCE_OF_CHANGE; var connectionOpportunity = connectionRequest.ConnectionOpportunity; if (connectionOpportunity != null) { var opportunityWorkflows = futureFollowupDateWorkflows .Where(w => (w.ConnectionOpportunityId.HasValue && w.ConnectionOpportunityId.Value == connectionOpportunity.Id) || (w.ConnectionTypeId.HasValue && w.ConnectionTypeId.Value == connectionOpportunity.ConnectionTypeId)); foreach (var connectionWorkflow in opportunityWorkflows) { LaunchWorkflow(updateRockContext, connectionRequest, connectionWorkflow, ConnectionWorkflowTriggerType.FutureFollowupDateReached.ConvertToString()); triggerWorkflow += 1; } updateRockContext.ConnectionRequests.Attach(connectionRequest); connectionRequest.ConnectionState = ConnectionState.Active; var guid = Rock.SystemGuid.ConnectionActivityType.FUTURE_FOLLOWUP_COMPLETE.AsGuid(); var futureFollowupCompleteActivityId = new ConnectionActivityTypeService(rockContext) .Queryable() .Where(t => t.Guid == guid) .Select(t => t.Id) .FirstOrDefault(); ConnectionRequestActivity connectionRequestActivity = new ConnectionRequestActivity(); connectionRequestActivity.ConnectionRequestId = connectionRequest.Id; connectionRequestActivity.ConnectionOpportunityId = connectionRequest.ConnectionOpportunityId; connectionRequestActivity.ConnectionActivityTypeId = futureFollowupCompleteActivityId; new ConnectionRequestActivityService(updateRockContext).Add(connectionRequestActivity); updateRockContext.SaveChanges(); recordsUpdated += 1; } } } catch (Exception ex) { // Log exception and keep on trucking. ExceptionLogService.LogException(new Exception($"Exception occurred trying to trigger future followup workFlow:{connectionRequest.Id}.", ex), _httpContext); recordsWithError += 1; } } // Format the result message string result = $"{recordsUpdated:N0} connection request records triggered {triggerWorkflow} workflows."; if (recordsWithError > 0) { result += $"{recordsWithError:N0} records logged an exception."; } return(result); } catch (Exception ex) { // Log exception and return the exception messages. ExceptionLogService.LogException(ex, _httpContext); return(ex.Messages().AsDelimited("; ")); } }
/// <summary> /// Handles the SelectPerson event of the ppRequestor control checking for possible duplicate records. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> protected void ppRequestor_SelectPerson( object sender, EventArgs e ) { if ( ppRequestor.PersonId.HasValue ) { using ( var rockContext = new RockContext() ) { ConnectionRequestService connectionRequestService = new ConnectionRequestService( rockContext ); int connectionOpportunityId = hfConnectionOpportunityId.ValueAsInt(); // Check if this person already has a connection request for this opportunity. var connectionRequest = connectionRequestService.Queryable() .Where( r => r.PersonAliasId == ppRequestor.PersonAliasId.Value && r.ConnectionOpportunityId == connectionOpportunityId && ( r.ConnectionState == ConnectionState.Active || r.ConnectionState == ConnectionState.FutureFollowUp ) ) .FirstOrDefault(); if ( connectionRequest != null ) { nbWarningMessage.Visible = true; nbWarningMessage.Title = "Possible Duplicate: "; nbWarningMessage.Text = string.Format( "There is already an active (or future follow up) request in the '{0}' opportunity for {1}. Are you sure you want to save this request?" , connectionRequest.ConnectionOpportunity.PublicName, ppRequestor.PersonName.TrimEnd() ); } else { nbWarningMessage.Visible = false; } } } CheckGroupRequirement(); }
/// <summary> /// Updates the Connection Requests to us the new To person /// </summary> protected void UpdateConnectionRequests() { //Get the selected people FromPersonId = ppFrom.PersonId; ToPersonId = ppTo.PersonId; // Create Needed Services ConnectionRequestService connectionRequestService = new ConnectionRequestService(rockContext); //Get Connection Requests from From person var assigned = connectionRequestService.Queryable().Where(a => a.ConnectorPersonAliasId == FromPersonId); //Set each Connection Request in From person to To person foreach (var x in assigned) { x.ConnectorPersonAliasId = ToPersonId; x.ModifiedDateTime = DateTime.Now; x.ModifiedByPersonAliasId = CurrentPersonAliasId; } //Save changes rockContext.SaveChanges(); //Update UI nbSuccess.Visible = true; }
/// <summary> /// Returns the number of Workflows and Connection Requests for the selected Fron person, then populates grids. /// </summary> protected void UpdateUi() { // Get the selected person FromPersonId = ppFrom.PersonId; // Construct List var workflowResultList = new List<WorkflowActivity>(); var connectionRequestResultList = new List<ConnectionRequest>(); // Create Needed Services WorkflowActivityService workflowActivityService = new WorkflowActivityService(rockContext); ConnectionRequestService connectionRequestService = new ConnectionRequestService(rockContext); // Get Workflows from From person var assignedWorkflows = workflowActivityService.Queryable() .Where( a => a.AssignedPersonAliasId == FromPersonId && a.CompletedDateTime == null && a.Workflow.CompletedDateTime == null); // Get Connection Requests from From person var assignedConnectionRequests = connectionRequestService.Queryable() .Where( b => b.ConnectorPersonAliasId == FromPersonId && b.ConnectionState != ConnectionState.Connected && b.ConnectionState != ConnectionState.Inactive); // UI Updates if (ppFrom.PersonId != null) { foreach (var workflow in assignedWorkflows) { workflowResultList.Add(workflow); } foreach (var connectionRequest in assignedConnectionRequests) { connectionRequestResultList.Add(connectionRequest); } lbCount.Text = assignedWorkflows.Count() + " open workflows assigned to this person.<br />" + assignedConnectionRequests.Count() + " open Connection Requests assigned to this person."; gWorkflows.DataSource = workflowResultList; gWorkflows.DataBind(); gConnections.DataSource = connectionRequestResultList; gConnections.DataBind(); if (assignedWorkflows.Any()) { btnSaveWorkflows.Visible = true; ppTo.Visible = true; } if (assignedConnectionRequests.Any()) { btnSaveConnections.Visible = true; ppTo.Visible = true; } } else { nbSuccess.Visible = false; nbWarningMessage.Visible = false; } }
/// <summary> /// Handles the ItemDataBound event of the rConnectionTypes control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RepeaterItemEventArgs"/> instance containing the event data.</param> protected void rConnectionTypes_ItemDataBound( object sender, RepeaterItemEventArgs e ) { var lConnectionOpportunityList = e.Item.FindControl( "lConnectionOpportunityList" ) as Literal; if ( lConnectionOpportunityList != null ) { var connectionType = e.Item.DataItem as ConnectionType; var pageGuid = this.GetAttributeValue( "ConnectionRequestDetail" ).AsGuidOrNull(); PageReference connectionRequestDetailPage = null; if ( pageGuid.HasValue ) { connectionRequestDetailPage = new PageReference( pageGuid.Value.ToString() ); } if ( connectionType != null && this.Person != null ) { using ( var rockContext = new RockContext() ) { int personId = this.Person.Id; var connectionRequestService = new ConnectionRequestService( rockContext ); var connectionRequestList = connectionRequestService.Queryable().Where( a => a.PersonAlias.PersonId == personId && a.ConnectionOpportunity.ConnectionTypeId == connectionType.Id ).OrderBy( a => a.ConnectionOpportunity.Name ).AsNoTracking().ToList(); string listHtml = string.Empty; foreach ( var connectionRequest in connectionRequestList ) { string connectionNameHtml; string connectionName; if ( connectionRequest.CampusId.HasValue ) { connectionName = string.Format( "{0} ({1})", connectionRequest.ConnectionOpportunity, CampusCache.Read( connectionRequest.CampusId.Value ) ); } else { connectionName = string.Format( "{0}", connectionRequest.ConnectionOpportunity ); } if ( connectionRequestDetailPage != null && connectionRequestDetailPage.PageId > 0 ) { connectionRequestDetailPage.Parameters = new System.Collections.Generic.Dictionary<string, string>(); connectionRequestDetailPage.Parameters.Add( "ConnectionRequestId", connectionRequest.Id.ToString() ); connectionRequestDetailPage.Parameters.Add( "ConnectionOpportunityId", connectionRequest.ConnectionOpportunityId.ToString() ); connectionNameHtml = string.Format( "<a href='{0}'>{1}</a>", connectionRequestDetailPage.BuildUrl(), connectionName ); } else { connectionNameHtml = connectionName; } listHtml += string.Format( "<li {0}>{1} - <small>{2}</small></li>", connectionRequest.ConnectionState == ConnectionState.Connected ? "class='is-inactive'" : string.Empty, connectionNameHtml, connectionRequest.ConnectionState == ConnectionState.Connected ? "Connected" : connectionRequest.ConnectionStatus.ToString() ); } lConnectionOpportunityList.Text = listHtml; } } } }
public virtual void Execute(IJobExecutionContext context) { JobDataMap dataMap = context.JobDetail.JobDataMap; var rockContext = new RockContext(); var groupService = new GroupService(rockContext); var groupMemberService = new GroupMemberService(rockContext); var connectionRequestService = new ConnectionRequestService(rockContext); var group = groupService.GetByGuid(dataMap.GetString("ConnectionGroup").AsGuid()); var systemEmail = dataMap.GetString("SystemEmail").AsGuidOrNull(); if (!systemEmail.HasValue) { throw new Exception("System Email is required!"); } List <int> connectorPersonAliasIds = new List <int>(); var recipients = new List <RecipientData>(); if (group != null) { var childrenGroups = groupService.GetAllDescendents(group.Id); var allGroups = childrenGroups.ToList(); allGroups.Add(group); connectorPersonAliasIds = allGroups.SelectMany(p => p.Members.Select(m => m.Person).SelectMany(psn => psn.Aliases).Select(a => a.Id)).ToList(); } var connectionOpportunities = dataMap.GetString("ConnectionOpportunities").SplitDelimitedValues(); // get job type id int jobId = Convert.ToInt16(context.JobDetail.Description); var jobService = new ServiceJobService(rockContext); var job = jobService.Get(jobId); DateTime _midnightToday = RockDateTime.Today.AddDays(1); var currentDateTime = RockDateTime.Now; PersonService personService = new PersonService(rockContext); var connectionRequestsQry = connectionRequestService.Queryable().Where(cr => connectionOpportunities.Contains(cr.ConnectionOpportunity.Guid.ToString()) && cr.ConnectorPersonAliasId != null && ( cr.ConnectionState == ConnectionState.Active || (cr.ConnectionState == ConnectionState.FutureFollowUp && cr.FollowupDate.HasValue && cr.FollowupDate.Value < _midnightToday) )); // If we have a group of connectors, limit it to them. if (group != null) { List <int> groupconnectorPersonIds = group.ActiveMembers().SelectMany(gm => gm.Person.Aliases).Select(a => a.Id).ToList(); connectionRequestsQry = connectionRequestsQry.Where(cr => cr.ConnectorPersonAliasId.HasValue && groupconnectorPersonIds.Contains(cr.ConnectorPersonAliasId.Value)); } // Now get all the connection data for everyone. var connectionRequestGroups = connectionRequestsQry.GroupBy(cr => cr.ConnectorPersonAlias.PersonId); foreach (var connectionRequestGroup in connectionRequestGroups) { Person person = personService.Get(connectionRequestGroup.Key); List <ConnectionOpportunity> opportunities = connectionRequestGroup.Select(a => a.ConnectionOpportunity).Distinct().ToList(); var newConnectionRequests = connectionRequestGroup.Where(cr => cr.CreatedDateTime >= job.LastSuccessfulRunDateTime).GroupBy(cr => cr.ConnectionOpportunityId).ToList(); // Get all the idle connections var idleConnectionRequests = connectionRequestGroup .Where(cr => ( (cr.ConnectionRequestActivities.Any() && cr.ConnectionRequestActivities.Max(ra => ra.CreatedDateTime) < currentDateTime.AddDays(-cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle))) || (!cr.ConnectionRequestActivities.Any() && cr.CreatedDateTime < currentDateTime.AddDays(-cr.ConnectionOpportunity.ConnectionType.DaysUntilRequestIdle)) ) .Select(a => new { ConnectionOpportunityId = a.ConnectionOpportunityId, Id = a.Id }) .GroupBy(cr => cr.ConnectionOpportunityId).ToList(); // get list of requests that have a status that is considered critical. var criticalConnectionRequests = connectionRequestGroup .Where(r => r.ConnectionStatus.IsCritical ) .Select(a => new { ConnectionOpportunityId = a.ConnectionOpportunityId, Id = a.Id }) .GroupBy(cr => cr.ConnectionOpportunityId).ToList(); var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null); mergeFields.Add("Requests", connectionRequestGroup.Select(c => c).ToList()); mergeFields.Add("ConnectionOpportunities", opportunities); mergeFields.Add("ConnectionRequests", connectionRequestGroup.GroupBy(cr => cr.ConnectionOpportunity).ToList()); mergeFields.Add("NewConnectionRequests", newConnectionRequests); mergeFields.Add("IdleConnectionRequestIds", idleConnectionRequests); mergeFields.Add("CriticalConnectionRequestIds", criticalConnectionRequests); mergeFields.Add("Person", person); mergeFields.Add("LastRunDate", job.LastSuccessfulRunDateTime); mergeFields.Add("IncludeOpportunityBreakdown", dataMap.GetString("IncludeOpportunityBreakdown").AsBoolean()); mergeFields.Add("IncludeAllRequests", dataMap.GetString("IncludeAllRequests").AsBoolean()); recipients.Add(new RecipientData(person.Email, mergeFields)); } // If we have valid recipients, send the email if (recipients.Count > 0) { RockEmailMessage email = new RockEmailMessage(systemEmail.Value); email.SetRecipients(recipients); email.CreateCommunicationRecord = dataMap.GetString("SaveCommunicationHistory").AsBoolean(); email.Send(); } context.Result = string.Format("{0} Connection reminders sent", recipients.Count); }
/// <summary> /// Trigger Future Followup Workflow /// </summary> /// <param name="context">The context.</param> /// <param name="futureFollowupDateWorkflows">The future follow-up date workflows.</param> /// <returns></returns> private string TriggerFutureFollowupWorkFlow(IJobExecutionContext context, List <ConnectionWorkflow> futureFollowupDateWorkflows) { try { JobDataMap dataMap = context.JobDetail.JobDataMap; context.UpdateLastStatusMessage($"Processing future follow-up workFlows."); int recordsUpdated = 0; int triggerWorkflow = 0; int recordsWithError = 0; if (futureFollowupDateWorkflows.Any()) { var rockContext = new RockContext(); var connectionOpportunityIds = futureFollowupDateWorkflows .Where(a => a.ConnectionOpportunityId.HasValue) .Select(a => a.ConnectionOpportunityId.Value) .ToList(); var connectionTypeIds = futureFollowupDateWorkflows .Where(a => a.ConnectionTypeId.HasValue) .Select(a => a.ConnectionTypeId.Value) .ToList(); var allConnectionOpportunities = new List <ConnectionOpportunity>(); if (connectionOpportunityIds.Any() || connectionTypeIds.Any()) { var relatedConnectionOpportunities = new ConnectionOpportunityService(rockContext) .Queryable() .AsNoTracking() .Where(o => connectionOpportunityIds.Contains(o.Id) || connectionTypeIds.Contains(o.ConnectionTypeId)) .ToList(); allConnectionOpportunities.AddRange(relatedConnectionOpportunities); } if (allConnectionOpportunities.Any()) { connectionOpportunityIds = allConnectionOpportunities.Select(a => a.Id).ToList(); var numberOfDaysToLookBack = dataMap.GetString(AttributeKeys.NumberOfDaysToLookBack).AsInteger(); DateTime midnightToday = RockDateTime.Today.AddDays(1); DateTime startDate = RockDateTime.Today.AddDays(-numberOfDaysToLookBack); var connectionRequestService = new ConnectionRequestService(rockContext); var eligibleConnectionRequests = connectionRequestService .Queryable("ConnectionRequestWorkflows") .AsNoTracking() .Where(c => connectionOpportunityIds.Contains(c.ConnectionOpportunityId) && c.ConnectionState == ConnectionState.FutureFollowUp && c.FollowupDate.HasValue && c.FollowupDate >= startDate && c.FollowupDate < midnightToday ) .ToList(); foreach (var connectionRequest in eligibleConnectionRequests) { try { using (var updateRockContext = new RockContext()) { // increase the timeout just in case. updateRockContext.Database.CommandTimeout = 180; updateRockContext.SourceOfChange = SOURCE_OF_CHANGE; var connectionOpportunity = allConnectionOpportunities.SingleOrDefault(a => a.Id == connectionRequest.ConnectionOpportunityId); if (connectionOpportunity != null) { var opportunityWorkflows = futureFollowupDateWorkflows .Where(w => (w.ConnectionOpportunityId.HasValue && w.ConnectionOpportunityId.Value == connectionOpportunity.Id) || (w.ConnectionTypeId.HasValue && w.ConnectionTypeId.Value == connectionOpportunity.ConnectionTypeId)); foreach (var connectionWorkflow in opportunityWorkflows .Where(a => !connectionRequest.ConnectionRequestWorkflows.Any(b => b.ConnectionWorkflowId == a.Id))) { LaunchWorkflow(updateRockContext, connectionRequest, connectionWorkflow, ConnectionWorkflowTriggerType.FutureFollowupDateReached.ConvertToString()); triggerWorkflow += 1; } updateRockContext.ConnectionRequests.Attach(connectionRequest); connectionRequest.ConnectionState = ConnectionState.Active; updateRockContext.SaveChanges(); recordsUpdated += 1; } } } catch (Exception ex) { // Log exception and keep on trucking. ExceptionLogService.LogException(new Exception($"Exception occurred trying to trigger future followup workFlow:{connectionRequest.Id}.", ex), _httpContext); recordsWithError += 1; } } } } // Format the result message string result = $"{recordsUpdated:N0} connection request records triggered {triggerWorkflow} workflows."; if (recordsWithError > 0) { result += $"{recordsWithError:N0} records logged an exception."; } return(result); } catch (Exception ex) { // Log exception and return the exception messages. ExceptionLogService.LogException(ex, _httpContext); return(ex.Messages().AsDelimited("; ")); } }
/// <summary> /// Binds the grid. /// </summary> private void BindGrid() { var rockContext = new RockContext(); var campaignConnectionItems = Rock.Web.SystemSettings.GetValue(CampaignConnectionKey.CAMPAIGN_CONNECTION_CONFIGURATION).FromJsonOrNull <List <CampaignItem> >() ?? new List <CampaignItem>(); var relatedOpportunityIds = campaignConnectionItems.Select(a => a.OpportunityGuid).ToList(); List <ConnectionOpportunity> relatedOpportunities = new List <ConnectionOpportunity>(); Dictionary <Guid, int> activeOpportunityRequests = new Dictionary <Guid, int>(); if (relatedOpportunityIds.Any()) { var connectionOpportunityService = new ConnectionOpportunityService(rockContext); var connectionRequestService = new ConnectionRequestService(rockContext); var connectionRequestsQry = connectionRequestService.Queryable(); relatedOpportunities = connectionOpportunityService.GetListByGuids(relatedOpportunityIds); foreach (var connectionOpportunity in relatedOpportunities) { var activeRequestCount = connectionRequestsQry .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id && (a.ConnectionState == ConnectionState.Active || (a.ConnectionState == ConnectionState.FutureFollowUp && a.FollowupDate.HasValue && a.FollowupDate.Value < _midnightToday))) .Count(); activeOpportunityRequests.AddOrReplace(connectionOpportunity.Guid, activeRequestCount); } } var relatedDataViewIds = campaignConnectionItems.Select(a => a.DataViewGuid).ToList(); List <DataView> relatedDataViews = new List <DataView>(); if (relatedDataViewIds.Any()) { var dataViewService = new DataViewService(rockContext); relatedDataViews = dataViewService.GetListByGuids(relatedDataViewIds); } var campaignConnectionRows = new List <CampaignConnectionRow>(); var entitySetItemQry = new EntitySetItemService(rockContext).Queryable(); foreach (var campaignConnectionItem in campaignConnectionItems) { var campaignConnectionRow = new CampaignConnectionRow(); campaignConnectionRow.Guid = campaignConnectionItem.Guid; campaignConnectionRow.Name = campaignConnectionItem.Name; campaignConnectionRow.ConnectionOpportunity = relatedOpportunities.FirstOrDefault(a => a.Guid == campaignConnectionItem.OpportunityGuid); campaignConnectionRow.DataView = relatedDataViews.FirstOrDefault(a => a.Guid == campaignConnectionItem.DataViewGuid); campaignConnectionRow.ActiveRequests = activeOpportunityRequests.GetValueOrNull(campaignConnectionItem.OpportunityGuid) ?? 0; campaignConnectionRow.PendingConnections = entitySetItemQry.Where(a => a.EntitySetId == campaignConnectionItem.EntitySetId).Count(); campaignConnectionRow.IsActive = campaignConnectionItem.IsActive; campaignConnectionRows.Add(campaignConnectionRow); } var qry = campaignConnectionRows.AsQueryable(); SortProperty sortProperty = gCampaigns.SortProperty; if (sortProperty != null) { qry = qry.Sort(sortProperty); } else { qry = qry.OrderBy(g => g.Name); } gCampaigns.DataSource = qry.ToList(); gCampaigns.DataBind(); }
/// <summary> /// creates or updates the entity set on the basis of campaign connection configuration, and returns the Id of the entitySetId /// </summary> /// <param name="campaignConfiguration">The campaign configuration.</param> /// <returns></returns> public static int GetEntitySet(CampaignItem campaignConfiguration) { var rockContext = new RockContext(); var connectionOpportunityService = new ConnectionOpportunityService(rockContext); var connectionRequestService = new ConnectionRequestService(rockContext); var entitySetService = new Rock.Model.EntitySetService(rockContext); var connectionOpportunity = connectionOpportunityService.Get(campaignConfiguration.OpportunityGuid); // list of person on the basis of Dataview result and optout group. var filteredPersonIds = GetFilteredPersonIds(campaignConfiguration, rockContext); // get the last connection datetime. var lastConnectionDateTime = RockDateTime.Now.AddDays(-campaignConfiguration.DaysBetweenConnection); // if DaysBetweenConnection is 0 then check for connection request for any time period. if (campaignConfiguration.DaysBetweenConnection == default(int)) { lastConnectionDateTime = DateTime.MinValue; } // list of person that has active connection request OR has connection closed in the past number of days between connection. var excludedPersonIds = connectionRequestService .Queryable() .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id && ( a.ConnectionState == ConnectionState.Active || a.ConnectionState == ConnectionState.FutureFollowUp || ((a.ConnectionState == ConnectionState.Connected || a.ConnectionState == ConnectionState.Inactive) && a.ModifiedDateTime > lastConnectionDateTime))) .Select(a => a.PersonAlias.PersonId) .ToList(); // filtered list of person removing all the personIds found in excludedPersonIds List filteredPersonIds = filteredPersonIds.Where(a => !excludedPersonIds.Contains(a)).ToList(); // get the ordered list of personIds based on the oldest previous connection request and connection opportunity /* 2020-05-06 MDP * If there are many filteredPersonIds, we'll get a SQL Exception, so let's get *all* the Connected connection Requests first, * and then use C# to filter. */ var orderedLastCompletedRequestForPerson = connectionRequestService .Queryable() .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id && a.ConnectionState == ConnectionState.Connected) .GroupBy(a => a.PersonAlias.PersonId) .Select(a => new { PersonId = a.Key, LastConnectionDateTime = a.OrderByDescending(b => b.ModifiedDateTime).Select(b => b.ModifiedDateTime).FirstOrDefault() }) .OrderBy(a => a.LastConnectionDateTime) .Select(a => a.PersonId).ToList(); // Use C# to filter persons so we can avoid a SQL Exception orderedLastCompletedRequestForPerson = orderedLastCompletedRequestForPerson.Where(a => filteredPersonIds.Contains(a)).ToList(); var random = new Random(); //// get the final ordered list of personIds based on the oldest previous connection request and //// connection opportunity otherwise order randomly for the person who don't have any previous connection request. var orderedPersonIds = filteredPersonIds .OrderBy(a => { var index = orderedLastCompletedRequestForPerson.IndexOf(a); if (index == -1) { return(random.Next(orderedLastCompletedRequestForPerson.Count, int.MaxValue)); } else { return(index); } }).ToList(); EntitySet entitySet = null; if (campaignConfiguration.EntitySetId != default(int)) { entitySet = entitySetService.Get(campaignConfiguration.EntitySetId); } List <Rock.Model.EntitySetItem> entitySetItems = new List <Rock.Model.EntitySetItem>(); var personEntityTypeId = EntityTypeCache.Get <Rock.Model.Person>().Id; if (entitySet == null || entitySet.EntityTypeId != personEntityTypeId) { entitySet = new Rock.Model.EntitySet(); entitySet.EntityTypeId = personEntityTypeId; entitySet.ExpireDateTime = null; entitySetService.Add(entitySet); } else { var entitySetItemQry = new EntitySetItemService(rockContext) .Queryable().AsNoTracking() .Where(i => i.EntitySetId == entitySet.Id); rockContext.BulkDelete(entitySetItemQry); } // Update the EntitySet name entitySet.Name = campaignConfiguration.Name; var orderIndex = 0; foreach (var personId in orderedPersonIds) { try { var item = new Rock.Model.EntitySetItem(); item.Order = orderIndex++; item.EntityId = personId; entitySetItems.Add(item); } catch { // ignore } } rockContext.SaveChanges(); entitySetItems.ForEach(a => { a.EntitySetId = entitySet.Id; }); rockContext.BulkInsert(entitySetItems); return(entitySet.Id); }
/// <summary> /// Creates the connection requests. /// </summary> /// <param name="context">The context.</param> /// <param name="campaignItem">The campaign item.</param> /// <returns></returns> private int CreateConnectionRequests(IJobExecutionContext context, CampaignItem campaignItem) { context.UpdateLastStatusMessage($"Processing create connection requests for {campaignItem.Name}"); // Skip creating connection requests if set to "AsNeeded" and DailyLimitAssigned is 0 or null if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded && (campaignItem.DailyLimitAssigned <= 0 || campaignItem.DailyLimitAssigned == null)) { return(0); } int recordsProcessed = 0; var rockContext = new RockContext(); var connectionOpportunityService = new ConnectionOpportunityService(rockContext); var personAliasService = new PersonAliasService(rockContext); var connectionRequestService = new ConnectionRequestService(rockContext); var connectionOpportunity = connectionOpportunityService.Get(campaignItem.OpportunityGuid); if (connectionOpportunity == null) { return(0); } // get cutoff for the last connection datetime. var lastConnectionDateTime = RockDateTime.Now.AddDays(-campaignItem.DaysBetweenConnection); // if DaysBetweenConnection is 0 then check for connection request for any time period. if (campaignItem.DaysBetweenConnection == default(int)) { lastConnectionDateTime = DateTime.MinValue; } var entitySetItemService = new EntitySetItemService(rockContext); var entitySetItemsQry = entitySetItemService .Queryable() .Where(a => a.EntitySetId == campaignItem.EntitySetId) .OrderBy(a => a.Order); bool autoAssignment = false; var eligibleConnectors = new List <ConnectionConnector>(); if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded && campaignItem.DailyLimitAssigned.HasValue && campaignItem.DailyLimitAssigned != default(int)) { autoAssignment = true; eligibleConnectors = GetEligibleConnectorWithLimit(connectionOpportunity.Id, rockContext, campaignItem.DailyLimitAssigned.Value); } int?connectionStatusId = connectionOpportunity.ConnectionType.ConnectionStatuses .Where(s => s.IsDefault) .Select(s => ( int? )s.Id) .FirstOrDefault(); // If opportunity doesn't have a default status, something is wrong if (connectionStatusId == null) { ExceptionLogService.LogException(new Exception($"Unable to determine default connection status for {connectionOpportunity.Name} while processing campaigns", null)); return(0); } var dayofWeek = RockDateTime.Now.DayOfWeek; var entitySetItemList = entitySetItemsQry.ToList(); foreach (var entitySetItem in entitySetItemList) { var personAlias = personAliasService.GetPrimaryAlias(entitySetItem.EntityId); var defaultCampus = personAlias.Person.GetCampus(); int?connectorPersonAliasId = null; if (autoAssignment) { int?connectorPersonId = null; if (campaignItem.PreferPreviousConnector) { var personIds = eligibleConnectors .Where(a => a.Limit - a.Current > 0 && (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) && (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value))) .Select(a => a.PersonId) .ToList(); if (personIds.Any()) { var person = connectionRequestService .Queryable() .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id && a.PersonAlias.PersonId == personAlias.PersonId && a.ConnectionState == ConnectionState.Connected && a.ConnectorPersonAliasId.HasValue && personIds.Contains(a.ConnectorPersonAlias.PersonId)) .Select(a => a.ConnectorPersonAlias.Person) .FirstOrDefault(); if (person != null) { connectorPersonId = person.Id; } } } if (!connectorPersonId.HasValue) { var eligibleConnector = eligibleConnectors .Where(a => a.Limit - a.Current > 0 && (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) && (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value))) .OrderBy(a => a.Current) // order from least assigned to most assigned .ThenBy(x => Guid.NewGuid()) // and then randomize .FirstOrDefault(); if (eligibleConnector != null) { connectorPersonId = eligibleConnector.PersonId; } } if (!connectorPersonId.HasValue) { continue; } foreach (var connectionConnector in eligibleConnectors.Where(a => a.PersonId == connectorPersonId.Value)) { connectorPersonAliasId = connectionConnector.PersonAliasId; connectionConnector.Current += 1; } } using (var insertRockContext = new RockContext()) { try { /* * 3/30/2020 - NA * * When setting the connection request's Requester, we have to use the PrimaryAlias * to set the connectionRequest.PersonAlias property because the ConnectionRequestChangeTransaction * https://github.com/SparkabilityGroup/Rock/blob/a556a9285b7fdfe5594441286242f4feaa5847f2/Rock/Transactions/ConnectionRequestChangeTransaction.cs#L123 * (which handles triggered workflows) expects it. Also, it needs to be tracked by * the current rockContext... * * In other words, this will not work correctly: * PersonAliasId = personAlias.Id, * * Reason: This plug-in cannot change Rock core assembly code. */ var personPrimaryAlias = new PersonAliasService(insertRockContext).GetPrimaryAlias(entitySetItem.EntityId); var connectionRequestActivityService = new ConnectionRequestActivityService(insertRockContext); var insertConnectionRequestService = new ConnectionRequestService(insertRockContext); // double check that they haven't already been added var personAlreadyHasConnectionRequest = CampaignConnectionHelper.PersonAlreadyHasConnectionRequest(connectionOpportunity.Id, rockContext, lastConnectionDateTime, entitySetItem.EntityId); if (personAlreadyHasConnectionRequest) { continue; } var connectionRequest = new ConnectionRequest() { ConnectionOpportunityId = connectionOpportunity.Id, PersonAlias = personPrimaryAlias, ConnectionState = ConnectionState.Active, ConnectorPersonAliasId = connectorPersonAliasId, CampusId = defaultCampus?.Id, ConnectionStatusId = connectionStatusId.Value, }; if (campaignItem.RequestCommentsLavaTemplate.IsNotNullOrWhiteSpace()) { var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Person", personAlias.Person); mergeFields.Add("Family", personAlias.Person.GetFamily()); connectionRequest.Comments = campaignItem.RequestCommentsLavaTemplate.ResolveMergeFields(mergeFields); } insertConnectionRequestService.Add(connectionRequest); if (connectorPersonAliasId.HasValue) { var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid(); int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid); if (assignedActivityId.HasValue) { var connectionRequestActivity = new ConnectionRequestActivity(); connectionRequestActivity.ConnectionRequest = connectionRequest; connectionRequestActivity.ConnectionOpportunityId = connectionRequest.ConnectionOpportunityId; connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value; connectionRequestActivity.ConnectorPersonAliasId = connectorPersonAliasId; connectionRequestActivityService.Add(connectionRequestActivity); } } insertRockContext.SaveChanges(); } catch (Exception ex) { // Log exception and keep on trucking. var exception = new Exception($"Exception occurred trying to create connection request:{personAlias.Id}.", ex); createConnectionRequestExceptions.Add(exception); ExceptionLogService.LogException(exception, null); } } recordsProcessed += 1; } return(recordsProcessed); }
/// <summary> /// Assigns the connection requests from the SelectedCampaign's entity set. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="selectedCampaignItem">The selected campaign item.</param> /// <param name="numberOfRequestsRemaining">The number of requests remaining.</param> /// <param name="connectorPerson">The connector person.</param> private static void AssignConnectionRequestsFromEntitySet(RockContext rockContext, CampaignItem selectedCampaignItem, ref int numberOfRequestsRemaining, Person connectorPerson) { var opportunityService = new ConnectionOpportunityService(rockContext); ConnectionOpportunity opportunity = opportunityService.Get(selectedCampaignItem.OpportunityGuid); if (opportunity == null || !opportunity.IsActive) { return; } int?defaultStatusId = opportunity.ConnectionType.ConnectionStatuses .Where(s => s.IsDefault) .Select(s => ( int? )s.Id) .FirstOrDefault(); // If opportunity doesn't have a default status, something is wrong if (defaultStatusId == null) { return; } var connectorCampusIds = GetConnectorCampusIds(selectedCampaignItem, connectorPerson); var connectionRequestService = new ConnectionRequestService(rockContext); var connectionRequestActivityService = new ConnectionRequestActivityService(rockContext); // get previous connections for the connector that have the same campus of the connector, or if the person's campus or connector person's campus is null var previousConnectedPersonIdsForCurrentPerson = connectionRequestService.Queryable() .Where(a => a.ConnectionOpportunityId == opportunity.Id) .Where(a => a.ConnectorPersonAlias.PersonId == connectorPerson.Id) .Where(a => (a.CampusId == null) || connectorCampusIds.Any(connectorCampusId => connectorCampusId == null || a.CampusId.Value == connectorCampusId)) .Select(a => a.PersonAlias.PersonId).Distinct().ToList(); var entitySetId = CampaignConnectionHelper.GetEntitySet(selectedCampaignItem); var entitySetItemService = new EntitySetItemService(rockContext); var entitySetItemList = entitySetItemService.Queryable().Where(a => a.EntitySetId == entitySetId).OrderBy(a => a.Order).Select(a => new { PersonId = a.EntityId, EntityItemOrder = a.Order }).ToList(); if (selectedCampaignItem.PreferPreviousConnector) { // sort them by any where the current person was assigned to this person before entitySetItemList = entitySetItemList .OrderBy(a => previousConnectedPersonIdsForCurrentPerson.Any(x => x == a.PersonId)) .ThenBy(a => a.EntityItemOrder).ToList(); } else { entitySetItemList = entitySetItemList.OrderBy(a => a.EntityItemOrder).ToList(); } var personService = new PersonService(rockContext); // get the last connection datetime. var lastConnectionDateTime = RockDateTime.Now.AddDays(-selectedCampaignItem.DaysBetweenConnection); // if DaysBetweenConnection is 0 then check for connection request for any time period. if (selectedCampaignItem.DaysBetweenConnection == default(int)) { lastConnectionDateTime = DateTime.MinValue; } foreach (var entitySetItem in entitySetItemList) { var entitySetPerson = personService.Get(entitySetItem.PersonId); if (entitySetPerson == null) { continue; } var entitySetPersonPrimaryCampusId = entitySetPerson.PrimaryCampusId; bool validCampus = IsValidCampus(connectorCampusIds, entitySetPersonPrimaryCampusId); if (!validCampus) { continue; } // double check that they haven't already been added bool personAlreadyHasConnectionRequest = PersonAlreadyHasConnectionRequest(opportunity.Id, rockContext, lastConnectionDateTime, entitySetPerson.Id); if (personAlreadyHasConnectionRequest) { continue; } var connectionRequest = new ConnectionRequest(); connectionRequest.ConnectionOpportunityId = opportunity.Id; /* * 3/30/2020 - NA * * When setting the connection request's Requester, we have to use the PrimaryAlias * to set the connectionRequest.PersonAlias property because the ConnectionRequestChangeTransaction * https://github.com/SparkabilityGroup/Rock/blob/a556a9285b7fdfe5594441286242f4feaa5847f2/Rock/Transactions/ConnectionRequestChangeTransaction.cs#L123 * (which handles triggered workflows) expects it. Also, it needs to be tracked by * the current rockContext... hence the change from GetAsNoTracking() to just Get() above: * var entitySetPerson = personService.Get( entitySetItem.PersonId ); * * In other words, this will not work correctly: * connectionRequest.PersonAliasId = entitySetPerson.PrimaryAliasId.Value; * * Reason: This plug-in cannot change Rock core assembly code. */ connectionRequest.PersonAlias = entitySetPerson.PrimaryAlias; connectionRequest.ConnectionState = ConnectionState.Active; connectionRequest.ConnectorPersonAliasId = connectorPerson.PrimaryAliasId; connectionRequest.CampusId = entitySetPersonPrimaryCampusId; connectionRequest.ConnectionStatusId = defaultStatusId.Value; if (selectedCampaignItem.RequestCommentsLavaTemplate.IsNotNullOrWhiteSpace()) { var mergeFields = new Dictionary <string, object>(); mergeFields.Add("Person", entitySetPerson); mergeFields.Add("Family", entitySetPerson.GetFamily()); connectionRequest.Comments = selectedCampaignItem.RequestCommentsLavaTemplate.ResolveMergeFields(mergeFields); } connectionRequestService.Add(connectionRequest); var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid(); int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid); if (assignedActivityId.HasValue) { var connectionRequestActivity = new ConnectionRequestActivity(); connectionRequestActivity.ConnectionRequest = connectionRequest; connectionRequestActivity.ConnectionOpportunityId = connectionRequest.ConnectionOpportunityId; connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value; connectionRequestActivity.ConnectorPersonAliasId = connectorPerson.PrimaryAliasId; connectionRequestActivityService.Add(connectionRequestActivity); } numberOfRequestsRemaining--; if (numberOfRequestsRemaining <= 0) { break; } } }
public void Execute(IJobExecutionContext context) { var rockContext = new RockContext(); var dataMap = context.JobDetail.JobDataMap; DateTime?lastRun = null; if (context.PreviousFireTimeUtc.HasValue) { lastRun = RockDateTime.ConvertLocalDateTimeToRockDateTime(context.PreviousFireTimeUtc.Value.LocalDateTime); } var systemEmailGuid = dataMap.GetString("Email").AsGuidOrNull(); string appRoot = Rock.Web.Cache.GlobalAttributesCache.Read().GetValue("PublicApplicationRoot"); if (appRoot.IsNullOrWhiteSpace()) { throw new Exception("Couldn't fetch application root!"); } if (systemEmailGuid == null) { throw new Exception("A system email template needs to be set."); } var systemEmailTemplate = new SystemEmailService(rockContext).Get(systemEmailGuid.Value); if (systemEmailTemplate == null) { throw new Exception("The system email template setting is not a valid system email template."); } var cutOffHours = dataMap.GetString("IncludeHours").AsIntegerOrNull(); if (!cutOffHours.HasValue) { throw new Exception("A cutoff period needs to be set."); } if (lastRun == null) { lastRun = RockDateTime.Now.AddHours(-1 * cutOffHours.Value); } var connectionRequestService = new ConnectionRequestService(rockContext); var openConnectionRequests = connectionRequestService.Queryable() .AsNoTracking() .Where(cr => cr.CreatedDateTime >= lastRun && cr.ConnectionState != ConnectionState.Connected && cr.ConnectorPersonAliasId != null); if (!openConnectionRequests.Any()) { context.Result = "There are no open and assigned connection requests to send alerts for"; return; } var groupedRequests = openConnectionRequests .ToList() .GroupBy(cr => cr.ConnectorPersonAlias); int mailedCount = 0; foreach (var connectionRequestGrouping in groupedRequests) { if (connectionRequestGrouping.Key == null) { continue; } var connectionRequests = connectionRequestGrouping.ToList(); var mergeFields = new Dictionary <string, object> { { "ConnectionRequests", connectionRequests }, { "Person", connectionRequestGrouping.Key.Person } }; var recipients = new List <string> { connectionRequestGrouping.Key.Person.Email }; Email.Send(systemEmailTemplate.From.ResolveMergeFields(mergeFields), systemEmailTemplate.FromName.ResolveMergeFields(mergeFields), systemEmailTemplate.Subject.ResolveMergeFields(mergeFields), recipients, systemEmailTemplate.Body.ResolveMergeFields(mergeFields), appRoot, null); mailedCount++; } context.Result = string.Format("{0} reminders were sent ", mailedCount); }