/// <summary> /// Executes the specified context. /// </summary> /// <param name="context">The context.</param> public virtual void Execute( IJobExecutionContext context ) { JobDataMap dataMap = context.JobDetail.JobDataMap; var emailTemplateGuid = dataMap.GetString( "SystemEmail" ).AsGuidOrNull(); var dataViewGuid = dataMap.GetString( "DataView" ).AsGuidOrNull(); if( dataViewGuid != null && emailTemplateGuid != null ) { var rockContext = new RockContext(); var dataView = new DataViewService( rockContext ).Get( (Guid)dataViewGuid ); List<IEntity> resultSet = null; var errorMessages = new List<string>(); var dataTimeout = dataMap.GetString( "DatabaseTimeout" ).AsIntegerOrNull() ?? 180; try { var qry = dataView.GetQuery( null, rockContext, dataTimeout, out errorMessages ); if( qry != null ) { resultSet = qry.AsNoTracking().ToList(); } } catch( Exception exception ) { ExceptionLogService.LogException( exception, HttpContext.Current ); while( exception != null ) { if( exception is SqlException && (exception as SqlException).Number == -2 ) { // if there was a SQL Server Timeout, have the warning be a friendly message about that. errorMessages.Add( "This dataview did not complete in a timely manner. You can try again or adjust the timeout setting of this block." ); exception = exception.InnerException; } else { errorMessages.Add( exception.Message ); exception = exception.InnerException; } return; } } var recipients = new List<RecipientData>(); if( resultSet.Any() ) { foreach( Person person in resultSet ) { var mergeFields = Lava.LavaHelper.GetCommonMergeFields( null ); mergeFields.Add( "Person", person ); recipients.Add( new RecipientData( person.Email, mergeFields ) ); } } var appRoot = GlobalAttributesCache.Read( rockContext ).GetValue( "ExternalApplicationRoot" ); Email.Send( (Guid)emailTemplateGuid, recipients, appRoot ); context.Result = string.Format( "{0} emails sent", recipients.Count() ); } }
/// <summary> /// Gets the communication list members. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="listGroupId">The list group identifier.</param> /// <param name="segmentCriteria">The segment criteria.</param> /// <param name="segmentDataViewIds">The segment data view ids.</param> /// <returns></returns> public static IQueryable <GroupMember> GetCommunicationListMembers(RockContext rockContext, int?listGroupId, SegmentCriteria segmentCriteria, List <int> segmentDataViewIds) { IQueryable <GroupMember> groupMemberQuery = null; if (listGroupId.HasValue) { var groupMemberService = new GroupMemberService(rockContext); var personService = new PersonService(rockContext); var dataViewService = new DataViewService(rockContext); groupMemberQuery = groupMemberService.Queryable().Where(a => a.GroupId == listGroupId.Value && a.GroupMemberStatus == GroupMemberStatus.Active); Expression segmentExpression = null; ParameterExpression paramExpression = personService.ParameterExpression; var segmentDataViewList = dataViewService.GetByIds(segmentDataViewIds).AsNoTracking().ToList(); foreach (var segmentDataView in segmentDataViewList) { List <string> errorMessages; var exp = segmentDataView.GetExpression(personService, paramExpression, out errorMessages); if (exp != null) { if (segmentExpression == null) { segmentExpression = exp; } else { if (segmentCriteria == SegmentCriteria.All) { segmentExpression = Expression.AndAlso(segmentExpression, exp); } else { segmentExpression = Expression.OrElse(segmentExpression, exp); } } } } if (segmentExpression != null) { var personQry = personService.Get(paramExpression, segmentExpression); groupMemberQuery = groupMemberQuery.Where(a => personQry.Any(p => p.Id == a.PersonId)); } } return(groupMemberQuery); }
/// <summary> /// Formats the selection. /// </summary> /// <param name="entityType"></param> /// <param name="selection">The selection.</param> /// <returns></returns> public override string FormatSelection( Type entityType, string selection ) { string s = "Not In Another Data View"; int? dataviewId = selection.AsIntegerOrNull(); if ( dataviewId.HasValue ) { var dataView = new DataViewService( new RockContext() ).Get( dataviewId.Value ); if ( dataView != null ) { return string.Format( "Not Included in '{0}' Data View", dataView.Name ); } } return s; }
/// <summary> /// Renders the specified writer. /// </summary> /// <param name="badge">The badge.</param> /// <param name="writer">The writer.</param> public override void Render( PersonBadgeCache badge, System.Web.UI.HtmlTextWriter writer ) { RockContext rockContext = new RockContext(); var dataViewAttributeGuid = GetAttributeValue( badge, "DataView" ).AsGuid(); var dataViewService = new DataViewService( rockContext ); if ( dataViewAttributeGuid != Guid.Empty ) { var dataView = dataViewService.Get( dataViewAttributeGuid ); if ( dataView != null ) { var errors = new List<string>(); var qry = dataView.GetQuery( null, 30, out errors ); if ( qry != null && qry.Where( e => e.Id == Person.Id ).Any() ) { Dictionary<string, object> mergeValues = new Dictionary<string, object>(); mergeValues.Add( "Person", Person ); writer.Write( GetAttributeValue( badge, "BadgeContent" ).ResolveMergeFields( mergeValues ) ); } } } }
/// <summary> /// Handles the Click event of the btnEdit 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 btnEdit_Click( object sender, EventArgs e ) { var service = new DataViewService(); var item = service.Get( int.Parse( hfDataViewId.Value ) ); ShowEditDetails( item ); }
/// <summary> /// Provides a user-friendly description of the specified filter values. /// </summary> /// <param name="entityType">The System Type of the entity to which the filter will be applied.</param> /// <param name="selection">A formatted string representing the filter settings.</param> /// <returns> /// A string containing the user-friendly description of the settings. /// </returns> public override string FormatSelection( Type entityType, string selection ) { var settings = new FilterSettings( selection ); string result = GetTitle( null ); if (!settings.IsValid) { return result; } using (var context = new RockContext()) { var dataView = new DataViewService( context ).Get( settings.PersonDataViewGuid.GetValueOrDefault() ); result = string.Format( "Members matching Person filter \"{0}\" is {1} {2}", ( dataView != null ? dataView.ToString() : string.Empty ), settings.PersonCountComparison.ConvertToString(), settings.PersonCount ); } return result; }
/// <summary> /// Handles the Click event of the btnCancel 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 btnCancel_Click( object sender, EventArgs e ) { if ( hfDataViewId.Value.Equals( "0" ) ) { int? parentCategoryId = PageParameter( "ParentCategoryId" ).AsIntegerOrNull(); if ( parentCategoryId.HasValue ) { // Cancelling on Add, and we know the parentCategoryId, so we are probably in treeview mode, so navigate to the current page var qryParams = new Dictionary<string, string>(); qryParams["CategoryId"] = parentCategoryId.ToString(); NavigateToPage( RockPage.Guid, qryParams ); } else { // Cancelling on Add. Return to Grid NavigateToParentPage(); } } else { // Cancelling on Edit. Return to Details DataViewService service = new DataViewService(new RockContext()); DataView item = service.Get( int.Parse( hfDataViewId.Value ) ); ShowReadonlyDetails( item ); } }
/// <summary> /// Provides a user-friendly description of the specified filter values. /// </summary> /// <param name="entityType">The System Type of the entity to which the filter will be applied.</param> /// <param name="selection">A formatted string representing the filter settings.</param> /// <returns> /// A string containing the user-friendly description of the settings. /// </returns> public override string FormatSelection( Type entityType, string selection ) { var settings = new FilterSettings( selection ); string result = "Connected to Location"; if (!settings.IsValid) { return result; } using (var context = new RockContext()) { var dataView = new DataViewService( context ).Get( settings.DataViewGuid.GetValueOrDefault() ); string locationTypeName = null; if (settings.LocationTypeGuid.HasValue) { locationTypeName = DefinedValueCache.Read( settings.LocationTypeGuid.Value, context ).Value; } result = string.Format( "Location {0} is in filter: {1}", ( locationTypeName != null ? "type \"" + locationTypeName + "\"" : string.Empty ), ( dataView != null ? dataView.ToString() : string.Empty ) ); } return result; }
/// <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 ) { DataView dataView = null; var rockContext = new RockContext(); DataViewService service = new DataViewService( rockContext ); int dataViewId = int.Parse( hfDataViewId.Value ); int? origDataViewFilterId = null; if ( dataViewId == 0 ) { dataView = new DataView(); dataView.IsSystem = false; } else { dataView = service.Get( dataViewId ); origDataViewFilterId = dataView.DataViewFilterId; } dataView.Name = tbName.Text; dataView.Description = tbDescription.Text; dataView.TransformEntityTypeId = ddlTransform.SelectedValueAsInt(); dataView.EntityTypeId = etpEntityType.SelectedEntityTypeId; dataView.CategoryId = cpCategory.SelectedValueAsInt(); var newDataViewFilter = ReportingHelper.GetFilterFromControls( phFilters ); if ( !Page.IsValid ) { return; } if ( !dataView.IsValid ) { // Controls will render the error messages return; } var adding = dataView.Id.Equals( 0 ); if ( adding ) { service.Add( dataView ); } rockContext.WrapTransaction( () => { if ( origDataViewFilterId.HasValue ) { // delete old report filter so that we can add the new filter (but with original guids), then drop the old filter DataViewFilterService dataViewFilterService = new DataViewFilterService( rockContext ); DataViewFilter origDataViewFilter = dataViewFilterService.Get( origDataViewFilterId.Value ); dataView.DataViewFilterId = null; rockContext.SaveChanges(); DeleteDataViewFilter( origDataViewFilter, dataViewFilterService ); } dataView.DataViewFilter = newDataViewFilter; rockContext.SaveChanges(); } ); if ( adding ) { // add EDIT and ADMINISTRATE to the person who added the dataView Rock.Security.Authorization.AllowPerson( dataView, Authorization.EDIT, this.CurrentPerson, rockContext ); Rock.Security.Authorization.AllowPerson( dataView, Authorization.ADMINISTRATE, this.CurrentPerson, rockContext ); } var qryParams = new Dictionary<string, string>(); qryParams["DataViewId"] = dataView.Id.ToString(); NavigateToPage( RockPage.Guid, qryParams ); }
/// <summary> /// Provides a user-friendly description of the specified filter values. /// </summary> /// <param name="entityType">The System Type of the entity to which the filter will be applied.</param> /// <param name="selection">A formatted string representing the filter settings.</param> /// <returns> /// A string containing the user-friendly description of the settings. /// </returns> public override string FormatSelection( Type entityType, string selection ) { var settings = new SelectSettings( selection ); string result = GetTitle( null ); if ( !settings.IsValid ) { return result; } using ( var context = new RockContext() ) { var dataView = new DataViewService( context ).Get( settings.DataViewGuid.GetValueOrDefault() ); result = string.Format( "Members of Groups in Data View \"{0}\"", (dataView != null ? dataView.ToString() : string.Empty )); var groupMemberStatus = settings.MemberStatus; if (groupMemberStatus.HasValue) { result += ", with Status: " + groupMemberStatus.ToString(); } if (settings.RoleType.HasValue && settings.RoleType != RoleTypeSpecifier.Any) { result += ", with Role Type: " + settings.RoleType.ToString(); } } return result; }
/// <summary> /// Job that will sync groups. /// /// Called by the <see cref="IScheduler" /> when a /// <see cref="ITrigger" /> fires that is associated with /// the <see cref="IJob" />. /// </summary> public virtual void Execute( IJobExecutionContext context ) { JobDataMap dataMap = context.JobDetail.JobDataMap; bool requirePasswordReset = dataMap.GetBoolean( "RequirePasswordReset" ); int groupsSynced = 0; int groupsChanged = 0; try { // get groups set to sync GroupService groupService = new GroupService( new RockContext() ); var groupIdsThatSync = groupService.Queryable().Where( g => g.SyncDataViewId != null ).Select( a => a.Id ).ToList(); foreach ( var syncGroupId in groupIdsThatSync ) { bool hasGroupChanged = false; // use a fresh rockContext per group so that ChangeTracker doesn't get bogged down using ( var rockContext = new RockContext() ) { var syncGroup = new GroupService( rockContext ).Get( syncGroupId ); GroupMemberService groupMemberService = new GroupMemberService( rockContext ); // increase the timeout just in case the dataview source is slow rockContext.Database.CommandTimeout = 180; var syncSource = new DataViewService( rockContext ).Get( syncGroup.SyncDataViewId.Value ); // ensure this is a person dataview bool isPersonDataSet = syncSource.EntityTypeId == EntityTypeCache.Read( typeof( Rock.Model.Person ) ).Id; if ( isPersonDataSet ) { SortProperty sortById = new SortProperty(); sortById.Property = "Id"; sortById.Direction = System.Web.UI.WebControls.SortDirection.Ascending; List<string> errorMessages = new List<string>(); var personService = new PersonService( rockContext ); var parameterExpression = personService.ParameterExpression; var whereExpression = syncSource.GetExpression( personService, parameterExpression, out errorMessages ); var sourceItems = personService.Get( parameterExpression, whereExpression ).Select( q => q.Id ).ToList(); var targetItems = groupMemberService.Queryable().Where( gm => gm.GroupId == syncGroup.Id ).ToList(); // delete items from the target not in the source foreach ( var targetItem in targetItems.Where( t => !sourceItems.Contains( t.PersonId ) ) ) { // made a clone of the person as it will be detached when the group member is deleted. Also // saving the delete before the email is sent in case an exception occurs so the user doesn't // get an email everytime the agent runs. Person recipient = (Person)targetItem.Person.Clone(); groupMemberService.Delete( targetItem ); rockContext.SaveChanges(); hasGroupChanged = true; if ( syncGroup.ExitSystemEmailId.HasValue ) { SendExitEmail( syncGroup.ExitSystemEmailId.Value, recipient, syncGroup ); } } // add items not in target but in the source foreach ( var sourceItem in sourceItems.Where( s => !targetItems.Select( t => t.PersonId ).Contains( s ) ) ) { // add source to target var newGroupMember = new GroupMember { Id = 0 }; newGroupMember.PersonId = sourceItem; newGroupMember.Group = syncGroup; newGroupMember.GroupMemberStatus = GroupMemberStatus.Active; newGroupMember.GroupRoleId = syncGroup.GroupType.DefaultGroupRoleId ?? syncGroup.GroupType.Roles.FirstOrDefault().Id; groupMemberService.Add( newGroupMember ); hasGroupChanged = true; if ( syncGroup.WelcomeSystemEmailId.HasValue ) { SendWelcomeEmail( syncGroup.WelcomeSystemEmailId.Value, sourceItem, syncGroup, syncGroup.AddUserAccountsDuringSync ?? false, requirePasswordReset ); } } if ( hasGroupChanged ) { groupsChanged++; } groupsSynced++; rockContext.SaveChanges(); if ( hasGroupChanged && ( syncGroup.IsSecurityRole || syncGroup.GroupType.Guid.Equals( Rock.SystemGuid.GroupType.GROUPTYPE_SECURITY_ROLE.AsGuid() ) ) ) { Rock.Security.Role.Flush( syncGroup.Id ); } } } } var resultMessage = string.Empty; if ( groupsSynced == 0 ) { resultMessage = "No groups to sync"; } else if ( groupsSynced == 1 ) { resultMessage = "1 group was sync'ed"; } else { resultMessage = string.Format( "{0} groups were sync'ed", groupsSynced ); } resultMessage += string.Format( " and {0} groups where changed", groupsChanged ); context.Result = resultMessage; } catch ( System.Exception ex ) { HttpContext context2 = HttpContext.Current; ExceptionLogService.LogException( ex, context2 ); throw; } }
/// <summary> /// Persists the DataView to the database by updating the DataViewPersistedValues for this DataView. Returns true if successful /// </summary> /// <param name="databaseTimeoutSeconds">The database timeout seconds.</param> public void PersistResult(int?databaseTimeoutSeconds = null) { List <string> errorMessages; using (var dbContext = this.GetDbContext()) { Stopwatch persistStopwatch = Stopwatch.StartNew(); Stopwatch stopwatch = Stopwatch.StartNew(); DataViewFilterOverrides dataViewFilterOverrides = new DataViewFilterOverrides(); // set an override so that the Persisted Values aren't used when rebuilding the values from the DataView Query dataViewFilterOverrides.IgnoreDataViewPersistedValues.Add(this.Id); var qry = this.GetQuery(null, dbContext, dataViewFilterOverrides, databaseTimeoutSeconds, out errorMessages); if (!errorMessages.Any()) { RockContext rockContext = dbContext as RockContext; if (rockContext == null) { rockContext = new RockContext(); } rockContext.Database.CommandTimeout = databaseTimeoutSeconds; var savedDataViewPersistedValues = rockContext.DataViewPersistedValues.Where(a => a.DataViewId == this.Id); var updatedEntityIdsQry = qry.Select(a => a.Id); if (!(rockContext is RockContext)) { // if this DataView doesn't use a RockContext get the EntityIds into memory as as a List<int> then back into IQueryable<int> so that we aren't use multiple dbContexts updatedEntityIdsQry = updatedEntityIdsQry.ToList().AsQueryable(); } var persistedValuesToRemove = savedDataViewPersistedValues.Where(a => !updatedEntityIdsQry.Any(x => x == a.EntityId)); var persistedEntityIdsToInsert = updatedEntityIdsQry.Where(x => !savedDataViewPersistedValues.Any(a => a.EntityId == x)).ToList(); stopwatch.Stop(); int removeCount = persistedValuesToRemove.Count(); if (removeCount > 0) { // increase the batch size if there are a bunch of rows (and this is a narrow table with no references to it) int?deleteBatchSize = removeCount > 50000 ? 25000 : ( int? )null; int rowRemoved = rockContext.BulkDelete(persistedValuesToRemove, deleteBatchSize); } if (persistedEntityIdsToInsert.Any()) { List <DataViewPersistedValue> persistedValuesToInsert = persistedEntityIdsToInsert.OrderBy(a => a) .Select(a => new DataViewPersistedValue { DataViewId = this.Id, EntityId = a }).ToList(); rockContext.BulkInsert(persistedValuesToInsert); } persistStopwatch.Stop(); DataViewService.AddRunDataViewTransaction(this.Id, Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds), Convert.ToInt32(persistStopwatch.Elapsed.TotalMilliseconds)); } } }
/// <summary> /// Gets the expression. /// </summary> /// <param name="serviceInstance">The service instance.</param> /// <param name="paramExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public Expression GetExpression(IService serviceInstance, ParameterExpression paramExpression, DataViewFilterOverrides dataViewFilterOverrides, out List <string> errorMessages) { errorMessages = new List <string>(); var cachedEntityType = EntityTypeCache.Get(EntityTypeId.Value); if (cachedEntityType?.AssemblyName == null) { return(null); } Type filteredEntityType = cachedEntityType.GetEntityType(); if (filteredEntityType == null) { return(null); } bool usePersistedValues = this.PersistedScheduleIntervalMinutes.HasValue && this.PersistedLastRefreshDateTime.HasValue; if (dataViewFilterOverrides != null) { // don't use persisted values if this dataview is in the list of dataviews that should not be persisted due to override usePersistedValues = usePersistedValues && !dataViewFilterOverrides.IgnoreDataViewPersistedValues.Contains(this.Id); } DataViewService.AddRunDataViewTransaction(Id); if (usePersistedValues) { // If this is a persisted dataview, get the ids for the expression by querying DataViewPersistedValue instead of evaluating all the filters var rockContext = serviceInstance.Context as RockContext; if (rockContext == null) { rockContext = new RockContext(); } var persistedValuesQuery = rockContext.DataViewPersistedValues.Where(a => a.DataViewId == this.Id); var ids = persistedValuesQuery.Select(v => v.EntityId); MemberExpression propertyExpression = Expression.Property(paramExpression, "Id"); if (!(serviceInstance.Context is RockContext)) { // if this DataView doesn't use a RockContext get the EntityIds into memory as as a List<int> then back into IQueryable<int> so that we aren't use multiple dbContexts ids = ids.ToList().AsQueryable(); } var idsExpression = Expression.Constant(ids.AsQueryable(), typeof(IQueryable <int>)); Expression expression = Expression.Call(typeof(Queryable), "Contains", new Type[] { typeof(int) }, idsExpression, propertyExpression); return(expression); } else { Expression filterExpression = DataViewFilter != null?DataViewFilter.GetExpression(filteredEntityType, serviceInstance, paramExpression, dataViewFilterOverrides, errorMessages) : null; if (cachedEntityType.Id == EntityTypeCache.Get(typeof(Rock.Model.Person)).Id) { var qry = new PersonService(( RockContext )serviceInstance.Context).Queryable(this.IncludeDeceased); Expression extractedFilterExpression = FilterExpressionExtractor.Extract <Rock.Model.Person>(qry, paramExpression, "p"); if (filterExpression == null) { filterExpression = extractedFilterExpression; } else { filterExpression = Expression.AndAlso(filterExpression, extractedFilterExpression); } } Expression transformedExpression = GetTransformExpression(serviceInstance, paramExpression, filterExpression, errorMessages); if (transformedExpression != null) { return(transformedExpression); } return(filterExpression); } }
/// <summary> /// Called after the save operation has been executed /// </summary> /// <remarks> /// This method is only called if <see cref="M:Rock.Data.EntitySaveHook`1.PreSave" /> returns /// without error. /// </remarks> protected override void PostSave() { // Get the current person's alias ID from the current context. var currentPersonAliasId = DbContext.GetCurrentPersonAlias()?.Id; var connectionRequest = this.Entity as ConnectionRequest; // Create and send the change notification message now that the connection request has been saved. var processConnectionRequestChangeMessage = GetProcessConnectionRequestChangeMessage(Entry, connectionRequest, currentPersonAliasId); processConnectionRequestChangeMessage.SendWhen(this.DbContext.WrappedTransactionCompletedTask); var rockContext = ( RockContext )this.RockContext; if (Entity.ConnectionStatus == null) { Entity.ConnectionStatus = new ConnectionStatusService(rockContext).Get(Entity.ConnectionStatusId); } if (Entity.ConnectionStatus != null && Entity.ConnectionStatus.AutoInactivateState && Entity.ConnectionState != ConnectionState.Inactive) { Entity.ConnectionState = ConnectionState.Inactive; rockContext.SaveChanges(); } var connectionStatusAutomationsQuery = new ConnectionStatusAutomationService(rockContext).Queryable().Where(a => a.SourceStatusId == Entity.ConnectionStatusId); if (this.Entity._runAutomationsInPostSaveChanges && connectionStatusAutomationsQuery.Any()) { var connectionStatusAutomationsList = connectionStatusAutomationsQuery.AsNoTracking().OrderBy(a => a.AutomationName).ToList(); var connectionStatusAutomations = connectionStatusAutomationsList; int changedStatusCount = 0; foreach (var connectionStatusAutomation in connectionStatusAutomations) { if (this.Entity.processedConnectionStatusAutomations.Contains(connectionStatusAutomation.Id)) { // to avoid recursion, skip over automations that have already been processed in this thread. continue; } if (Entity.ConnectionStatusId == connectionStatusAutomation.DestinationStatusId) { // If already have this status, no need to figure out if it needs to be set to this status, // or to set the status. this.Entity.processedConnectionStatusAutomations.Add(connectionStatusAutomation.Id); continue; } bool isAutomationValid = true; 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) { var dataViewQuery = new ConnectionRequestService(rockContext).GetQueryUsingDataView(dataview); isAutomationValid = dataViewQuery.Any(a => a.Id == Entity.Id); } } if (isAutomationValid && connectionStatusAutomation.GroupRequirementsFilter != GroupRequirementsFilter.Ignore) { // Group Requirement can't be meet when either placement group or placement group role id is missing if (!Entity.AssignedGroupId.HasValue || !Entity.AssignedGroupMemberRoleId.HasValue) { isAutomationValid = false; } else { var isRequirementMeet = true; var group = new GroupService(rockContext).Get(Entity.AssignedGroupId.Value); var hasGroupRequirement = new GroupRequirementService(rockContext).Queryable().Where(a => (a.GroupId.HasValue && a.GroupId == group.Id) || (a.GroupTypeId.HasValue && a.GroupTypeId == group.GroupTypeId)).Any(); if (hasGroupRequirement) { var requirementsResults = group.PersonMeetsGroupRequirements( rockContext, Entity.PersonAlias.PersonId, Entity.AssignedGroupMemberRoleId.Value); if (requirementsResults != null && requirementsResults .Where(a => a.MeetsGroupRequirement != MeetsGroupRequirement.NotApplicable) .Any(r => r.MeetsGroupRequirement != MeetsGroupRequirement.Meets && r.MeetsGroupRequirement != MeetsGroupRequirement.MeetsWithWarning) ) { isRequirementMeet = false; } } // connection request based on if group requirement is meet or not is added to list for status update isAutomationValid = (connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.DoesNotMeet && !isRequirementMeet) || (connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.MustMeet && isRequirementMeet); } } if (isAutomationValid) { if (Entity.SetConnectionStatusFromAutomationLoop(connectionStatusAutomation)) { changedStatusCount++; rockContext.SaveChanges(); } } } } var hasHistoryChanges = HistoryChangeList?.Any() == true; var hasPersonHistoryChanges = PersonHistoryChangeList?.Any() == true; if (hasHistoryChanges || hasPersonHistoryChanges) { using (var historyRockContext = new RockContext()) { if (hasHistoryChanges) { HistoryService.SaveChanges(historyRockContext, typeof(ConnectionRequest), Rock.SystemGuid.Category.HISTORY_CONNECTION_REQUEST.AsGuid(), Entity.Id, HistoryChangeList, false, Entity.ModifiedByPersonAliasId); } if (hasPersonHistoryChanges) { var personId = Entity.PersonAlias?.PersonId ?? new PersonAliasService(rockContext).GetPersonId(Entity.PersonAliasId); if (personId.HasValue) { HistoryService.SaveChanges( historyRockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_CONNECTION_REQUEST.AsGuid(), personId.Value, PersonHistoryChangeList, "Request", typeof(ConnectionRequest), Entity.Id, false, Entity.ModifiedByPersonAliasId, rockContext.SourceOfChange); } } historyRockContext.SaveChanges(false); } } base.PostSave(); }
/// <summary> /// Called after the save operation has been executed /// </summary> /// <remarks> /// This method is only called if <see cref="M:Rock.Data.EntitySaveHook`1.PreSave" /> returns /// without error. /// </remarks> protected override void PostSave() { var rockContext = ( RockContext )this.RockContext; if (Entity.ConnectionStatus == null) { Entity.ConnectionStatus = new ConnectionStatusService(rockContext).Get(Entity.ConnectionStatusId); } if (Entity.ConnectionStatus != null && Entity.ConnectionStatus.AutoInactivateState && Entity.ConnectionState != ConnectionState.Inactive) { Entity.ConnectionState = ConnectionState.Inactive; rockContext.SaveChanges(); } if (Entity.ConnectionStatus.ConnectionStatusAutomations.Any()) { foreach (var connectionStatusAutomation in Entity.ConnectionStatus.ConnectionStatusAutomations) { bool isAutomationValid = true; 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) { var dataViewGetQueryArgs = new DataViewGetQueryArgs { DbContext = rockContext }; isAutomationValid = dataview.GetQuery(dataViewGetQueryArgs).Any(a => a.Id == Entity.Id); } } if (isAutomationValid && connectionStatusAutomation.GroupRequirementsFilter != GroupRequirementsFilter.Ignore) { // Group Requirement can't be meet when either placement group or placement group role id is missing if (!Entity.AssignedGroupId.HasValue || !Entity.AssignedGroupMemberRoleId.HasValue) { isAutomationValid = false; } else { var isRequirementMeet = true; var group = new GroupService(rockContext).Get(Entity.AssignedGroupId.Value); var hasGroupRequirement = new GroupRequirementService(rockContext).Queryable().Where(a => (a.GroupId.HasValue && a.GroupId == group.Id) || (a.GroupTypeId.HasValue && a.GroupTypeId == group.GroupTypeId)).Any(); if (hasGroupRequirement) { var requirementsResults = group.PersonMeetsGroupRequirements( rockContext, Entity.PersonAlias.PersonId, Entity.AssignedGroupMemberRoleId.Value); if (requirementsResults != null && requirementsResults .Where(a => a.MeetsGroupRequirement != MeetsGroupRequirement.NotApplicable) .Any(r => r.MeetsGroupRequirement != MeetsGroupRequirement.Meets && r.MeetsGroupRequirement != MeetsGroupRequirement.MeetsWithWarning) ) { isRequirementMeet = false; } } // connection request based on if group requirement is meet or not is added to list for status update isAutomationValid = (connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.DoesNotMeet && !isRequirementMeet) || (connectionStatusAutomation.GroupRequirementsFilter == GroupRequirementsFilter.MustMeet && isRequirementMeet); } } if (isAutomationValid) { Entity.ConnectionStatusId = connectionStatusAutomation.DestinationStatusId; // disabled pre post processing in order to prevent circular loop that may arise due to status change. rockContext.SaveChanges(true); } } } if (HistoryChangeList?.Any() == true) { HistoryService.SaveChanges(rockContext, typeof(ConnectionRequest), Rock.SystemGuid.Category.HISTORY_CONNECTION_REQUEST.AsGuid(), Entity.Id, HistoryChangeList, true, Entity.ModifiedByPersonAliasId); } if (PersonHistoryChangeList?.Any() == true) { var personAlias = Entity.PersonAlias ?? new PersonAliasService(rockContext).Get(Entity.PersonAliasId); HistoryService.SaveChanges( rockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_CONNECTION_REQUEST.AsGuid(), personAlias.PersonId, PersonHistoryChangeList, "Request", typeof(ConnectionRequest), Entity.Id, true, Entity.ModifiedByPersonAliasId, rockContext.SourceOfChange); } base.PostSave(); }
/// <summary> /// Handles the Click event of the btnCancel 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 btnCancel_Click( object sender, EventArgs e ) { if ( hfDataViewId.Value.Equals( "0" ) ) { // Cancelling on Add. Return to tree view with parent category selected var qryParams = new Dictionary<string, string>(); string parentCategoryId = PageParameter( "parentCategoryId" ); if ( !string.IsNullOrWhiteSpace( parentCategoryId ) ) { qryParams["CategoryId"] = parentCategoryId; } NavigateToPage( RockPage.Guid, qryParams ); } else { // Cancelling on Edit. Return to Details DataViewService service = new DataViewService(); DataView item = service.Get( int.Parse( hfDataViewId.Value ) ); ShowReadonlyDetails( item ); } }
/// <summary> /// Shows the detail. /// </summary> /// <param name="itemKey">The item key.</param> /// <param name="itemKeyValue">The item key value.</param> /// <param name="parentCategoryId">The parent category id.</param> public void ShowDetail( string itemKey, int itemKeyValue, int? parentCategoryId ) { pnlDetails.Visible = false; if ( !itemKey.Equals( "DataViewId" ) ) { return; } var dataViewService = new DataViewService(); DataView dataView = null; if ( !itemKeyValue.Equals( 0 ) ) { dataView = dataViewService.Get( itemKeyValue ); } else { dataView = new DataView { Id = 0, IsSystem = false, CategoryId = parentCategoryId }; } if ( dataView == null || !dataView.IsAuthorized( "View", CurrentPerson ) ) { return; } pnlDetails.Visible = true; hfDataViewId.Value = dataView.Id.ToString(); // render UI based on Authorized and IsSystem bool readOnly = false; nbEditModeMessage.Text = string.Empty; if ( !dataView.IsAuthorized( "Edit", CurrentPerson ) ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( DataView.FriendlyTypeName ); } if ( dataView.DataViewFilter != null && !dataView.DataViewFilter.IsAuthorized( "View", CurrentPerson ) ) { readOnly = true; nbEditModeMessage.Text = "INFO: This Data View contains a filter that you do not have access to view."; } if ( dataView.IsSystem ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlySystem( DataView.FriendlyTypeName ); } btnSecurity.Visible = dataView.IsAuthorized( "Administrate", CurrentPerson ); btnSecurity.Title = dataView.Name; btnSecurity.EntityId = dataView.Id; if ( readOnly ) { btnEdit.Visible = false; btnDelete.Visible = false; ShowReadonlyDetails( dataView ); } else { btnEdit.Visible = true; string errorMessage = string.Empty; btnDelete.Visible = dataViewService.CanDelete( dataView, out errorMessage ); if ( dataView.Id > 0 ) { ShowReadonlyDetails( dataView ); } else { ShowEditDetails( dataView ); } } }
/// <summary> /// Gets the chart data. /// </summary> /// <param name="groupBy">The group by.</param> /// <param name="graphBy">The graph by.</param> /// <param name="startDate">The start date.</param> /// <param name="endDate">The end date.</param> /// <param name="groupIds">The group ids.</param> /// <param name="campusIds">The campus ids. Include the keyword 'null' in the list to include CampusId is null</param> /// <param name="scheduleIds">The schedule ids.</param> /// <param name="dataViewId">The data view identifier.</param> /// <returns></returns> public IEnumerable <IChartData> GetChartData(ChartGroupBy groupBy = ChartGroupBy.Week, AttendanceGraphBy graphBy = AttendanceGraphBy.Total, DateTime?startDate = null, DateTime?endDate = null, string groupIds = null, string campusIds = null, int?dataViewId = null, string scheduleIds = null) { var qryAttendance = Queryable().AsNoTracking() .Where(a => a.DidAttend.HasValue && a.DidAttend.Value && a.PersonAlias != null); if (startDate.HasValue) { qryAttendance = qryAttendance.Where(a => a.StartDateTime >= startDate.Value); } if (endDate.HasValue) { qryAttendance = qryAttendance.Where(a => a.StartDateTime < endDate.Value); } if (dataViewId.HasValue) { var rockContext = (RockContext)this.Context; var dataView = new DataViewService(rockContext).Get(dataViewId.Value); if (dataView != null) { var personService = new PersonService(rockContext); var errorMessages = new List <string>(); ParameterExpression paramExpression = personService.ParameterExpression; Expression whereExpression = dataView.GetExpression(personService, paramExpression, out errorMessages); Rock.Web.UI.Controls.SortProperty sort = null; var dataViewPersonIdQry = personService .Queryable().AsNoTracking() .Where(paramExpression, whereExpression, sort) .Select(p => p.Id); qryAttendance = qryAttendance.Where(a => dataViewPersonIdQry.Contains(a.PersonAlias.PersonId)); } } if (!string.IsNullOrWhiteSpace(groupIds)) { var groupIdList = groupIds.Split(',').AsIntegerList(); qryAttendance = qryAttendance.Where(a => a.GroupId.HasValue && groupIdList.Contains(a.GroupId.Value)); } // If campuses were included, filter attendances by those that have selected campuses // if 'null' is one of the campuses, treat that as a 'CampusId is Null' var includeNullCampus = (campusIds ?? "").Split(',').ToList().Any(a => a.Equals("null", StringComparison.OrdinalIgnoreCase)); var campusIdList = (campusIds ?? "").Split(',').AsIntegerList(); // remove 0 from the list, just in case it is there campusIdList.Remove(0); if (campusIdList.Any()) { if (includeNullCampus) { // show records that have a campusId in the campusIdsList + records that have a null campusId qryAttendance = qryAttendance.Where(a => (a.CampusId.HasValue && campusIdList.Contains(a.CampusId.Value)) || !a.CampusId.HasValue); } else { // only show records that have a campusId in the campusIdList qryAttendance = qryAttendance.Where(a => a.CampusId.HasValue && campusIdList.Contains(a.CampusId.Value)); } } else if (includeNullCampus) { // 'null' was the only campusId in the campusIds parameter, so only show records that have a null CampusId qryAttendance = qryAttendance.Where(a => !a.CampusId.HasValue); } // If schedules were included, filter attendances by those that have selected schedules var scheduleIdList = (scheduleIds ?? "").Split(',').AsIntegerList(); scheduleIdList.Remove(0); if (scheduleIdList.Any()) { qryAttendance = qryAttendance.Where(a => a.ScheduleId.HasValue && scheduleIdList.Contains(a.ScheduleId.Value)); } var qryAttendanceWithSummaryDateTime = qryAttendance.GetAttendanceWithSummaryDateTime(groupBy); var summaryQry = qryAttendanceWithSummaryDateTime.Select(a => new { a.SummaryDateTime, Campus = new { Id = a.Attendance.CampusId, Name = a.Attendance.Campus.Name }, Group = new { Id = a.Attendance.GroupId, Name = a.Attendance.Group.Name }, Schedule = new { Id = a.Attendance.ScheduleId, Name = a.Attendance.Schedule.Name }, Location = new { Id = a.Attendance.LocationId, Name = a.Attendance.Location.Name } }); List <SummaryData> result = null; if (graphBy == AttendanceGraphBy.Total) { var groupByQry = summaryQry.GroupBy(a => new { a.SummaryDateTime }).Select(s => new { s.Key, Count = s.Count() }).OrderBy(o => o.Key); result = groupByQry.ToList().Select(a => new SummaryData { DateTimeStamp = a.Key.SummaryDateTime.ToJavascriptMilliseconds(), DateTime = a.Key.SummaryDateTime, SeriesName = "Total", YValue = a.Count }).ToList(); } else if (graphBy == AttendanceGraphBy.Campus) { var groupByQry = summaryQry.GroupBy(a => new { a.SummaryDateTime, Series = a.Campus }).Select(s => new { s.Key, Count = s.Count() }).OrderBy(o => o.Key); result = groupByQry.ToList().Select(a => new SummaryData { DateTimeStamp = a.Key.SummaryDateTime.ToJavascriptMilliseconds(), DateTime = a.Key.SummaryDateTime, SeriesName = a.Key.Series.Name, YValue = a.Count }).ToList(); } else if (graphBy == AttendanceGraphBy.Group) { var groupByQry = summaryQry.GroupBy(a => new { a.SummaryDateTime, Series = a.Group }).Select(s => new { s.Key, Count = s.Count() }).OrderBy(o => o.Key); result = groupByQry.ToList().Select(a => new SummaryData { DateTimeStamp = a.Key.SummaryDateTime.ToJavascriptMilliseconds(), DateTime = a.Key.SummaryDateTime, SeriesName = a.Key.Series.Name, YValue = a.Count }).ToList(); } else if (graphBy == AttendanceGraphBy.Schedule) { var groupByQry = summaryQry.GroupBy(a => new { a.SummaryDateTime, Series = a.Schedule }).Select(s => new { s.Key, Count = s.Count() }).OrderBy(o => o.Key); result = groupByQry.ToList().Select(a => new SummaryData { DateTimeStamp = a.Key.SummaryDateTime.ToJavascriptMilliseconds(), DateTime = a.Key.SummaryDateTime, SeriesName = a.Key.Series.Name, YValue = a.Count }).ToList(); } else if (graphBy == AttendanceGraphBy.Location) { var groupByQry = summaryQry.GroupBy(a => new { a.SummaryDateTime, Series = a.Location }).Select(s => new { s.Key, Count = s.Count() }).OrderBy(o => o.Key); result = groupByQry.ToList().Select(a => new SummaryData { DateTimeStamp = a.Key.SummaryDateTime.ToJavascriptMilliseconds(), DateTime = a.Key.SummaryDateTime, SeriesName = a.Key.Series.Name, YValue = a.Count }).ToList(); } return(result); }
/// <summary> /// Formats the selection. /// </summary> /// <param name="entityType"></param> /// <param name="selection">The selection.</param> /// <returns></returns> public override string FormatSelection( Type entityType, string selection ) { string s = "Another Data View"; int dataviewId = int.MinValue; if ( int.TryParse( selection, out dataviewId ) ) { var dataView = new DataViewService( new RockContext() ).Get( dataviewId ); if ( dataView != null ) { return string.Format( "Included in '{0}' Data View", dataView.Name ); } } return s; }
/// <summary> /// Gets the expression. /// </summary> /// <param name="entityType"></param> /// <param name="serviceInstance">The service instance.</param> /// <param name="parameterExpression">The parameter expression.</param> /// <param name="selection">The selection.</param> /// <returns></returns> /// <exception cref="System.Exception">Filter issue(s): + errorMessages.AsDelimited( ; )</exception> public override Expression GetExpression( Type entityType, IService serviceInstance, ParameterExpression parameterExpression, string selection ) { int dataviewId = int.MinValue; if ( int.TryParse( selection, out dataviewId ) ) { var dataView = new DataViewService( (RockContext)serviceInstance.Context ).Get( dataviewId ); if ( dataView != null && dataView.DataViewFilter != null ) { // Verify that there is not a child filter that uses this view (would result in stack-overflow error) if ( !IsViewInFilter( dataView.Id, dataView.DataViewFilter ) ) { // TODO: Should probably verify security again on the selected dataview and it's filters, // as that could be a moving target. var errorMessages = new List<string>(); Expression expression = dataView.GetExpression( serviceInstance, parameterExpression, out errorMessages ); if ( errorMessages.Any() ) { throw new System.Exception( "Filter issue(s): " + errorMessages.AsDelimited( "; " ) ); } return expression; } } } return null; }
/// <summary> /// Handles the Click event of the btnDelete 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 btnDelete_Click( object sender, EventArgs e ) { int? categoryId = null; var rockContext = new RockContext(); var dataViewService = new DataViewService( rockContext ); var dataView = dataViewService.Get( int.Parse( hfDataViewId.Value ) ); if ( dataView != null ) { string errorMessage; if ( !dataViewService.CanDelete( dataView, out errorMessage ) ) { ShowReadonlyDetails( dataView ); mdDeleteWarning.Show( errorMessage, ModalAlertType.Information ); } else { categoryId = dataView.CategoryId; // delete report filter try { DataViewFilterService dataViewFilterService = new DataViewFilterService( rockContext ); DeleteDataViewFilter( dataView.DataViewFilter, dataViewFilterService ); } catch { // } dataViewService.Delete( dataView ); rockContext.SaveChanges(); // reload page, selecting the deleted data view's parent var qryParams = new Dictionary<string, string>(); if ( categoryId != null ) { qryParams["CategoryId"] = categoryId.ToString(); } NavigateToPage( RockPage.Guid, qryParams ); } } }
/// <summary> /// Refresh the recipients list. /// </summary> /// <param name="rockContext">The rock context.</param> /// <returns></returns> public void RefreshCommunicationRecipientList(RockContext rockContext) { if (!ListGroupId.HasValue) { return; } var segmentDataViewGuids = this.Segments.SplitDelimitedValues().AsGuidList(); var segmentDataViewIds = new DataViewService(rockContext).GetByGuids(segmentDataViewGuids).Select(a => a.Id).ToList(); var qryCommunicationListMembers = GetCommunicationListMembers(rockContext, ListGroupId, this.SegmentCriteria, segmentDataViewIds); // NOTE: If this is scheduled communication, don't include Members that were added after the scheduled FutureSendDateTime. // However, don't exclude if the date added can't be determined or they will never be sent a scheduled communication. if (this.FutureSendDateTime.HasValue) { var memberAddedCutoffDate = this.FutureSendDateTime; qryCommunicationListMembers = qryCommunicationListMembers.Where(a => (a.DateTimeAdded.HasValue && a.DateTimeAdded.Value < memberAddedCutoffDate) || (a.CreatedDateTime.HasValue && a.CreatedDateTime.Value < memberAddedCutoffDate) || (!a.DateTimeAdded.HasValue && !a.CreatedDateTime.HasValue)); } var communicationRecipientService = new CommunicationRecipientService(rockContext); var recipientsQry = GetRecipientsQry(rockContext); // Get all the List member which is not part of communication recipients yet var newMemberInList = qryCommunicationListMembers .Include(c => c.Person) .Where(a => !recipientsQry.Any(r => r.PersonAlias.PersonId == a.PersonId)) .AsNoTracking() .ToList(); var emailMediumEntityType = EntityTypeCache.Get(SystemGuid.EntityType.COMMUNICATION_MEDIUM_EMAIL.AsGuid()); var smsMediumEntityType = EntityTypeCache.Get(SystemGuid.EntityType.COMMUNICATION_MEDIUM_SMS.AsGuid()); var pushMediumEntityType = EntityTypeCache.Get(SystemGuid.EntityType.COMMUNICATION_MEDIUM_PUSH_NOTIFICATION.AsGuid()); var recipientsToAdd = newMemberInList.Select(m => new CommunicationRecipient { PersonAliasId = m.Person.PrimaryAliasId.Value, Status = CommunicationRecipientStatus.Pending, CommunicationId = Id, MediumEntityTypeId = DetermineMediumEntityTypeId( emailMediumEntityType.Id, smsMediumEntityType.Id, pushMediumEntityType.Id, CommunicationType, m.CommunicationPreference, m.Person.CommunicationPreference) }); rockContext.BulkInsert <CommunicationRecipient>(recipientsToAdd); // Get all pending communication recipients that are no longer part of the group list member, then delete them from the Recipients var missingMemberInList = recipientsQry.Where(a => a.Status == CommunicationRecipientStatus.Pending) .Where(a => !qryCommunicationListMembers.Any(r => r.PersonId == a.PersonAlias.PersonId)); rockContext.BulkDelete <CommunicationRecipient>(missingMemberInList); rockContext.SaveChanges(); }
/// <summary> /// Shows the readonly details. /// </summary> /// <param name="dataView">The data view.</param> private void ShowReadonlyDetails( DataView dataView ) { SetEditMode( false ); hfDataViewId.SetValue( dataView.Id ); lReadOnlyTitle.Text = dataView.Name.FormatAsHtmlTitle(); hlblDataViewId.Text = "Id: " + dataView.Id.ToString(); lDescription.Text = dataView.Description; DescriptionList descriptionListMain = new DescriptionList(); if ( dataView.EntityType != null ) { descriptionListMain.Add( "Applies To", dataView.EntityType.FriendlyName ); } if ( dataView.Category != null ) { descriptionListMain.Add( "Category", dataView.Category.Name ); } if ( dataView.TransformEntityType != null ) { descriptionListMain.Add( "Post-filter Transformation", dataView.TransformEntityType.FriendlyName ); } lblMainDetails.Text = descriptionListMain.Html; DescriptionList descriptionListFilters = new DescriptionList(); if ( dataView.DataViewFilter != null && dataView.EntityTypeId.HasValue ) { var entityTypeCache = EntityTypeCache.Read( dataView.EntityTypeId.Value ); if ( entityTypeCache != null ) { var entityTypeType = entityTypeCache.GetEntityType(); if ( entityTypeType != null ) { descriptionListFilters.Add( "Filter", dataView.DataViewFilter.ToString( entityTypeType ) ); } } } lFilters.Text = descriptionListFilters.Html; DescriptionList descriptionListDataviews = new DescriptionList(); var dataViewFilterEntityId = EntityTypeCache.Read( typeof( Rock.Reporting.DataFilter.OtherDataViewFilter ) ).Id; var rockContext = new RockContext(); DataViewService dataViewService = new DataViewService( rockContext ); var dataViews = dataViewService.Queryable() .Where( d => d.DataViewFilter.ChildFilters .Any( f => f.Selection == dataView.Id.ToString() && f.EntityTypeId == dataViewFilterEntityId ) ); StringBuilder sbDataViews = new StringBuilder(); var dataViewDetailPage = GetAttributeValue( "DataViewDetailPage" ); foreach ( var dataview in dataViews ) { if ( !string.IsNullOrWhiteSpace( dataViewDetailPage ) ) { sbDataViews.Append( "<a href=\"" + LinkedPageUrl( "DataViewDetailPage", new Dictionary<string, string>() { { "DataViewId", dataview.Id.ToString() } } ) + "\">" + dataview.Name + "</a><br/>" ); } else { sbDataViews.Append( dataview.Name + "<br/>" ); } } descriptionListDataviews.Add( "Data Views", sbDataViews ); lDataViews.Text = descriptionListDataviews.Html; DescriptionList descriptionListReports = new DescriptionList(); StringBuilder sbReports = new StringBuilder(); ReportService reportService = new ReportService( rockContext ); var reports = reportService.Queryable().Where( r => r.DataViewId == dataView.Id ); var reportDetailPage = GetAttributeValue( "ReportDetailPage" ); foreach ( var report in reports ) { if ( !string.IsNullOrWhiteSpace( reportDetailPage ) ) { sbReports.Append( "<a href=\"" + LinkedPageUrl( "ReportDetailPage", new Dictionary<string, string>() { { "ReportId", report.Id.ToString() } } ) + "\">" + report.Name + "</a><br/>" ); } else { sbReports.Append( report.Name + "<br/>" ); } } descriptionListReports.Add( "Reports", sbReports ); lReports.Text = descriptionListReports.Html; ShowReport( dataView ); }
/// <summary> /// Gets the expression. /// </summary> /// <param name="serviceInstance">The service instance.</param> /// <param name="paramExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <returns></returns> /// <exception cref="Rock.Reporting.RockReportingException"> /// Unable to determine Assembly for EntityTypeId { EntityTypeId } /// or /// Unable to determine DataView EntityType for { dataViewEntityTypeCache }. /// or /// Unable to determine transform expression for TransformEntityTypeId: {TransformEntityTypeId} /// </exception> public Expression GetExpression(IService serviceInstance, ParameterExpression paramExpression, DataViewFilterOverrides dataViewFilterOverrides) { var dataViewEntityTypeCache = EntityTypeCache.Get(EntityTypeId.Value); if (dataViewEntityTypeCache?.AssemblyName == null) { throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"Unable to determine DataView Assembly for EntityTypeId { EntityTypeId }"); } Type dataViewEntityTypeType = dataViewEntityTypeCache.GetEntityType(); if (dataViewEntityTypeType == null) { throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"Unable to determine DataView EntityType for { dataViewEntityTypeCache }."); } // DataViews must have a DataViewFilter (something has gone wrong it doesn't have one) // Note that DataViewFilterId might be null even though DataViewFilter is not null // This is because the DataViewFilter might be just in memory and not saved to the database (for example, a Preview or a DynamicReport) if (this.DataViewFilter == null) { throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"DataViewFilter is null for DataView { this.Name } ({this.Id})."); } bool usePersistedValues = this.PersistedScheduleIntervalMinutes.HasValue && this.PersistedLastRefreshDateTime.HasValue; if (dataViewFilterOverrides != null) { // don't use persisted values if this DataView in the list of DataViews that should not be persisted due to override usePersistedValues = usePersistedValues && !dataViewFilterOverrides.IgnoreDataViewPersistedValues.Contains(this.Id); } // If dataViewFilterOverrides is null assume true in order to preserve current functionality. RockLogger.Log.Debug(RockLogDomains.Reporting, "{methodName} dataViewFilterOverrides: {@dataViewFilterOverrides} DataviewId: {DataviewId}", nameof(GetExpression), dataViewFilterOverrides, DataViewFilter.DataViewId); if (dataViewFilterOverrides == null || dataViewFilterOverrides.ShouldUpdateStatics) { DataViewService.AddRunDataViewTransaction(Id); } // We need to call GetExpression regardless of whether or not usePresistedValues is true so the child queries get their stats updated. var filterExpression = DataViewFilter != null?DataViewFilter.GetExpression(dataViewEntityTypeType, serviceInstance, paramExpression, dataViewFilterOverrides) : null; if (usePersistedValues) { // If this is a persisted DataView, get the ids for the expression by querying DataViewPersistedValue instead of evaluating all the filters var rockContext = serviceInstance.Context as RockContext; if (rockContext == null) { rockContext = new RockContext(); } var persistedValuesQuery = rockContext.DataViewPersistedValues.Where(a => a.DataViewId == this.Id); var ids = persistedValuesQuery.Select(v => v.EntityId); MemberExpression propertyExpression = Expression.Property(paramExpression, "Id"); if (!(serviceInstance.Context is RockContext)) { // if this DataView doesn't use a RockContext get the EntityIds into memory as a List<int> then back into IQueryable<int> so that we aren't use multiple dbContexts ids = ids.ToList().AsQueryable(); } var idsExpression = Expression.Constant(ids.AsQueryable(), typeof(IQueryable <int>)); Expression expression = Expression.Call(typeof(Queryable), "Contains", new Type[] { typeof(int) }, idsExpression, propertyExpression); return(expression); } else { if (dataViewEntityTypeCache.Id == EntityTypeCache.Get(typeof(Rock.Model.Person)).Id) { var qry = new PersonService(( RockContext )serviceInstance.Context).Queryable(this.IncludeDeceased); Expression extractedFilterExpression = FilterExpressionExtractor.Extract <Rock.Model.Person>(qry, paramExpression, "p"); if (filterExpression == null) { filterExpression = extractedFilterExpression; } else { filterExpression = Expression.AndAlso(filterExpression, extractedFilterExpression); } } if (this.TransformEntityTypeId.HasValue) { Expression transformedExpression = GetTransformExpression(this.TransformEntityTypeId.Value, serviceInstance, paramExpression, filterExpression); if (transformedExpression == null) { // if TransformEntityTypeId is defined, but we got null back, we'll get unexpected results, so throw an exception throw new RockDataViewFilterExpressionException(this.DataViewFilter, $"Unable to determine transform expression for TransformEntityTypeId: {TransformEntityTypeId}"); } return(transformedExpression); } return(filterExpression); } }
/// <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 ) { DataView dataView = null; var rockContext = new RockContext(); DataViewService service = new DataViewService( rockContext ); int dataViewId = int.Parse( hfDataViewId.Value ); int? dataViewFilterId = null; if ( dataViewId == 0 ) { dataView = new DataView(); dataView.IsSystem = false; } else { dataView = service.Get( dataViewId ); dataViewFilterId = dataView.DataViewFilterId; } dataView.Name = tbName.Text; dataView.Description = tbDescription.Text; dataView.TransformEntityTypeId = ddlTransform.SelectedValueAsInt(); dataView.EntityTypeId = ddlEntityType.SelectedValueAsInt(); dataView.CategoryId = cpCategory.SelectedValueAsInt(); dataView.DataViewFilter = GetFilterControl(); // update Guids since we are creating a new dataFilter and children and deleting the old one SetNewDataFilterGuids( dataView.DataViewFilter ); if ( !Page.IsValid ) { return; } if ( !dataView.IsValid ) { // Controls will render the error messages return; } if ( dataView.Id.Equals( 0 ) ) { service.Add( dataView ); } // Delete old report filter if ( dataViewFilterId.HasValue ) { DataViewFilterService dataViewFilterService = new DataViewFilterService( rockContext ); DataViewFilter dataViewFilter = dataViewFilterService.Get( dataViewFilterId.Value ); DeleteDataViewFilter( dataViewFilter, dataViewFilterService ); } rockContext.SaveChanges(); var qryParams = new Dictionary<string, string>(); qryParams["DataViewId"] = dataView.Id.ToString(); NavigateToPage( RockPage.Guid, qryParams ); }
/// <summary> /// Job that will sync groups. /// /// Called by the <see cref="IScheduler" /> when a /// <see cref="ITrigger" /> fires that is associated with /// the <see cref="IJob" />. /// </summary> public virtual void Execute( IJobExecutionContext context ) { JobDataMap dataMap = context.JobDetail.JobDataMap; try { // get groups set to sync RockContext rockContext = new RockContext(); GroupService groupService = new GroupService( rockContext ); var groupsThatSync = groupService.Queryable().Where( g => g.SyncDataViewId != null ).ToList(); foreach ( var syncGroup in groupsThatSync ) { GroupMemberService groupMemberService = new GroupMemberService( rockContext ); var syncSource = new DataViewService( rockContext ).Get( syncGroup.SyncDataViewId.Value ); // ensure this is a person dataview bool isPersonDataSet = syncSource.EntityTypeId == EntityTypeCache.Read( typeof( Rock.Model.Person ) ).Id; if ( isPersonDataSet ) { SortProperty sortById = new SortProperty(); sortById.Property = "Id"; sortById.Direction = System.Web.UI.WebControls.SortDirection.Ascending; List<string> errorMessages = new List<string>(); var sourceItems = syncSource.GetQuery( sortById, 180, out errorMessages ).Select( q => q.Id ).ToList(); var targetItems = groupMemberService.Queryable("Person").Where( gm => gm.GroupId == syncGroup.Id ).ToList(); // delete items from the target not in the source foreach ( var targetItem in targetItems.Where( t => !sourceItems.Contains( t.PersonId ) ) ) { // made a clone of the person as it will be detached when the group member is deleted. Also // saving the delete before the email is sent in case an exception occurs so the user doesn't // get an email everytime the agent runs. Person recipient = (Person)targetItem.Person.Clone(); groupMemberService.Delete( targetItem ); rockContext.SaveChanges(); if ( syncGroup.ExitSystemEmailId.HasValue ) { SendExitEmail( syncGroup.ExitSystemEmailId.Value, recipient, syncGroup ); } } // add items not in target but in the source foreach ( var sourceItem in sourceItems.Where( s => !targetItems.Select( t => t.PersonId ).Contains( s ) ) ) { // add source to target var newGroupMember = new GroupMember { Id = 0 }; newGroupMember.PersonId = sourceItem; newGroupMember.Group = syncGroup; newGroupMember.GroupMemberStatus = GroupMemberStatus.Active; newGroupMember.GroupRoleId = syncGroup.GroupType.DefaultGroupRoleId ?? syncGroup.GroupType.Roles.FirstOrDefault().Id; groupMemberService.Add( newGroupMember ); if ( syncGroup.WelcomeSystemEmailId.HasValue ) { SendWelcomeEmail( syncGroup.WelcomeSystemEmailId.Value, sourceItem, syncGroup, syncGroup.AddUserAccountsDuringSync ?? false ); } } rockContext.SaveChanges(); } } } catch ( System.Exception ex ) { HttpContext context2 = HttpContext.Current; ExceptionLogService.LogException( ex, context2 ); throw ex; } }
/// <summary> /// Shows the detail. /// </summary> /// <param name="itemKey">The item key.</param> /// <param name="itemKeyValue">The item key value.</param> /// <param name="parentCategoryId">The parent category id.</param> public void ShowDetail( string itemKey, int itemKeyValue, int? parentCategoryId ) { pnlDetails.Visible = false; if ( !itemKey.Equals( "DataViewId" ) ) { return; } var dataViewService = new DataViewService(new RockContext()); DataView dataView = null; if ( !itemKeyValue.Equals( 0 ) ) { dataView = dataViewService.Get( itemKeyValue ); } else { dataView = new DataView { Id = 0, IsSystem = false, CategoryId = parentCategoryId }; } if ( dataView == null || !dataView.IsAuthorized( Authorization.VIEW, CurrentPerson ) ) { return; } pnlDetails.Visible = true; hfDataViewId.Value = dataView.Id.ToString(); // render UI based on Authorized and IsSystem bool readOnly = false; nbEditModeMessage.Text = string.Empty; string authorizationMessage = string.Empty; if ( !this.IsAuthorizedForAllDataViewComponents( Authorization.EDIT, dataView, out authorizationMessage ) ) { readOnly = true; nbEditModeMessage.Text = authorizationMessage; } if ( dataView.IsSystem ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlySystem( DataView.FriendlyTypeName ); } btnSecurity.Visible = dataView.IsAuthorized( Authorization.ADMINISTRATE, CurrentPerson ); btnSecurity.Title = dataView.Name; btnSecurity.EntityId = dataView.Id; if ( readOnly ) { btnEdit.Visible = false; btnDelete.Visible = false; ShowReadonlyDetails( dataView ); } else { btnEdit.Visible = true; string errorMessage = string.Empty; btnDelete.Visible = dataViewService.CanDelete( dataView, out errorMessage ); if ( dataView.Id > 0 ) { ShowReadonlyDetails( dataView ); } else { ShowEditDetails( dataView ); } } }
/// <summary> /// Loads the drop downs. /// </summary> private void LoadDropDowns() { RockContext rockContext = new RockContext(); ddlDataView.Items.Clear(); var dataviewList = new DataViewService( rockContext ).Queryable().Select( s => new { s.Id, s.Name } ).OrderBy( a => a.Name ).ToList(); foreach ( var item in dataviewList ) { ddlDataView.Items.Add( new ListItem( item.Name, item.Id.ToString() ) ); } ddlSourceType.Items.Clear(); foreach ( var item in new DefinedValueService( rockContext ).GetByDefinedTypeGuid( Rock.SystemGuid.DefinedType.METRIC_SOURCE_TYPE.AsGuid() ) ) { ddlSourceType.Items.Add( new ListItem( item.Value, item.Id.ToString() ) ); } rblScheduleSelect.Items.Clear(); rblScheduleSelect.Items.Add( new ListItem( ScheduleSelectionType.Unique.ConvertToString(), ScheduleSelectionType.Unique.ConvertToInt().ToString() ) ); rblScheduleSelect.Items.Add( new ListItem( ScheduleSelectionType.NamedSchedule.ConvertToString(), ScheduleSelectionType.NamedSchedule.ConvertToInt().ToString() ) ); var scheduleCategoryId = new CategoryService( rockContext ).Get( Rock.SystemGuid.Category.SCHEDULE_METRICS.AsGuid() ).Id; var scheduleCategories = new ScheduleService( rockContext ).Queryable() .Where( a => a.CategoryId == scheduleCategoryId && a.Name != string.Empty ) .OrderBy( a => a.Name ).ToList(); ddlSchedule.Items.Clear(); foreach ( var item in scheduleCategories ) { ddlSchedule.Items.Add( new ListItem( item.Name, item.Id.ToString() ) ); } // limit to EntityTypes that support picking a Value with a picker etpMetricPartitionEntityType.EntityTypes = new EntityTypeService( new RockContext() ).GetEntities().OrderBy( t => t.FriendlyName ).Where( a => a.SingleValueFieldTypeId.HasValue ).ToList(); // just in case they select an EntityType that can be qualified by DefinedType... ddlMetricPartitionDefinedTypePicker.Items.Clear(); ddlMetricPartitionDefinedTypePicker.Items.Add( new ListItem() ); var definedTypesList = new DefinedTypeService( rockContext ).Queryable().OrderBy( a => a.Name ) .Select( a => new { a.Id, a.Name } ).ToList(); foreach ( var definedType in definedTypesList ) { ddlMetricPartitionDefinedTypePicker.Items.Add( new ListItem( definedType.Name, definedType.Id.ToString() ) ); } }
/// <summary> /// Binds the attendees grid. /// </summary> private void BindAttendeesGrid() { var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( drpSlidingDateRange.DelimitedValues ); if ( dateRange.End == null || dateRange.End > RockDateTime.Now ) { dateRange.End = RockDateTime.Now; } var rockContext = new RockContext(); // make a qryPersonAlias so that the generated SQL will be a "WHERE .. IN ()" instead of an OUTER JOIN (which is incredibly slow for this) var qryPersonAlias = new PersonAliasService( rockContext ).Queryable(); var qryAttendance = new AttendanceService( rockContext ).Queryable(); qryAttendance = qryAttendance.Where( a => a.DidAttend.HasValue && a.DidAttend.Value ); var groupType = this.GetSelectedTemplateGroupType(); var qryAllVisits = qryAttendance; if ( groupType != null ) { var childGroupTypeIds = new GroupTypeService( rockContext ).GetChildGroupTypes( groupType.Id ).Select( a => a.Id ); qryAllVisits = qryAttendance.Where( a => childGroupTypeIds.Any( b => b == a.Group.GroupTypeId ) ); } else { return; } var groupIdList = new List<int>(); string groupIds = GetSelectedGroupIds().AsDelimited( "," ); if ( !string.IsNullOrWhiteSpace( groupIds ) ) { groupIdList = groupIds.Split( ',' ).AsIntegerList(); qryAttendance = qryAttendance.Where( a => a.GroupId.HasValue && groupIdList.Contains( a.GroupId.Value ) ); } //// If campuses were included, filter attendances by those that have selected campuses //// if 'null' is one of the campuses, treat that as a 'CampusId is Null' var includeNullCampus = clbCampuses.SelectedValues.Any( a => a.Equals( "null", StringComparison.OrdinalIgnoreCase ) ); var campusIdList = clbCampuses.SelectedValues.AsIntegerList(); // remove 0 from the list, just in case it is there campusIdList.Remove( 0 ); if ( campusIdList.Any() ) { if ( includeNullCampus ) { // show records that have a campusId in the campusIdsList + records that have a null campusId qryAttendance = qryAttendance.Where( a => ( a.CampusId.HasValue && campusIdList.Contains( a.CampusId.Value ) ) || !a.CampusId.HasValue ); } else { // only show records that have a campusId in the campusIdList qryAttendance = qryAttendance.Where( a => a.CampusId.HasValue && campusIdList.Contains( a.CampusId.Value ) ); } } else if ( includeNullCampus ) { // 'null' was the only campusId in the campusIds parameter, so only show records that have a null CampusId qryAttendance = qryAttendance.Where( a => !a.CampusId.HasValue ); } // have the "Missed" query be the same as the qry before the Main date range is applied since it'll have a different date range var qryMissed = qryAttendance; if ( dateRange.Start.HasValue ) { qryAttendance = qryAttendance.Where( a => a.StartDateTime >= dateRange.Start.Value ); } if ( dateRange.End.HasValue ) { qryAttendance = qryAttendance.Where( a => a.StartDateTime < dateRange.End.Value ); } // we want to get the first 2 visits at a minimum so we can show the date in the grid int nthVisitsTake = 2; int? byNthVisit = null; if ( radByVisit.Checked ) { // If we are filtering by nth visit, we might want to get up to first 5 byNthVisit = ddlNthVisit.SelectedValue.AsIntegerOrNull(); if ( byNthVisit.HasValue && byNthVisit > 2 ) { nthVisitsTake = byNthVisit.Value; } } ChartGroupBy groupBy = hfGroupBy.Value.ConvertToEnumOrNull<ChartGroupBy>() ?? ChartGroupBy.Week; IQueryable<PersonWithSummary> qryByPersonWithSummary = null; if ( byNthVisit.HasValue && byNthVisit.Value == 0 ) { // Show members of the selected groups that did not attend at all during selected date range // Get all the person ids that did attend var attendeePersonIds = qryAttendance.Select( a => a.PersonAlias.PersonId ); // Get all the active members of the selected groups who have no attendance within selected date range and campus qryByPersonWithSummary = new GroupMemberService( rockContext ) .Queryable().AsNoTracking() .Where( m => groupIdList.Contains( m.GroupId ) && !attendeePersonIds.Contains( m.PersonId ) && m.GroupMemberStatus == GroupMemberStatus.Active ) .Select( m => new PersonWithSummary { PersonId = m.PersonId, FirstVisits = new DateTime[] { }.AsQueryable(), LastVisit = new AttendancePersonAlias(), AttendanceSummary = new DateTime[] { }.AsQueryable() } ); } else { var qryAttendanceWithSummaryDateTime = qryAttendance.GetAttendanceWithSummaryDateTime( groupBy ); var qryGroup = new GroupService( rockContext ).Queryable(); var qryJoinPerson = qryAttendance.Join( qryPersonAlias, k1 => k1.PersonAliasId, k2 => k2.Id, ( a, pa ) => new { CampusId = a.CampusId, GroupId = a.GroupId, ScheduleId = a.ScheduleId, StartDateTime = a.StartDateTime, PersonAliasId = pa.Id, PersonAliasPersonId = pa.PersonId } ); var qryJoinFinal = qryJoinPerson.Join( qryGroup, k1 => k1.GroupId, k2 => k2.Id, ( a, g ) => new AttendancePersonAlias { CampusId = a.CampusId, GroupId = a.GroupId, GroupName = g.Name, ScheduleId = a.ScheduleId, StartDateTime = a.StartDateTime, PersonAliasId = a.PersonAliasId, PersonAliasPersonId = a.PersonAliasPersonId } ); var qryByPerson = qryJoinFinal.GroupBy( a => a.PersonAliasPersonId ).Select( a => new { PersonId = a.Key, Attendances = a } ); int? attendedMinCount = null; int? attendedMissedCount = null; DateRange attendedMissedDateRange = new DateRange(); if ( radByPattern.Checked ) { attendedMinCount = tbPatternXTimes.Text.AsIntegerOrNull(); if ( cbPatternAndMissed.Checked ) { attendedMissedCount = tbPatternMissedXTimes.Text.AsIntegerOrNull(); attendedMissedDateRange = new DateRange( drpPatternDateRange.LowerValue, drpPatternDateRange.UpperValue ); if ( !attendedMissedDateRange.Start.HasValue || !attendedMissedDateRange.End.HasValue ) { nbMissedDateRangeRequired.Visible = true; return; } } } nbMissedDateRangeRequired.Visible = false; // get either the first 2 visits or the first 5 visits (using a const take of 2 or 5 vs a variable to help the SQL optimizer) qryByPersonWithSummary = qryByPerson.Select( a => new PersonWithSummary { PersonId = a.PersonId, FirstVisits = qryAllVisits.Where( b => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == b.PersonAliasId ) ).Select( s => s.StartDateTime ).OrderBy( x => x ).Take( 2 ), LastVisit = a.Attendances.OrderByDescending( x => x.StartDateTime ).FirstOrDefault(), AttendanceSummary = qryAttendanceWithSummaryDateTime.Where( x => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == x.Attendance.PersonAliasId ) ).GroupBy( g => g.SummaryDateTime ).Select( s => s.Key ) } ); if ( nthVisitsTake > 2 ) { qryByPersonWithSummary = qryByPerson.Select( a => new PersonWithSummary { PersonId = a.PersonId, FirstVisits = qryAllVisits.Where( b => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == b.PersonAliasId ) ).Select( s => s.StartDateTime ).OrderBy( x => x ).Take( 5 ), LastVisit = a.Attendances.OrderByDescending( x => x.StartDateTime ).FirstOrDefault(), AttendanceSummary = qryAttendanceWithSummaryDateTime.Where( x => qryPersonAlias.Where( pa => pa.PersonId == a.PersonId ).Any( pa => pa.Id == x.Attendance.PersonAliasId ) ).GroupBy( g => g.SummaryDateTime ).Select( s => s.Key ) } ); } if ( byNthVisit.HasValue ) { // only return attendees where their nth visit is within the selected daterange int skipCount = byNthVisit.Value - 1; qryByPersonWithSummary = qryByPersonWithSummary.Where( a => a.FirstVisits.OrderBy( x => x ).Skip( skipCount ).Take( 1 ).Any( d => d >= dateRange.Start && d < dateRange.End ) ); } if ( attendedMinCount.HasValue ) { qryByPersonWithSummary = qryByPersonWithSummary.Where( a => a.AttendanceSummary.Count() >= attendedMinCount ); } if ( attendedMissedCount.HasValue ) { if ( attendedMissedDateRange.Start.HasValue && attendedMissedDateRange.End.HasValue ) { var attendedMissedPossible = GetPossibleAttendancesForDateRange( attendedMissedDateRange, groupBy ); int attendedMissedPossibleCount = attendedMissedPossible.Count(); qryMissed = qryMissed.Where( a => a.StartDateTime >= attendedMissedDateRange.Start.Value && a.StartDateTime < attendedMissedDateRange.End.Value ); var qryMissedAttendanceByPersonAndSummary = qryMissed.GetAttendanceWithSummaryDateTime( groupBy ) .GroupBy( g1 => new { g1.SummaryDateTime, g1.Attendance.PersonAlias.PersonId } ) .GroupBy( a => a.Key.PersonId ) .Select( a => new { PersonId = a.Key, AttendanceCount = a.Count() } ); var qryMissedByPerson = qryMissedAttendanceByPersonAndSummary .Where( x => ( attendedMissedPossibleCount - x.AttendanceCount ) >= attendedMissedCount ); // filter to only people that missed at least X weeks/months/years between specified missed date range qryByPersonWithSummary = qryByPersonWithSummary.Where( a => qryMissedByPerson.Any( b => b.PersonId == a.PersonId ) ); } } } var personService = new PersonService( rockContext ); // Filter by dataview var dataViewId = dvpDataView.SelectedValueAsInt(); if ( dataViewId.HasValue ) { var dataView = new DataViewService( _rockContext ).Get( dataViewId.Value ); if ( dataView != null ) { var errorMessages = new List<string>(); ParameterExpression paramExpression = personService.ParameterExpression; Expression whereExpression = dataView.GetExpression( personService, paramExpression, out errorMessages ); SortProperty sort = null; var dataViewPersonIdQry = personService .Queryable().AsNoTracking() .Where( paramExpression, whereExpression, sort ) .Select( p => p.Id ); qryByPersonWithSummary = qryByPersonWithSummary.Where( a => dataViewPersonIdQry.Contains( a.PersonId ) ); } } // declare the qryResult that we'll use in case they didn't choose IncludeParents or IncludeChildren (and the Anonymous Type will also work if we do include parents or children) var qryPerson = personService.Queryable(); var qryResult = qryByPersonWithSummary.Join( qryPerson, a => a.PersonId, p => p.Id, ( a, p ) => new { a.PersonId, ParentId = (int?)null, ChildId = (int?)null, Person = p, Parent = (Person)null, Child = (Person)null, a.FirstVisits, a.LastVisit, p.PhoneNumbers, a.AttendanceSummary } ); var includeParents = hfViewBy.Value.ConvertToEnumOrNull<ViewBy>().GetValueOrDefault( ViewBy.Attendees ) == ViewBy.ParentsOfAttendees; var includeChildren = hfViewBy.Value.ConvertToEnumOrNull<ViewBy>().GetValueOrDefault( ViewBy.Attendees ) == ViewBy.ChildrenOfAttendees; // if Including Parents, join with qryChildWithParent instead of qryPerson if ( includeParents ) { var qryChildWithParent = new PersonService( rockContext ).GetChildWithParent(); qryResult = qryByPersonWithSummary.Join( qryChildWithParent, a => a.PersonId, p => p.Child.Id, ( a, p ) => new { a.PersonId, ParentId = (int?)p.Parent.Id, ChildId = (int?)null, Person = p.Child, Parent = p.Parent, Child = (Person)null, a.FirstVisits, a.LastVisit, p.Parent.PhoneNumbers, a.AttendanceSummary } ); } if ( includeChildren ) { var qryParentWithChildren = new PersonService( rockContext ).GetParentWithChild(); qryResult = qryByPersonWithSummary.Join( qryParentWithChildren, a => a.PersonId, p => p.Parent.Id, ( a, p ) => new { a.PersonId, ParentId = (int?)null, ChildId = (int?)p.Child.Id, Person = p.Parent, Parent = (Person)null, Child = p.Child, a.FirstVisits, a.LastVisit, p.Child.PhoneNumbers, a.AttendanceSummary } ); } var parentField = gAttendeesAttendance.Columns.OfType<PersonField>().FirstOrDefault( a => a.HeaderText == "Parent" ); if ( parentField != null ) { parentField.Visible = includeParents; } var parentEmailField = gAttendeesAttendance.Columns.OfType<RockBoundField>().FirstOrDefault( a => a.HeaderText == "Parent Email" ); if ( parentEmailField != null ) { parentEmailField.ExcelExportBehavior = includeParents ? ExcelExportBehavior.AlwaysInclude : ExcelExportBehavior.NeverInclude; } var childField = gAttendeesAttendance.Columns.OfType<PersonField>().FirstOrDefault( a => a.HeaderText == "Child" ); if ( childField != null ) { childField.Visible = includeChildren; } var childEmailField = gAttendeesAttendance.Columns.OfType<RockBoundField>().FirstOrDefault( a => a.HeaderText == "Child Email" ); if ( childEmailField != null ) { childEmailField.ExcelExportBehavior = includeChildren ? ExcelExportBehavior.AlwaysInclude : ExcelExportBehavior.NeverInclude; } SortProperty sortProperty = gAttendeesAttendance.SortProperty; if ( sortProperty != null ) { if ( sortProperty.Property == "AttendanceSummary.Count" ) { if ( sortProperty.Direction == SortDirection.Descending ) { qryResult = qryResult.OrderByDescending( a => a.AttendanceSummary.Count() ); } else { qryResult = qryResult.OrderBy( a => a.AttendanceSummary.Count() ); } } else if ( sortProperty.Property == "FirstVisit.StartDateTime" ) { if ( sortProperty.Direction == SortDirection.Descending ) { qryResult = qryResult.OrderByDescending( a => a.FirstVisits.Min() ); } else { qryResult = qryResult.OrderBy( a => a.FirstVisits.Min() ); } } else { qryResult = qryResult.Sort( sortProperty ); } } else { qryResult = qryResult.OrderBy( a => a.Person.LastName ).ThenBy( a => a.Person.NickName ); } var attendancePercentField = gAttendeesAttendance.Columns.OfType<RockTemplateField>().First( a => a.HeaderText.EndsWith( "Attendance %" ) ); attendancePercentField.HeaderText = string.Format( "{0}ly Attendance %", groupBy.ConvertToString() ); // Calculate all the possible attendance summary dates UpdatePossibleAttendances( dateRange, groupBy ); // pre-load the schedule names since FriendlyScheduleText requires building the ICal object, etc _scheduleNameLookup = new ScheduleService( rockContext ).Queryable() .ToList() .ToDictionary( k => k.Id, v => v.FriendlyScheduleText ); if ( includeParents ) { gAttendeesAttendance.PersonIdField = "ParentId"; gAttendeesAttendance.DataKeyNames = new string[] { "ParentId", "PersonId" }; } else if ( includeChildren ) { gAttendeesAttendance.PersonIdField = "ChildId"; gAttendeesAttendance.DataKeyNames = new string[] { "ChildId", "PersonId" }; } else { gAttendeesAttendance.PersonIdField = "PersonId"; gAttendeesAttendance.DataKeyNames = new string[] { "PersonId" }; } // Create the dynamic attendance grid columns as needed CreateDynamicAttendanceGridColumns(); try { nbAttendeesError.Visible = false; // increase the timeout from 30 to 90. The Query can be slow if SQL hasn't calculated the Query Plan for the query yet. // Sometimes, most of the time consumption is figuring out the Query Plan, but after it figures it out, it caches it so that the next time it'll be much faster rockContext.Database.CommandTimeout = 90; gAttendeesAttendance.SetLinqDataSource( qryResult.AsNoTracking() ); gAttendeesAttendance.DataBind(); } catch ( Exception exception ) { LogAndShowException( exception ); } }
/// <summary> /// Reads new values entered by the user for the field /// returns DataView.Guid /// </summary> /// <param name="control">Parent control that controls were added to in the CreateEditControl() method</param> /// <param name="configurationValues">The configuration values.</param> /// <returns></returns> public override string GetEditValue( Control control, Dictionary<string, ConfigurationValue> configurationValues ) { var picker = control as DataViewPicker; if ( picker != null ) { int? id = picker.SelectedValue.AsIntegerOrNull(); if ( id.HasValue ) { var dataview = new DataViewService( new RockContext() ).Get( id.Value ); if ( dataview != null ) { return dataview.Guid.ToString(); } } } return string.Empty; }
/// <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 ) { DataView dataView = null; using ( new UnitOfWorkScope() ) { DataViewService service = new DataViewService(); int dataViewId = int.Parse( hfDataViewId.Value ); int? dataViewFilterId = null; if ( dataViewId == 0 ) { dataView = new DataView(); dataView.IsSystem = false; } else { dataView = service.Get( dataViewId ); dataViewFilterId = dataView.DataViewFilterId; } dataView.Name = tbName.Text; dataView.Description = tbDescription.Text; dataView.TransformEntityTypeId = ddlTransform.SelectedValueAsInt(); dataView.EntityTypeId = ddlEntityType.SelectedValueAsInt(); dataView.CategoryId = cpCategory.SelectedValueAsInt(); dataView.DataViewFilter = GetFilterControl(); if ( !Page.IsValid ) { return; } if ( !dataView.IsValid ) { // Controls will render the error messages return; } RockTransactionScope.WrapTransaction( () => { if ( dataView.Id.Equals( 0 ) ) { service.Add( dataView, CurrentPersonId ); } service.Save( dataView, CurrentPersonId ); // Delete old report filter if ( dataViewFilterId.HasValue ) { DataViewFilterService dataViewFilterService = new DataViewFilterService(); DataViewFilter dataViewFilter = dataViewFilterService.Get( dataViewFilterId.Value ); DeleteDataViewFilter( dataViewFilter, dataViewFilterService ); dataViewFilterService.Save( dataViewFilter, CurrentPersonId ); } } ); } var qryParams = new Dictionary<string, string>(); qryParams["DataViewId"] = dataView.Id.ToString(); NavigateToPage( RockPage.Guid, qryParams ); }
/// <summary> /// Sets the value. /// value is an Account.Guid /// </summary> /// <param name="control">The control.</param> /// <param name="configurationValues">The configuration values.</param> /// <param name="value">The value.</param> public override void SetEditValue( Control control, Dictionary<string, ConfigurationValue> configurationValues, string value ) { var picker = control as DataViewPicker; if ( picker != null ) { Guid guid = value.AsGuid(); // get the item (or null) and set it var dataview = new DataViewService( new RockContext() ).Get( guid ); picker.SetValue( dataview ); } }
/// <summary> /// Handles the Click event of the btnDelete 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 btnDelete_Click( object sender, EventArgs e ) { int? categoryId = null; var dataViewService = new DataViewService(); var dataView = dataViewService.Get( int.Parse( hfDataViewId.Value ) ); if ( dataView != null ) { string errorMessage; if ( !dataViewService.CanDelete( dataView, out errorMessage ) ) { ShowReadonlyDetails( dataView ); mdDeleteWarning.Show( errorMessage, ModalAlertType.Information ); } else { categoryId = dataView.CategoryId; dataViewService.Delete( dataView, CurrentPersonId ); dataViewService.Save( dataView, CurrentPersonId ); // reload page, selecting the deleted data view's parent var qryParams = new Dictionary<string, string>(); if ( categoryId != null ) { qryParams["CategoryId"] = categoryId.ToString(); } NavigateToPage( RockPage.Guid, qryParams ); } } }
/// <summary> /// Returns the field's current value(s) /// </summary> /// <param name="parentControl">The parent control.</param> /// <param name="value">Information about the value</param> /// <param name="configurationValues">The configuration values.</param> /// <param name="condensed">Flag indicating if the value should be condensed (i.e. for use in a grid column)</param> /// <returns></returns> public override string FormatValue( Control parentControl, string value, Dictionary<string, ConfigurationValue> configurationValues, bool condensed ) { string formattedValue = string.Empty; Guid? guid = value.AsGuidOrNull(); if ( guid.HasValue ) { var service = new DataViewService( new RockContext() ); var dataview = service.Get( guid.Value ); if ( dataview != null ) { formattedValue = dataview.Name; } } return base.FormatValue( parentControl, formattedValue, null, condensed ); }
/// <summary> /// Handles the GridRebind event of the gReport 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 gReport_GridRebind( object sender, EventArgs e ) { var service = new DataViewService(); var item = service.Get( int.Parse( hfDataViewId.Value ) ); ShowReport( item ); }
/// <summary> /// Shows the detail. /// </summary> /// <param name="dataViewId">The data view identifier.</param> /// <param name="parentCategoryId">The parent category id.</param> public void ShowDetail( int dataViewId, int? parentCategoryId ) { pnlDetails.Visible = false; var rockContext = new RockContext(); var dataViewService = new DataViewService( rockContext ); DataView dataView = null; if ( !dataViewId.Equals( 0 ) ) { dataView = dataViewService.Get( dataViewId ); pdAuditDetails.SetEntity( dataView, ResolveRockUrl( "~" ) ); } if ( dataView == null ) { dataView = new DataView { Id = 0, IsSystem = false, CategoryId = parentCategoryId }; dataView.Name = string.Empty; // hide the panel drawer that show created and last modified dates pdAuditDetails.Visible = false; } if ( !dataView.IsAuthorized( Authorization.VIEW, CurrentPerson ) ) { return; } pnlDetails.Visible = true; hfDataViewId.Value = dataView.Id.ToString(); hlblEditDataViewId.Text = "Id: " + dataView.Id.ToString(); // render UI based on Authorized and IsSystem bool readOnly = false; nbEditModeMessage.Text = string.Empty; string authorizationMessage = string.Empty; if ( !dataView.IsAuthorizedForAllDataViewComponents( Authorization.EDIT, CurrentPerson, rockContext, out authorizationMessage ) ) { readOnly = true; nbEditModeMessage.Text = authorizationMessage; } if ( dataView.IsSystem ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlySystem( DataView.FriendlyTypeName ); } btnSecurity.Visible = dataView.IsAuthorized( Authorization.ADMINISTRATE, CurrentPerson ); btnSecurity.Title = dataView.Name; btnSecurity.EntityId = dataView.Id; if ( readOnly ) { btnEdit.Visible = false; btnDelete.Visible = false; ShowReadonlyDetails( dataView ); } else { btnEdit.Visible = true; string errorMessage = string.Empty; btnDelete.Enabled = dataViewService.CanDelete( dataView, out errorMessage ); if (!btnDelete.Enabled) { btnDelete.ToolTip = errorMessage; btnDelete.Attributes["onclick"] = null; } if ( dataView.Id > 0 ) { ShowReadonlyDetails( dataView ); } else { ShowEditDetails( dataView ); } } }
/// <summary> /// Sets the selection. /// Implement this version of SetSelection if your DataFilterComponent works the same in all FilterModes /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="controls">The controls.</param> /// <param name="selection">The selection.</param> public override void SetSelection( Type entityType, Control[] controls, string selection ) { var ddlDataView = controls.GetByName<DataViewPicker>( _CtlDataView ); var ddlRoleType = controls.GetByName<RockDropDownList>( _CtlRoleType ); var ddlGroupMemberStatus = controls.GetByName<RockDropDownList>( _CtlGroupStatus ); var settings = new SelectSettings( selection ); if ( !settings.IsValid ) { return; } if ( settings.DataViewGuid.HasValue ) { var dsService = new DataViewService( new RockContext() ); var dataView = dsService.Get( settings.DataViewGuid.Value ); if ( dataView != null ) { ddlDataView.SelectedValue = dataView.Id.ToString(); } } ddlRoleType.SelectedValue = settings.RoleType.ToStringSafe(); ddlGroupMemberStatus.SelectedValue = settings.MemberStatus.ToStringSafe(); }
/// <summary> /// Handles the Click event of the Copy button 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 btnCopy_Click( object sender, EventArgs e ) { // Create a new Data View using the current item as a template. var id = int.Parse( hfDataViewId.Value ); var dataViewService = new DataViewService( new RockContext() ); var newItem = dataViewService.GetNewFromTemplate( id ); if (newItem == null) return; newItem.Name += " (Copy)"; // Reset the stored identifier for the active Data View. hfDataViewId.Value = "0"; ShowEditDetails( newItem ); }
/// <summary> /// Refresh the recipients list. /// </summary> /// <param name="rockContext">The rock context.</param> /// <returns></returns> public void RefreshCommunicationRecipientList(RockContext rockContext) { if (!ListGroupId.HasValue) { return; } var emailMediumEntityType = EntityTypeCache.Get(SystemGuid.EntityType.COMMUNICATION_MEDIUM_EMAIL.AsGuid()); var smsMediumEntityType = EntityTypeCache.Get(SystemGuid.EntityType.COMMUNICATION_MEDIUM_SMS.AsGuid()); var preferredCommunicationTypeAttribute = AttributeCache.Get(SystemGuid.Attribute.GROUPMEMBER_COMMUNICATION_LIST_PREFERRED_COMMUNICATION_MEDIUM.AsGuid()); var segmentDataViewGuids = this.Segments.SplitDelimitedValues().AsGuidList(); var segmentDataViewIds = new DataViewService(rockContext).GetByGuids(segmentDataViewGuids).Select(a => a.Id).ToList(); var qryCommunicationListMembers = GetCommunicationListMembers(rockContext, ListGroupId, this.SegmentCriteria, segmentDataViewIds); // NOTE: If this is scheduled communication, don't include Members that were added after the scheduled FutureSendDateTime if (this.FutureSendDateTime.HasValue) { var memberAddedCutoffDate = this.FutureSendDateTime; qryCommunicationListMembers = qryCommunicationListMembers.Where(a => (a.DateTimeAdded.HasValue && a.DateTimeAdded.Value < memberAddedCutoffDate) || (a.CreatedDateTime.HasValue && a.CreatedDateTime.Value < memberAddedCutoffDate)); } var communicationRecipientService = new CommunicationRecipientService(rockContext); var recipientsQry = GetRecipientsQry(rockContext); // Get all the List member which is not part of communication recipients yet var newMemberInList = qryCommunicationListMembers .Where(a => !recipientsQry.Any(r => r.PersonAlias.PersonId == a.PersonId)) .AsNoTracking() .ToList(); foreach (var newMember in newMemberInList) { var communicationRecipient = new CommunicationRecipient { PersonAliasId = newMember.Person.PrimaryAliasId.Value, Status = CommunicationRecipientStatus.Pending, CommunicationId = Id }; switch (CommunicationType) { case CommunicationType.Email: communicationRecipient.MediumEntityTypeId = emailMediumEntityType.Id; break; case CommunicationType.SMS: communicationRecipient.MediumEntityTypeId = smsMediumEntityType.Id; break; case CommunicationType.RecipientPreference: newMember.LoadAttributes(); if (preferredCommunicationTypeAttribute != null) { var recipientPreference = ( CommunicationType? )newMember .GetAttributeValue(preferredCommunicationTypeAttribute.Key).AsIntegerOrNull(); switch (recipientPreference) { case CommunicationType.SMS: communicationRecipient.MediumEntityTypeId = smsMediumEntityType.Id; break; case CommunicationType.Email: communicationRecipient.MediumEntityTypeId = emailMediumEntityType.Id; break; default: communicationRecipient.MediumEntityTypeId = emailMediumEntityType.Id; break; } } break; default: throw new Exception("Unexpected CommunicationType: " + CommunicationType.ConvertToString()); } communicationRecipientService.Add(communicationRecipient); } // Get all pending communication recipents that are no longer part of the group list member, then delete them from the Recipients var missingMemberInList = recipientsQry.Where(a => a.Status == CommunicationRecipientStatus.Pending) .Where(a => !qryCommunicationListMembers.Any(r => r.PersonId == a.PersonAlias.PersonId)) .ToList(); foreach (var missingMember in missingMemberInList) { communicationRecipientService.Delete(missingMember); } rockContext.SaveChanges(); }
/// <summary> /// Gets financial transaction details based on selected filter values. /// </summary> /// <param name="start">The start.</param> /// <param name="end">The end.</param> /// <param name="minAmount">The minimum amount.</param> /// <param name="maxAmount">The maximum amount.</param> /// <param name="currencyTypeIds">The currency type ids.</param> /// <param name="sourceTypeIds">The source type ids.</param> /// <param name="accountIds">The account ids.</param> /// <param name="dataViewId">The data view identifier.</param> /// <returns></returns> public IQueryable <FinancialTransactionDetail> GetGifts( DateTime?start, DateTime?end, decimal?minAmount, decimal?maxAmount, List <int> currencyTypeIds, List <int> sourceTypeIds, List <int> accountIds, int?dataViewId) { // Base Transaction Detail query var qry = GetGifts(); // Start Date Filter if (start.HasValue) { qry = qry.Where(t => t.Transaction.TransactionDateTime >= start.Value); } // End Date Filter if (end.HasValue) { qry = qry.Where(t => t.Transaction.TransactionDateTime < end.Value); } // Account Id Filter var distictAccountIds = accountIds.Where(i => i != 0).Distinct().ToList(); if (distictAccountIds.Any()) { qry = qry .Where(t => distictAccountIds.Contains(t.AccountId)); } // Currency Type Filter var distictCurrencyTypeIds = currencyTypeIds.Where(i => i != 0).Distinct().ToList(); if (distictCurrencyTypeIds.Any()) { qry = qry .Where(t => t.Transaction.FinancialPaymentDetail != null && t.Transaction.FinancialPaymentDetail.CurrencyTypeValueId.HasValue && distictCurrencyTypeIds.Contains(t.Transaction.FinancialPaymentDetail.CurrencyTypeValueId.Value)); } // Source Type Filter var distictSourceTypeIds = sourceTypeIds.Where(i => i != 0).Distinct().ToList(); if (distictSourceTypeIds.Any()) { qry = qry .Where(t => t.Transaction.SourceTypeValueId.HasValue && distictSourceTypeIds.Contains(t.Transaction.SourceTypeValueId.Value)); } // Amount Range Filter if (minAmount.HasValue || maxAmount.HasValue) { var givingIdQry = qry .GroupBy(d => d.Transaction.AuthorizedPersonAlias.Person.GivingId) .Select(d => new { d.Key, Total = d.Sum(t => t.Amount) }) .Where(s => (!minAmount.HasValue || s.Total >= minAmount.Value) && (!maxAmount.HasValue || s.Total <= maxAmount.Value)) .Select(s => s.Key); // put all the givingIds into a List instead of a subquery to prevent a timeout issue var givingIdList = givingIdQry.ToList(); qry = qry .Where(d => givingIdList.Contains(d.Transaction.AuthorizedPersonAlias.Person.GivingId)); } // Data View Filter if (dataViewId.HasValue) { var rockContext = (RockContext)this.Context; if (rockContext != null) { var personService = new PersonService(rockContext); var dataView = new DataViewService(rockContext).Get(dataViewId.Value); if (dataView != null) { var errorMessages = new List <string>(); ParameterExpression paramExpression = personService.ParameterExpression; Expression whereExpression = dataView.GetExpression(personService, paramExpression, out errorMessages); SortProperty sortProperty = null; var dataViewGivingIdQry = personService .Queryable().AsNoTracking() .Where(paramExpression, whereExpression, sortProperty) .Select(p => p.GivingId); qry = qry .Where(t => dataViewGivingIdQry.Contains(t.Transaction.AuthorizedPersonAlias.Person.GivingId)); } } } return(qry); }