/// <summary> /// Handles the SaveClick event of the mdAddCampaignRequests control. /// </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 mdAddCampaignRequests_SaveClick(object sender, EventArgs e) { // note if there is only one CampaignConnectionItem, ddlCampaignConnectionItemsMultiple will not be visible, but it is still the selected one, because there is only one var selectedCampaignConnectionItemGuid = ddlCampaignConnectionItemsMultiple.SelectedValue.AsGuidOrNull(); if (!selectedCampaignConnectionItemGuid.HasValue) { // shouldn't happen return; } var campaignConnectionItems = Rock.Web.SystemSettings.GetValue(CampaignConnectionKey.CAMPAIGN_CONNECTION_CONFIGURATION).FromJsonOrNull <List <CampaignItem> >() ?? new List <CampaignItem>(); var selectedCampaignConnectionItem = campaignConnectionItems.Where(a => a.Guid == selectedCampaignConnectionItemGuid.Value).FirstOrDefault(); if (selectedCampaignConnectionItem == null) { // shouldn't happen return; } int numberOfRequests, numberOfRequestsRemaining; numberOfRequests = nbNumberOfRequests.Text.AsInteger(); CampaignConnectionHelper.AddConnectionRequestsForPerson(selectedCampaignConnectionItem, this.CurrentPerson, numberOfRequests, out numberOfRequestsRemaining); if (numberOfRequestsRemaining == numberOfRequests) { nbAddConnectionRequestsMessage.Text = "Additional Requests are not available as this time."; nbAddConnectionRequestsMessage.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Info; nbAddConnectionRequestsMessage.Visible = true; } mdAddCampaignRequests.Hide(); NavigateToCurrentPageReference(); }
/// <summary> /// Processes the campaign configuration entity set. /// </summary> /// <param name="context">The context.</param> /// <param name="campaignItem">The campaign item.</param> private void ProcessCampaignConfigurationEntitySet(IJobExecutionContext context, CampaignItem campaignItem) { context.UpdateLastStatusMessage($"Processing entity set for {campaignItem.Name}."); campaignItem.EntitySetId = CampaignConnectionHelper.GetEntitySet(campaignItem); CampaignConnectionHelper.AddOrUpdateCampaignConfiguration(campaignItem.Guid, campaignItem); }
/// <summary> /// Handles the DeleteClick event of the gCampaigns control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void gCampaigns_DeleteClick(object sender, RowEventArgs e) { var campaignConnectionItem = CampaignConnectionHelper.GetCampaignConfiguration(e.RowKeyValue.ToString().AsGuid()); if (campaignConnectionItem != null && campaignConnectionItem.EntitySetId != default(int)) { var rockContext = new RockContext(); var entitySetService = new EntitySetService(rockContext); var entitySet = entitySetService.Get(campaignConnectionItem.EntitySetId); string errorMessage; if (!entitySetService.CanDelete(entitySet, out errorMessage)) { mdGridWarning.Show(errorMessage, ModalAlertType.Information); return; } var entitySetItemQry = new EntitySetItemService(rockContext) .Queryable().AsNoTracking() .Where(i => i.EntitySetId == entitySet.Id); rockContext.BulkDelete(entitySetItemQry); entitySetService.Delete(entitySet); rockContext.SaveChanges(); CampaignConnectionHelper.RemoveCampaignConfiguration(e.RowKeyValue.ToString().AsGuid()); BindGrid(); } }
/// <summary> /// Handles the Click event of the btnAddCampaignRequests control. /// </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 btnAddCampaignRequests_Click(object sender, EventArgs e) { var campaignConnectionItems = Rock.Web.SystemSettings.GetValue(CampaignConnectionKey.CAMPAIGN_CONNECTION_CONFIGURATION).FromJsonOrNull <List <CampaignItem> >() ?? new List <CampaignItem>(); campaignConnectionItems = campaignConnectionItems.Where(c => c.IsActive).OrderBy(a => a.Name).ToList(); var rockContext = new RockContext(); // limit to campaigns that the current person is a connector in campaignConnectionItems = campaignConnectionItems.Where(a => CampaignConnectionHelper.GetConnectorCampusIds(a, CurrentPerson).Any()).ToList(); ddlCampaignConnectionItemsMultiple.Items.Clear(); var campaignConnectionItemsPendingCount = new Dictionary <CampaignItem, int>(); foreach (var campaignConnectionItem in campaignConnectionItems) { int pendingCount = CampaignConnectionHelper.GetPendingConnectionCount(campaignConnectionItem, CurrentPerson); campaignConnectionItemsPendingCount.AddOrIgnore(campaignConnectionItem, pendingCount); var listItem = new ListItem(); listItem.Text = string.Format("{0} ({1} pending connections)", campaignConnectionItem.Name, pendingCount); listItem.Value = campaignConnectionItem.Guid.ToString(); ddlCampaignConnectionItemsMultiple.Items.Add(listItem); } nbAddConnectionRequestsMessage.Visible = false; nbNumberOfRequests.Visible = true; if (campaignConnectionItems.Count() == 0) { nbAddConnectionRequestsMessage.Text = "There are no campaigns available for you to request connections for."; nbAddConnectionRequestsMessage.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Warning; nbAddConnectionRequestsMessage.Visible = true; ddlCampaignConnectionItemsMultiple.Visible = false; lCampaignConnectionItemSingle.Visible = false; nbNumberOfRequests.Visible = false; } else if (campaignConnectionItems.Count() == 1) { var campaignConnectionItem = campaignConnectionItems[0]; lCampaignConnectionItemSingle.Visible = true; int pendingCount = campaignConnectionItemsPendingCount.GetValueOrNull(campaignConnectionItem) ?? 0; lCampaignConnectionItemSingle.Text = string.Format("{0} ({1} pending connections)", campaignConnectionItem.Name, pendingCount); ddlCampaignConnectionItemsMultiple.Visible = false; } else { lCampaignConnectionItemSingle.Visible = false; ddlCampaignConnectionItemsMultiple.Visible = true; } if (campaignConnectionItems.Count > 0) { var firstCampaignConnectionItem = campaignConnectionItems.First(); SetDefaultNumberOfRequests(firstCampaignConnectionItem.Guid, campaignConnectionItemsPendingCount.GetValueOrNull(firstCampaignConnectionItem) ?? 0); } mdAddCampaignRequests.Show(); }
/// <summary> /// Sets the default number of requests. /// </summary> /// <param name="selectedCampaignConnectionItemGuid">The selected campaign connection item unique identifier.</param> private void SetDefaultNumberOfRequests(Guid?selectedCampaignConnectionItemGuid) { if (!selectedCampaignConnectionItemGuid.HasValue) { // shouldn't happen return; } var campaignConnectionItems = Rock.Web.SystemSettings.GetValue(CampaignConnectionKey.CAMPAIGN_CONNECTION_CONFIGURATION).FromJsonOrNull <List <CampaignItem> >() ?? new List <CampaignItem>(); var selectedCampaignConnectionItem = campaignConnectionItems.Where(a => a.Guid == selectedCampaignConnectionItemGuid.Value).FirstOrDefault(); var rockContext = new RockContext(); var opportunityService = new ConnectionOpportunityService(rockContext); IQueryable <ConnectionOpportunityConnectorGroup> opportunityConnecterGroupQuery = opportunityService.Queryable() .Where(a => a.Guid == selectedCampaignConnectionItem.OpportunityGuid) .SelectMany(a => a.ConnectionOpportunityConnectorGroups); int?defaultDailyLimitAssigned = null; // Check to see if the group member has any CampaignDailyLimit values defined. var currentPersonConnectorGroupMember = opportunityConnecterGroupQuery .Select(s => s.ConnectorGroup).SelectMany(g => g.Members) .WhereAttributeValue(rockContext, av => (av.Attribute.Key == "CampaignDailyLimit") && av.ValueAsNumeric > 0) .FirstOrDefault(m => m.PersonId == this.CurrentPersonId.Value); if (currentPersonConnectorGroupMember != null) { currentPersonConnectorGroupMember.LoadAttributes(); defaultDailyLimitAssigned = currentPersonConnectorGroupMember.GetAttributeValue("CampaignDailyLimit").AsIntegerOrNull(); } if (defaultDailyLimitAssigned == null && selectedCampaignConnectionItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded) { defaultDailyLimitAssigned = selectedCampaignConnectionItem.DailyLimitAssigned; } var entitySetItemService = new EntitySetItemService(rockContext); int pendingCount = CampaignConnectionHelper.GetPendingConnectionCount(selectedCampaignConnectionItem, CurrentPerson); if (pendingCount == 0) { nbAddConnectionRequestsMessage.Text = "There are no pending requests remaining."; nbAddConnectionRequestsMessage.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Info; nbAddConnectionRequestsMessage.Visible = true; } else if (pendingCount < defaultDailyLimitAssigned) { nbAddConnectionRequestsMessage.Text = string.Format("There are only {0} pending requests remaining.", pendingCount); nbAddConnectionRequestsMessage.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Info; nbAddConnectionRequestsMessage.Visible = true; defaultDailyLimitAssigned = pendingCount; } else { nbAddConnectionRequestsMessage.Visible = false; } nbNumberOfRequests.Text = defaultDailyLimitAssigned.ToString(); }
/// <summary> /// Handles the Click event of the btnSave control. /// </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 btnSave_Click(object sender, EventArgs e) { var campaignConnectionGuid = hfCampaignConnectionGuid.Value.AsGuid(); CampaignItem campaignConnection = null; if (campaignConnectionGuid == Guid.Empty) { campaignConnection = new CampaignItem() { Guid = Guid.NewGuid() }; } else { campaignConnection = CampaignConnectionHelper.GetCampaignConfiguration(campaignConnectionGuid); } campaignConnection.Name = tbName.Text; campaignConnection.IsActive = cbIsActive.Checked; campaignConnection.ConnectionTypeGuid = ddlConnectionType.SelectedValue.AsGuid(); campaignConnection.RequestCommentsLavaTemplate = ceCommentLavaTemplate.Text; campaignConnection.OpportunityGuid = ddlConnectionOpportunity.SelectedValue.AsGuid(); var dataViewGuid = new DataViewService(new RockContext()).GetGuid(dvRequestor.SelectedValue.AsInteger()); if (dataViewGuid.HasValue) { campaignConnection.DataViewGuid = dataViewGuid.Value; } campaignConnection.FamilyLimits = rblFamilyLimits.SelectedValueAsEnum <FamilyLimits>(FamilyLimits.Everyone); campaignConnection.CreateConnectionRequestOption = rblCreateConnectionRequests.SelectedValueAsEnum <CreateConnectionRequestOptions>(CreateConnectionRequestOptions.AsNeeded); if (gpOptOutGroup.GroupId.HasValue) { campaignConnection.OptOutGroupGuid = new GroupService(new RockContext()).GetGuid(gpOptOutGroup.GroupId.Value); } campaignConnection.DailyLimitAssigned = nbDailyLimit.Text.AsIntegerOrNull(); campaignConnection.DaysBetweenConnection = nbNumberOfDays.Text.AsInteger(); campaignConnection.PreferPreviousConnector = cbPreferPreviousConnector.Checked; // Save what we have so far, and it will be saved again once the EntitySetId is updated when the thread completes. CampaignConnectionHelper.AddOrUpdateCampaignConfiguration(campaignConnection.Guid, campaignConnection); // Only update the EntitySet if the campaign is active if (campaignConnection.IsActive) { // Run this thread in the background since it takes several seconds to calculate. Task.Run(() => { campaignConnection.EntitySetId = CampaignConnectionHelper.GetEntitySet(campaignConnection); CampaignConnectionHelper.AddOrUpdateCampaignConfiguration(campaignConnection.Guid, campaignConnection); }); } NavigateToParentPage(); }
/// <summary> /// Handles the SelectedIndexChanged event of the ddlCampaignConnectionItem control. /// </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 ddlCampaignConnectionItem_SelectedIndexChanged(object sender, EventArgs e) { var selectedCampaignConnectionItemGuid = ddlCampaignConnectionItemsMultiple.SelectedValue.AsGuidOrNull(); if (!selectedCampaignConnectionItemGuid.HasValue) { // shouldn't happen return; } var campaignConnectionItem = CampaignConnectionHelper.GetCampaignConfiguration(selectedCampaignConnectionItemGuid.Value); int pendingCount = CampaignConnectionHelper.GetPendingConnectionCount(campaignConnectionItem, CurrentPerson); SetDefaultNumberOfRequests(selectedCampaignConnectionItemGuid.Value, pendingCount); }
/// <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 entitySetItemService = new EntitySetItemService(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 entitySetItemsQry = entitySetItemService .Queryable() .Where(a => a.EntitySetId == campaignItem.EntitySetId) .OrderBy(a => a.Order); bool autoAssignment = false; var eligibleConnectors = new List <ConnectionConnector>(); if (campaignItem.DailyLimitAssigned.HasValue && campaignItem.DailyLimitAssigned != default(int)) { autoAssignment = true; eligibleConnectors = GetEligibleConnectorWithLimit(connectionOpportunity.Id, rockContext, campaignItem.DailyLimitAssigned.Value); } var connectionStatusId = GetConnectionStatus(connectionOpportunity); if (!connectionStatusId.HasValue) { return(0); } var entitySetItemList = entitySetItemsQry.ToList(); foreach (var entitySetItem in entitySetItemList) { var entityItemPersonAlias = personAliasService.GetPrimaryAlias(entitySetItem.EntityId); int?connectorPersonId = null; if (autoAssignment) { connectorPersonId = GetConnector(campaignItem, connectionOpportunity, eligibleConnectors, entityItemPersonAlias, rockContext); if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded && !connectorPersonId.HasValue) { continue; } } // double check that they haven't already been added var personAlreadyHasConnectionRequest = CampaignConnectionHelper.PersonAlreadyHasConnectionRequest(connectionOpportunity.Id, rockContext, lastConnectionDateTime, entitySetItem.EntityId); if (personAlreadyHasConnectionRequest) { continue; } int?connectorPersonAliasId = null; if (connectorPersonId.HasValue) { foreach (var connectionConnector in eligibleConnectors.Where(a => a.PersonId == connectorPersonId.Value)) { connectorPersonAliasId = connectionConnector.PersonAliasId; connectionConnector.Current += 1; } } CreateConnectionRequest(entityItemPersonAlias, campaignItem.RequestCommentsLavaTemplate, connectionOpportunity.Id, connectionStatusId, connectorPersonAliasId, rockContext); recordsProcessed += 1; } return(recordsProcessed); }
/// <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); }