/// <summary> /// Binds the report grid. /// </summary> private void BindReportGrid() { var rockContext = new RockContext(); var reportService = new ReportService(rockContext); var reportGuid = this.GetAttributeValue("Report").AsGuidOrNull(); var personIdField = this.GetAttributeValue("PersonIdField"); Report report = null; if (reportGuid.HasValue) { report = reportService.Get(reportGuid.Value); } if (report == null) { nbConfigurationWarning.Visible = true; nbConfigurationWarning.Text = "A report needs to be configured in block settings"; pnlView.Visible = false; } else if (report.DataView == null) { nbConfigurationWarning.Visible = true; nbConfigurationWarning.Text = string.Format("The {0} report does not have a dataview", report); pnlView.Visible = false; } else { nbConfigurationWarning.Visible = false; string errorMessage; DataViewFilterOverrides dataViewFilterOverrides = ReportingHelper.GetFilterOverridesFromControls(phFilters); ReportingHelper.BindGrid(report, gReport, this.CurrentPerson, dataViewFilterOverrides, null, false, out errorMessage); if (report.EntityTypeId != EntityTypeCache.GetId <Rock.Model.Person>()) { var personColumn = gReport.ColumnsOfType <BoundField>().Where(a => a.HeaderText == personIdField).FirstOrDefault(); if (personColumn != null) { gReport.PersonIdField = personColumn.SortExpression; } } if (!string.IsNullOrWhiteSpace(errorMessage)) { nbReportErrors.NotificationBoxType = NotificationBoxType.Warning; nbReportErrors.Text = errorMessage; nbReportErrors.Visible = true; } else { nbReportErrors.Visible = false; } } }
/// <summary> /// Gets the expression with overrides. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="serviceInstance">The service instance.</param> /// <param name="parameterExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="selection">The selection.</param> /// <returns></returns> /// <exception cref="System.Exception">Filter issue(s): " + errorMessages.AsDelimited( "; " )</exception> public new Expression GetExpressionWithOverrides(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, DataViewFilterOverrides dataViewFilterOverrides, string selection) { // first get the 'IN other dataview expression' from the inherited from OtherDataViewFilter var baseExpression = base.GetExpressionWithOverrides(entityType, serviceInstance, parameterExpression, dataViewFilterOverrides, selection); if (baseExpression != null) { return(Expression.Not(baseExpression)); } else { return(baseExpression); } }
/// <summary> /// Gets the expression with overrides. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="serviceInstance">The service instance.</param> /// <param name="parameterExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="selection">A formatted string representing the filter settings: FieldName, <see cref="ComparisonType">Comparison Type</see>, (optional) Comparison Value(s)</param> /// <returns></returns> /// <exception cref="System.Exception">Filter issue(s): " + errorMessages.AsDelimited( "; " )</exception> public Expression GetExpressionWithOverrides(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, DataViewFilterOverrides dataViewFilterOverrides, string selection) { var selectionConfig = SelectionConfig.Parse(selection); var dataView = this.GetSelectedDataView(selectionConfig); if (dataView == null) { if (selectionConfig.DataViewId.HasValue && selectionConfig.DataViewId > 0) { // if there is DataViewId but it isn't in the database, the DataView might have been deleted. If so, this could return unexpected results. throw new RockDataViewFilterExpressionException($"DataViewFilter unable to determine DataView for DataViewId {selectionConfig.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 (DataViewService.IsViewInFilter(dataView, dataView.DataViewFilter)) { throw new System.Exception($"The {dataView.Name} data view references itself recursively within the {this.FormatSelection( entityType, selection ) } data filter."); } if (selectionConfig.UsePersisted == false) { dataViewFilterOverrides?.IgnoreDataViewPersistedValues.Add(dataView.Id); } Expression expression = dataView.GetExpression(serviceInstance, parameterExpression, dataViewFilterOverrides); return(expression); } return(null); }
/// <summary> /// Gets the expression with overrides. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="serviceInstance">The service instance.</param> /// <param name="parameterExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="selection">The selection.</param> /// <returns></returns> /// <exception cref="System.Exception">Filter issue(s): " + errorMessages.AsDelimited( "; " )</exception> public Expression GetExpressionWithOverrides(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, DataViewFilterOverrides dataViewFilterOverrides, string selection) { var dataView = this.GetSelectedDataView(selection); 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 its filters, // as that could be a moving target. var errorMessages = new List <string>(); Expression expression = dataView.GetExpression(serviceInstance, parameterExpression, dataViewFilterOverrides, out errorMessages); if (errorMessages.Any()) { throw new System.Exception("Filter issue(s): " + errorMessages.AsDelimited("; ")); } return(expression); } } return(null); }
/// <summary> /// Binds the report grid. /// </summary> private void BindReportGrid(bool isCommunication = false) { var rockContext = new RockContext(); var reportService = new ReportService(rockContext); var reportGuid = this.GetAttributeValue("Report").AsGuidOrNull(); var personIdField = this.GetAttributeValue("PersonIdField"); Report report = null; if (reportGuid.HasValue) { report = reportService.Get(reportGuid.Value); } if (report == null) { nbConfigurationWarning.Visible = true; nbConfigurationWarning.Text = "A report needs to be configured in block settings"; pnlView.Visible = false; } else if (report.DataView == null) { nbConfigurationWarning.Visible = true; nbConfigurationWarning.Text = string.Format("The {0} report does not have a dataview", report); pnlView.Visible = false; } else if (report.DataView.EntityTypeId != report.EntityTypeId) { nbConfigurationWarning.Visible = true; nbConfigurationWarning.Text = string.Format("The {0} report's EntityType doesn't match the dataview's EntityType", report); pnlView.Visible = false; } else { nbConfigurationWarning.Visible = false; DataViewFilterOverrides dataViewFilterOverrides = ReportingHelper.GetFilterOverridesFromControls(report.DataView, phFilters); ReportingHelper.BindGridOptions bindGridOptions = new ReportingHelper.BindGridOptions { CurrentPerson = this.CurrentPerson, DataViewFilterOverrides = dataViewFilterOverrides, DatabaseTimeoutSeconds = null, IsCommunication = isCommunication }; nbReportErrors.Visible = false; try { bindGridOptions.ReportDbContext = Reflection.GetDbContextForEntityType(EntityTypeCache.Get(report.EntityTypeId.Value).GetEntityType()); ReportingHelper.BindGrid(report, gReport, bindGridOptions); if (report.EntityTypeId != EntityTypeCache.GetId <Rock.Model.Person>()) { var personColumn = gReport.ColumnsOfType <BoundField>().Where(a => a.HeaderText == personIdField).FirstOrDefault(); if (personColumn != null) { gReport.PersonIdField = personColumn.SortExpression; } } } catch (Exception ex) { ExceptionLogService.LogException(ex); var sqlTimeoutException = ReportingHelper.FindSqlTimeoutException(ex); if (sqlTimeoutException != null) { nbReportErrors.NotificationBoxType = NotificationBoxType.Warning; nbReportErrors.Text = "This report did not complete in a timely manner."; } else { if (ex is RockDataViewFilterExpressionException) { RockDataViewFilterExpressionException rockDataViewFilterExpressionException = ex as RockDataViewFilterExpressionException; nbReportErrors.Text = rockDataViewFilterExpressionException.GetFriendlyMessage(report.DataView); } else { nbReportErrors.Text = "There was a problem with one of the filters for this report's dataview."; } nbReportErrors.NotificationBoxType = NotificationBoxType.Danger; nbReportErrors.Details = ex.Message; nbReportErrors.Visible = true; } } } }
/// <summary> /// Binds the grid. /// </summary> /// <param name="report">The report.</param> /// <param name="gReport">The g report.</param> /// <param name="currentPerson">The current person.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="databaseTimeoutSeconds">The database timeout seconds.</param> /// <param name="isCommunication">if set to <c>true</c> [is communication].</param> /// <param name="errorMessage">The error message.</param> public static void BindGrid(Report report, Grid gReport, Person currentPerson, DataViewFilterOverrides dataViewFilterOverrides, int?databaseTimeoutSeconds, bool isCommunication, out string errorMessage) { errorMessage = null; if (report != null) { var errors = new List <string>(); if (!report.EntityTypeId.HasValue) { gReport.Visible = false; return; } var rockContext = new RockContext(); if (!report.IsAuthorized(Authorization.VIEW, currentPerson)) { gReport.Visible = false; return; } Type entityType = EntityTypeCache.Get(report.EntityTypeId.Value, rockContext).GetEntityType(); if (entityType == null) { errorMessage = string.Format("Unable to determine entityType for {0}", report.EntityType); return; } gReport.EntityTypeId = report.EntityTypeId; bool isPersonDataSet = report.EntityTypeId == EntityTypeCache.Get(typeof(Rock.Model.Person), true, rockContext).Id; if (isPersonDataSet) { gReport.PersonIdField = "Id"; gReport.DataKeyNames = new string[] { "Id" }; } else { gReport.PersonIdField = null; } if (report.EntityTypeId.HasValue) { gReport.RowItemText = EntityTypeCache.Get(report.EntityTypeId.Value, rockContext).FriendlyName; } List <EntityField> entityFields = Rock.Reporting.EntityHelper.GetEntityFields(entityType, true, false); var selectedEntityFields = new Dictionary <int, EntityField>(); var selectedAttributes = new Dictionary <int, AttributeCache>(); var selectedComponents = new Dictionary <int, ReportField>(); // if there is a selectField, keep it to preserve which items are checked var selectField = gReport.Columns.OfType <SelectField>().FirstOrDefault(); gReport.Columns.Clear(); int columnIndex = 0; if (!string.IsNullOrWhiteSpace(gReport.PersonIdField)) { // if we already had a selectField, use it (to preserve checkbox state) gReport.Columns.Add(selectField ?? new SelectField()); columnIndex++; } var reportFieldSortExpressions = new Dictionary <Guid, string>(); gReport.CommunicateMergeFields = new List <string>(); gReport.CommunicationRecipientPersonIdFields = new List <string>(); foreach (var reportField in report.ReportFields.OrderBy(a => a.ColumnOrder)) { bool mergeField = reportField.IsCommunicationMergeField.HasValue && reportField.IsCommunicationMergeField.Value; bool recipientField = reportField.IsCommunicationRecipientField.HasValue && reportField.IsCommunicationRecipientField.Value; columnIndex++; if (reportField.ReportFieldType == ReportFieldType.Property) { var entityField = entityFields.FirstOrDefault(a => a.Name == reportField.Selection); if (entityField != null) { selectedEntityFields.Add(columnIndex, entityField); BoundField boundField = entityField.GetBoundFieldType(); boundField.DataField = string.Format("Entity_{0}_{1}", entityField.Name, columnIndex); boundField.HeaderText = string.IsNullOrWhiteSpace(reportField.ColumnHeaderText) ? entityField.Title : reportField.ColumnHeaderText; boundField.SortExpression = boundField.DataField; reportFieldSortExpressions.AddOrReplace(reportField.Guid, boundField.SortExpression); boundField.Visible = reportField.ShowInGrid; gReport.Columns.Add(boundField); if (mergeField) { gReport.CommunicateMergeFields.Add($"{boundField.DataField}|{boundField.HeaderText.RemoveSpecialCharacters()}"); } if (recipientField) { gReport.CommunicationRecipientPersonIdFields.Add(boundField.DataField); } } } else if (reportField.ReportFieldType == ReportFieldType.Attribute) { Guid?attributeGuid = reportField.Selection.AsGuidOrNull(); if (attributeGuid.HasValue) { var attribute = AttributeCache.Get(attributeGuid.Value, rockContext); if (attribute != null && attribute.IsActive) { selectedAttributes.Add(columnIndex, attribute); BoundField boundField; if (attribute.FieldType.Guid.Equals(Rock.SystemGuid.FieldType.BOOLEAN.AsGuid())) { boundField = new BoolField(); } else if (attribute.FieldType.Guid.Equals(Rock.SystemGuid.FieldType.DEFINED_VALUE.AsGuid())) { boundField = new DefinedValueField(); } else { boundField = new CallbackField(); boundField.HtmlEncode = false; (boundField as CallbackField).OnFormatDataValue += (sender, e) => { string resultHtml = null; if (e.DataValue != null) { bool condensed = true; resultHtml = attribute.FieldType.Field.FormatValueAsHtml(gReport, e.DataValue.ToString(), attribute.QualifierValues, condensed); } e.FormattedValue = resultHtml ?? string.Empty; }; } boundField.DataField = string.Format("Attribute_{0}_{1}", attribute.Id, columnIndex); boundField.HeaderText = string.IsNullOrWhiteSpace(reportField.ColumnHeaderText) ? attribute.Name : reportField.ColumnHeaderText; boundField.SortExpression = boundField.DataField; reportFieldSortExpressions.AddOrReplace(reportField.Guid, boundField.SortExpression); if (attribute.FieldType.Guid.Equals(Rock.SystemGuid.FieldType.INTEGER.AsGuid()) || attribute.FieldType.Guid.Equals(Rock.SystemGuid.FieldType.DATE.AsGuid()) || attribute.FieldType.Guid.Equals(Rock.SystemGuid.FieldType.FILTER_DATE.AsGuid())) { boundField.HeaderStyle.HorizontalAlign = HorizontalAlign.Right; boundField.ItemStyle.HorizontalAlign = HorizontalAlign.Right; } boundField.Visible = reportField.ShowInGrid; gReport.Columns.Add(boundField); if (mergeField) { gReport.CommunicateMergeFields.Add($"{boundField.DataField}|{boundField.HeaderText.RemoveSpecialCharacters()}"); } if (recipientField) { gReport.CommunicationRecipientPersonIdFields.Add(boundField.DataField); } } } } else if (reportField.ReportFieldType == ReportFieldType.DataSelectComponent) { selectedComponents.Add(columnIndex, reportField); DataSelectComponent selectComponent = DataSelectContainer.GetComponent(reportField.DataSelectComponentEntityType.Name); if (selectComponent != null) { try { DataControlField columnField = selectComponent.GetGridField(entityType, reportField.Selection ?? string.Empty); string fieldId = $"{selectComponent.ColumnPropertyName}_{columnIndex}"; if (columnField is BoundField) { (columnField as BoundField).DataField = $"Data_{fieldId}"; var customSortProperties = selectComponent.SortProperties(reportField.Selection ?? string.Empty); bool sortReversed = selectComponent.SortReversed(reportField.Selection ?? string.Empty); if (customSortProperties != null) { if (customSortProperties == string.Empty) { // disable sorting if customSortExpression set to string.empty columnField.SortExpression = string.Empty; } else { columnField.SortExpression = customSortProperties.Split(',').Select(a => string.Format("Sort_{0}_{1}", a, columnIndex)).ToList().AsDelimited(","); } } else { // use default sorting if customSortExpression was null columnField.SortExpression = (columnField as BoundField).DataField; } if (sortReversed == true && !string.IsNullOrWhiteSpace(columnField.SortExpression)) { columnField.SortExpression = columnField.SortExpression + " DESC"; } } columnField.HeaderText = string.IsNullOrWhiteSpace(reportField.ColumnHeaderText) ? selectComponent.ColumnHeaderText : reportField.ColumnHeaderText; if (!string.IsNullOrEmpty(columnField.SortExpression)) { reportFieldSortExpressions.AddOrReplace(reportField.Guid, columnField.SortExpression); } columnField.Visible = reportField.ShowInGrid; gReport.Columns.Add(columnField); if (mergeField) { gReport.CommunicateMergeFields.Add($"Data_{fieldId}|{columnField.HeaderText.RemoveSpecialCharacters()}"); } if (recipientField) { string fieldName = (selectComponent is IRecipientDataSelect) ? $"Recipient_{fieldId}" : $"Data_{fieldId}"; gReport.CommunicationRecipientPersonIdFields.Add(fieldName); } } catch (Exception ex) { ExceptionLogService.LogException(ex, HttpContext.Current); errors.Add(string.Format("{0} - {1}", selectComponent, ex.Message)); } } } } // if no fields are specified, show the default fields (Previewable/All) for the EntityType var dataColumns = gReport.Columns.OfType <object>().Where(a => a.GetType() != typeof(SelectField)); if (dataColumns.Count() == 0) { // show either the Previewable Columns or all (if there are no previewable columns) bool showAllColumns = !entityFields.Any(a => a.FieldKind == FieldKind.Property && a.IsPreviewable); foreach (var entityField in entityFields.Where(a => a.FieldKind == FieldKind.Property)) { columnIndex++; selectedEntityFields.Add(columnIndex, entityField); BoundField boundField = entityField.GetBoundFieldType(); boundField.DataField = string.Format("Entity_{0}_{1}", entityField.Name, columnIndex); boundField.HeaderText = entityField.Name; boundField.SortExpression = boundField.DataField; boundField.Visible = showAllColumns || entityField.IsPreviewable; gReport.Columns.Add(boundField); } } try { gReport.Visible = true; gReport.ExportFilename = report.Name; SortProperty sortProperty = gReport.SortProperty; if (sortProperty == null) { var reportSort = new SortProperty(); var sortColumns = new Dictionary <string, SortDirection>(); foreach (var reportField in report.ReportFields.Where(a => a.SortOrder.HasValue).OrderBy(a => a.SortOrder.Value)) { if (reportFieldSortExpressions.ContainsKey(reportField.Guid)) { var sortField = reportFieldSortExpressions[reportField.Guid]; if (!string.IsNullOrWhiteSpace(sortField)) { sortColumns.Add(sortField, reportField.SortDirection); } } } if (sortColumns.Any()) { reportSort.Property = sortColumns.Select(a => a.Key + (a.Value == SortDirection.Descending ? " desc" : string.Empty)).ToList().AsDelimited(","); sortProperty = reportSort; } } var qryErrors = new List <string>(); System.Data.Entity.DbContext reportDbContext; dynamic qry = report.GetQueryable(entityType, selectedEntityFields, selectedAttributes, selectedComponents, sortProperty, dataViewFilterOverrides, databaseTimeoutSeconds ?? 180, isCommunication, out qryErrors, out reportDbContext); errors.AddRange(qryErrors); if (!string.IsNullOrEmpty(report.QueryHint) && reportDbContext is RockContext) { using (new QueryHintScope(reportDbContext as RockContext, report.QueryHint)) { gReport.SetLinqDataSource(qry); } } else { gReport.SetLinqDataSource(qry); } gReport.DataBind(); } catch (Exception ex) { Exception exception = ex; ExceptionLogService.LogException(ex, HttpContext.Current); while (exception != null) { if (exception is System.Data.SqlClient.SqlException) { // if there was a SQL Server Timeout, have the warning be a friendly message about that. if ((exception as System.Data.SqlClient.SqlException).Number == -2) { errorMessage = "This report did not complete in a timely manner. You can try again or adjust the timeout setting of this block."; return; } else { errors.Add(exception.Message); exception = exception.InnerException; } } else { errors.Add(exception.Message); exception = exception.InnerException; } } } if (errors.Any()) { errorMessage = "WARNING: There was a problem with one or more of the report's data components...<br/><br/> " + errors.AsDelimited("<br/>"); } } }
/// <summary> /// Gets the expression with overrides. /// </summary> /// <param name="entityType">Type of the entity.</param> /// <param name="serviceInstance">The service instance.</param> /// <param name="parameterExpression">The parameter expression.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="selection">A formatted string representing the filter settings: FieldName, <see cref="ComparisonType">Comparison Type</see>, (optional) Comparison Value(s)</param> /// <returns></returns> /// <exception cref="System.Exception">Filter issue(s): " + errorMessages.AsDelimited( "; " )</exception> public Expression GetExpressionWithOverrides(Type entityType, IService serviceInstance, ParameterExpression parameterExpression, DataViewFilterOverrides dataViewFilterOverrides, string selection) { var selectionConfig = SelectionConfig.Parse(selection); var dataView = this.GetSelectedDataView(selectionConfig); 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)) { throw new System.Exception($"The {dataView.Name} data view references itself recursively within the {this.FormatSelection( entityType, selection ) } data filter."); } var errorMessages = new List <string>(); if (selectionConfig.UsePersisted == false) { dataViewFilterOverrides?.IgnoreDataViewPersistedValues.Add(dataView.Id); } Expression expression = dataView.GetExpression(serviceInstance, parameterExpression, dataViewFilterOverrides, out errorMessages); if (errorMessages.Any()) { throw new System.Exception("Filter issue(s): " + errorMessages.AsDelimited("; ")); } return(expression); } return(null); }
public static void BindGrid(Report report, Grid gReport, Person currentPerson, DataViewFilterOverrides dataViewFilterOverrides, int?databaseTimeoutSeconds, bool isCommunication, out string errorMessage) { errorMessage = string.Empty; BindGridOptions bindGridOptions = new BindGridOptions { CurrentPerson = currentPerson, DataViewFilterOverrides = dataViewFilterOverrides, DatabaseTimeoutSeconds = databaseTimeoutSeconds, IsCommunication = isCommunication }; BindGrid(report, gReport, bindGridOptions); }