/// <summary> /// Job that updates the JobPulse setting with the current date/time. /// This will allow us to notify an admin if the jobs stop running. /// /// 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) { // get the job map JobDataMap dataMap = context.JobDetail.JobDataMap; // delete accounts that have not been confirmed in X hours int userExpireHours = Int32.Parse( dataMap.GetString( "HoursKeepUnconfirmedAccounts" ) ); DateTime userAccountExpireDate = DateTime.Now.Add( new TimeSpan( userExpireHours * -1,0,0 ) ); UserService userService = new UserService(); foreach (var user in userService.Queryable().Where(u => u.IsConfirmed == false && u.CreationDate < userAccountExpireDate)) { userService.Delete( user, null ); } userService.Save( null, null ); // purge exception log int exceptionExpireDays = Int32.Parse( dataMap.GetString( "DaysKeepExceptions" ) ); DateTime exceptionExpireDate = DateTime.Now.Add( new TimeSpan( userExpireHours * -1, 0, 0 ) ); ExceptionLogService exceptionLogService = new ExceptionLogService(); foreach ( var exception in exceptionLogService.Queryable().Where( e => e.ExceptionDate < exceptionExpireDate ) ) { exceptionLogService.Delete( exception, null ); } exceptionLogService.Save( null, null ); }
/// <summary> /// Shows the detail of the exception /// </summary> /// <param name="exceptionId">The exception identifier.</param> public void ShowDetail( int exceptionId ) { ExceptionLog baseException = null; if ( exceptionId != 0 ) { baseException = new ExceptionLogService( new RockContext() ).Get( exceptionId ); } //set fields if ( baseException == null ) { pnlSummary.Visible = false; return; } // set page title lPageTitle.Text = String.Format("Exception Overview").FormatAsHtmlTitle(); DescriptionList dl = new DescriptionList(); dl.Add( "Site", baseException.Site != null ? baseException.Site.Name : String.Empty, true ); if ( baseException.Page != null || !string.IsNullOrWhiteSpace(baseException.PageUrl) ) { dl.Add( "Page", string.Format( "{0} <a href=\"{1}\" class=\"btn btn-link btn-xs\" target=\"_blank\">Visit Page</a>", baseException.Page != null ? baseException.Page.InternalName : baseException.PageUrl.EncodeHtml(), baseException.PageUrl.EncodeHtml() ) ); } //If query string is not empty build query string list if ( !String.IsNullOrWhiteSpace( baseException.QueryString ) ) { dl.Add( "Query String", BuildQueryStringList( baseException.QueryString.EncodeHtml() ) ); } if (baseException.CreatedByPersonAlias != null && baseException.CreatedByPersonAlias.Person != null) { dl.Add( "User", baseException.CreatedByPersonAlias.Person.FullName ); } if ( baseException.CreatedDateTime.HasValue ) { dl.Add( "Exception Date", string.Format( "{0:g}", baseException.CreatedDateTime.Value ) ); } lExceptionSummary.Text = dl.Html; lCookies.Text = baseException.Cookies; lServerVariables.Text = baseException.ServerVariables; lFormData.Text = baseException.Form; btnShowCookies.Visible = !string.IsNullOrWhiteSpace( baseException.Cookies ); btnShowVariables.Visible = !string.IsNullOrWhiteSpace( baseException.ServerVariables ); btnShowFormData.Visible = !string.IsNullOrWhiteSpace( baseException.Form ); rptExcpetionDetails.DataSource = GetExceptionLogs( baseException ).OrderBy( e => e.Id ); rptExcpetionDetails.DataBind(); pnlSummary.Visible = true; }
/// <summary> /// Handles the GridRebind event of the gExceptionOccurrences 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 gExceptionOccurrences_GridRebind( object sender, EventArgs e ) { int exceptionID = 0; if ( int.TryParse( hfBaseExceptionID.Value, out exceptionID ) ) { ExceptionLogService exceptionService = new ExceptionLogService( new RockContext() ); ExceptionLog baseException = exceptionService.Get( exceptionID ); BindExceptionOccurrenceGrid( baseException ); } }
/// <summary> /// Loads the control. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); if ( !Page.IsPostBack ) { //Set Exception Panel visibility to show Exception List SetExceptionPanelVisibility( None.Id ); } // get data for graphs ExceptionLogService exceptionLogService = new ExceptionLogService( new RockContext() ); var exceptionList = exceptionLogService.Queryable() .Where(x => x.HasInnerException == false && x.CreatedDateTime != null) .GroupBy( x => DbFunctions.TruncateTime(x.CreatedDateTime.Value )) .Select( eg => new { DateValue = eg.Key, ExceptionCount = eg.Count(), UniqueExceptionCount = eg.Select( y => y.ExceptionType ).Distinct().Count() } ).OrderBy(eg => eg.DateValue).ToList(); if ( exceptionList.Count > 1 ) { StringBuilder sbChartData = new StringBuilder(); //sbChartData.Append( "[['Date', 'Unique Exceptions', 'Total Exceptions']," ); sbChartData.Append( "data.addColumn('date', 'Date');\n" ); sbChartData.Append( "data.addColumn('number', 'Unique Exceptions');\n" ); sbChartData.Append( "data.addColumn('number', 'Total Exceptions');\n" ); // load datatable foreach ( var exception in exceptionList ) { //sbChartData.Append( String.Format( "['{0}', {1}, {2}],", exception.DateValue.Value.ToShortDateString(), exception.UniqueExceptionCount, exception.ExceptionCount ) ); sbChartData.Append( String.Format( "data.addRow([new Date({0}, {1}, {2}), {3}, {4}]);\n", exception.DateValue.Value.Year, (exception.DateValue.Value.Month - 1), exception.DateValue.Value.Day, exception.UniqueExceptionCount, exception.ExceptionCount ) ); } lGraphScript.Text = String.Format( @" <script type=""text/javascript""> google.load(""visualization"", ""1"", {{ packages: [""corechart""] }}); google.setOnLoadCallback(drawChart); function drawChart() {{ var data = new google.visualization.DataTable(); {0} var options = {{ vAxis: {{ title: 'Exception Count', minValue: 0, titleTextStyle: {{ color: '#515151', italic: 'false' }} }}, backgroundColor: 'transparent', colors: ['#8498ab', '#a4b4c4', '#b9c7d5', '#c6d2df', '#d8e1ea'], hAxis: {{ textStyle: {{ color: '#515151' }}, baselineColor: '#515151' }}, legend: {{ position: 'bottom', textStyle: {{ color: '#515151' }} }} }}; var chart = new google.visualization.AreaChart(document.getElementById('exception-chart')); chart.draw(data, options); $(window).smartresize(function(){{ chart.draw(data, options); }}); }} </script>", sbChartData.ToString() ); } else { pnlExceptionChart.Visible = false; } }
/// <summary> /// Loads the control. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); if ( !Page.IsPostBack ) { //Set Exception Panel visibility to show Exception List SetExceptionPanelVisibility( None.Id ); } lcExceptions.Options.SetChartStyle( this.ChartStyle ); lcExceptions.Options.legend = lcExceptions.Options.legend ?? new Legend(); lcExceptions.Options.legend.show = this.GetAttributeValue( "ShowLegend" ).AsBooleanOrNull(); lcExceptions.Options.legend.position = this.GetAttributeValue( "LegendPosition" ); bcExceptions.Options.SetChartStyle( this.ChartStyle ); bcExceptions.Options.legend = bcExceptions.Options.legend ?? new Legend(); bcExceptions.Options.legend.show = this.GetAttributeValue( "ShowLegend" ).AsBooleanOrNull(); bcExceptions.Options.legend.position = this.GetAttributeValue( "LegendPosition" ); bcExceptions.Options.xaxis = new AxisOptions { mode = AxisMode.categories, tickLength = 0 }; bcExceptions.Options.series.bars.barWidth = 0.6; bcExceptions.Options.series.bars.align = "center"; bcExceptions.TooltipFormatter = @" function(item) { var itemDate = new Date(item.series.chartData[item.dataIndex].DateTimeStamp); var dateText = itemDate.toLocaleDateString(); var seriesLabel = item.series.label || ( item.series.labels ? item.series.labels[item.dataIndex] : null ); var pointValue = item.series.chartData[item.dataIndex].YValue || item.series.chartData[item.dataIndex].YValueTotal || '-'; return dateText + '<br />' + seriesLabel + ': ' + pointValue; } "; // get data for graphs ExceptionLogService exceptionLogService = new ExceptionLogService( new RockContext() ); var exceptionListCount = exceptionLogService.Queryable() .Where( x => x.HasInnerException == false && x.CreatedDateTime != null ) .GroupBy( x => DbFunctions.TruncateTime( x.CreatedDateTime.Value ) ) .Count(); if ( exceptionListCount == 1 ) { // if there is only one x datapoint for the Chart, show it as a barchart lcExceptions.Visible = false; bcExceptions.Visible = true; } else { lcExceptions.Visible = true; bcExceptions.Visible = false; } }
/// <summary> /// Logs the error. /// </summary> /// <param name="ex">The ex.</param> /// <param name="parentException">The parent exception.</param> /// <param name="status">The status.</param> /// <param name="context">The context.</param> private void LogError( Exception ex, int parentException, string status, System.Web.HttpContext context ) { try { // get the current user Rock.Model.UserLogin user = Rock.Model.UserService.GetCurrentUser(); // save the exception info to the db ExceptionLogService service = new ExceptionLogService(); ExceptionLog exceptionLog = new ExceptionLog(); ; exceptionLog.ParentId = parentException; exceptionLog.ExceptionDate = DateTime.Now; if ( ex.InnerException != null ) exceptionLog.HasInnerException = true; exceptionLog.Description = ex.Message; exceptionLog.StackTrace = ex.StackTrace; exceptionLog.Source = ex.Source; exceptionLog.StatusCode = status; if ( context.Items["Rock:SiteId"] != null ) exceptionLog.SiteId = Int32.Parse( context.Items["Rock:SiteId"].ToString() ); if ( context.Items["Rock:PageId"] != null ) exceptionLog.PageId = Int32.Parse( context.Items["Rock:PageId"].ToString() ); exceptionLog.ExceptionType = ex.GetType().Name; exceptionLog.PageUrl = context.Request.RawUrl; exceptionLog.QueryString = context.Request.QueryString.ToString(); // write cookies StringBuilder cookies = new StringBuilder(); cookies.Append( "<table class=\"cookies\">" ); foreach ( string cookie in context.Request.Cookies ) cookies.Append( "<tr><td><b>" + cookie + "</b></td><td>" + context.Request.Cookies[cookie].Value + "</td></tr>" ); cookies.Append( "</table>" ); exceptionLog.Cookies = cookies.ToString(); // write form items StringBuilder formItems = new StringBuilder(); cookies.Append( "<table class=\"formItems\">" ); foreach ( string formItem in context.Request.Form ) cookies.Append( "<tr><td><b>" + formItem + "</b></td><td>" + context.Request.Form[formItem].ToString() + "</td></tr>" ); cookies.Append( "</table>" ); exceptionLog.Form = formItems.ToString(); // write server vars StringBuilder serverVars = new StringBuilder(); cookies.Append( "<table class=\"server-variables\">" ); foreach ( string serverVar in context.Request.ServerVariables ) serverVars.Append( "<tr><td><b>" + serverVar + "</b></td><td>" + context.Request.ServerVariables[serverVar].ToString() + "</td></tr>" ); cookies.Append( "</table>" ); exceptionLog.ServerVariables = serverVars.ToString(); if ( user != null ) exceptionLog.CreatedByPersonId = user.PersonId; service.Add( exceptionLog, null ); service.Save( exceptionLog, null ); // log inner exceptions if ( ex.InnerException != null ) LogError( ex.InnerException, exceptionLog.Id, status, context ); } catch ( Exception ) { // if you get an exception while logging an exception I guess you're hosed... try { EventLog.WriteEntry( "Rock", string.Format( "Exception in Global.LogError(): {0}", ex.Message ), EventLogEntryType.Error ); } catch { } } }
/// <summary> /// Called before the save operation is executed. /// </summary> protected override void PreSave() { HistoryChanges = new History.HistoryChangeList(); switch (State) { case EntityContextState.Added: { // Get the authentication provider entity type var entityType = EntityTypeCache.Get(Entity.EntityTypeId ?? 0); var change = HistoryChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Authentication Provider").SetNewValue(entityType?.FriendlyName); // Don't log Pin Authentication user names. var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false; if (isUserNameSensitive) { change.SetCaption("User Account"); } History.EvaluateChange(HistoryChanges, "User Login", string.Empty, Entity.UserName, isUserNameSensitive); History.EvaluateChange(HistoryChanges, "Is Confirmed", null, Entity.IsConfirmed); History.EvaluateChange(HistoryChanges, "Is Password Change Required", null, Entity.IsPasswordChangeRequired); History.EvaluateChange(HistoryChanges, "Is Locked Out", null, Entity.IsLockedOut); break; } case EntityContextState.Modified: { var entityType = EntityTypeCache.Get(Entity.EntityTypeId ?? 0); // Don't log Pin Authentication user names. var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false; History.EvaluateChange(HistoryChanges, "User Login", OriginalValues[nameof(UserLogin.UserName)].ToStringSafe(), Entity.UserName, isUserNameSensitive); History.EvaluateChange(HistoryChanges, "Is Confirmed", OriginalValues[nameof(UserLogin.IsConfirmed)].ToStringSafe().AsBooleanOrNull(), Entity.IsConfirmed); History.EvaluateChange(HistoryChanges, "Is Password Change Required", OriginalValues[nameof(UserLogin.IsPasswordChangeRequired)].ToStringSafe().AsBooleanOrNull(), Entity.IsPasswordChangeRequired); History.EvaluateChange(HistoryChanges, "Is Locked Out", OriginalValues[nameof(UserLogin.IsLockedOut)].ToStringSafe().AsBooleanOrNull(), Entity.IsLockedOut); History.EvaluateChange(HistoryChanges, "Password", OriginalValues[nameof(UserLogin.Password)].ToStringSafe(), Entity.Password, true); // Did the provider type change? int?origEntityTypeId = OriginalValues[nameof(UserLogin.EntityTypeId)].ToStringSafe().AsIntegerOrNull(); int?entityTypeId = Entity.EntityType != null ? Entity.EntityType.Id : Entity.EntityTypeId; if (!entityTypeId.Equals(origEntityTypeId)) { var origProviderType = EntityTypeCache.Get(origEntityTypeId ?? 0)?.FriendlyName; var providerType = EntityTypeCache.Get(Entity.EntityTypeId ?? 0)?.FriendlyName; History.EvaluateChange(HistoryChanges, "User Login", origProviderType, providerType); } // Change the caption if this is a sensitive user account if (HistoryChanges.Count > 0 && isUserNameSensitive) { var change = HistoryChanges.FirstOrDefault(); change.SetCaption("User Account"); } break; } case EntityContextState.Deleted: { // By this point EF has stripped out some of the data we need to save history // Reload the data using a new context. RockContext newRockContext = new RockContext(); var userLogin = new UserLoginService(newRockContext).Get(Entity.Id); if (userLogin != null && userLogin.PersonId != null) { try { var entityType = EntityTypeCache.Get(userLogin.EntityTypeId ?? 0); var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false; if (!isUserNameSensitive) { HistoryChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "User Login").SetOldValue(userLogin.UserName); HistoryService.SaveChanges(newRockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), userLogin.PersonId.Value, HistoryChanges, Entity.UserName, typeof(UserLogin), Entity.Id, true, userLogin.ModifiedByPersonAliasId, null); } else { HistoryChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Authentication Provider").SetOldValue(entityType?.FriendlyName).SetCaption("User Account"); HistoryService.SaveChanges(newRockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), userLogin.PersonId.Value, HistoryChanges, entityType?.FriendlyName, typeof(UserLogin), Entity.Id, true, userLogin.ModifiedByPersonAliasId, null); } } catch (Exception ex) { // Just log the problem and move on... ExceptionLogService.LogException(ex); } } HistoryChanges.Clear(); return; } } base.PreSave(); }
/// <summary> /// Gets the related exception logs /// </summary> /// <param name="baseException">The base exception.</param> /// <returns>List of Exception Detail Summary objects</returns> private List<ExceptionLog> GetExceptionLogs( ExceptionLog baseException ) { List<ExceptionLog> exceptionList = new List<ExceptionLog>(); ExceptionLogService svc = new ExceptionLogService( new RockContext() ); //load the base exception exceptionList.Add( baseException ); //get the parentID int? parentId = baseException.ParentId; //loop through exception hierarchy (parent, grandparent, etc) while ( parentId != null && parentId > 0 ) { var exception = svc.Get( (int)parentId ); if ( exception != null ) { exceptionList.Add( exception ); } parentId = exception.ParentId; } //get inner exceptions if ( baseException.HasInnerException != null && (bool)baseException.HasInnerException ) { exceptionList.AddRange( svc.GetByParentId( baseException.Id ) ); } return exceptionList; }
/// <summary> /// Schedules the Job to run immediately using the Quartz Scheduler /// and waits for the job to finish. /// Returns <c>false</c> with an <c>out</c> <paramref name="errorMessage"/> if the job is already running as a RunNow job or if an exception occurs. /// NOTE: This will take at least 10 seconds to ensure the Quartz scheduler successfully started the job, plus any additional time that might /// still be needed to complete the job. /// </summary> /// <param name="job">The job.</param> /// <param name="errorMessage">The error message.</param> /// <returns></returns> public bool RunNow(ServiceJob job, out string errorMessage) { // use a new RockContext instead of using this.Context so we can SaveChanges without affecting other RockContext's with pending changes. var rockContext = new RockContext(); errorMessage = string.Empty; try { // create a scheduler specific for the job var scheduleConfig = new NameValueCollection(); var jobId = job.Id; var runNowSchedulerName = ("RunNow:" + job.Guid.ToString("N")).Truncate(40); scheduleConfig.Add(StdSchedulerFactory.PropertySchedulerInstanceName, runNowSchedulerName); var schedulerFactory = new StdSchedulerFactory(scheduleConfig); var sched = new StdSchedulerFactory(scheduleConfig).GetScheduler(); if (sched.IsStarted) { // the job is currently running as a RunNow job errorMessage = "Job already running as a RunNow job"; return(false); } // Check if another scheduler is running this job try { var otherSchedulers = new StdSchedulerFactory() .AllSchedulers .Where(s => s.SchedulerName != runNowSchedulerName); foreach (var scheduler in otherSchedulers) { var isAlreadyRunning = scheduler.GetCurrentlyExecutingJobs() .Where(j => j.JobDetail.Description == jobId.ToString() && j.JobDetail.ConcurrentExectionDisallowed) .Any(); if (isAlreadyRunning) { // A job with that Id is already running and ConcurrentExectionDisallowed is true errorMessage = $" Scheduler '{scheduler.SchedulerName}' is already executing job Id '{jobId}' (name: {job.Name})"; System.Diagnostics.Debug.WriteLine($"{RockDateTime.Now.ToString()} {errorMessage}"); return(false); } } } catch { // Was blank in the RunJobNowTransaction (intentional?) } // create the quartz job and trigger var jobDetail = new ServiceJobService(rockContext).BuildQuartzJob(job); var jobDataMap = jobDetail.JobDataMap; if (jobDataMap != null) { // Force the <string, string> dictionary so that within Jobs, it is always okay to use // JobDataMap.GetString(). This mimics Rock attributes always being stored as strings. // If we allow non-strings, like integers, then JobDataMap.GetString() throws an exception. jobDetail.JobDataMap.PutAll(jobDataMap.ToDictionary(kvp => kvp.Key, kvp => ( object )kvp.Value)); } var jobTrigger = TriggerBuilder.Create() .WithIdentity(job.Guid.ToString(), job.Name) .StartNow() .Build(); // schedule the job sched.ScheduleJob(jobDetail, jobTrigger); // set up the listener to report back from the job when it completes sched.ListenerManager.AddJobListener(new RockJobListener(), EverythingMatcher <JobKey> .AllJobs()); // start the scheduler sched.Start(); // Wait 10secs to give scheduler to start the job. // If we don't do this, the scheduler might Shutdown thinking there are no running jobs Task.Delay(10 * 1000).Wait(); // stop the scheduler when done with job sched.Shutdown(true); return(true); } catch (Exception ex) { // create a friendly error message ExceptionLogService.LogException(ex, null); errorMessage = string.Format("Error doing a 'Run Now' on job: {0}. \n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = errorMessage; job.LastStatus = "Error Loading Job"; rockContext.SaveChanges(); var jobHistoryService = new ServiceJobHistoryService(rockContext); var jobHistory = new ServiceJobHistory { ServiceJobId = job.Id, StartDateTime = RockDateTime.Now, StopDateTime = RockDateTime.Now, Status = job.LastStatus, StatusMessage = job.LastStatusMessage }; jobHistoryService.Add(jobHistory); rockContext.SaveChanges(); return(false); } }
/// <summary> /// Gets the Linq expression for the DataViewFilter. /// </summary> /// <param name="filteredEntityType">The object type of the filtered entity.</param> /// <param name="serviceInstance">A <see cref="System.Object"/> that contains the service reference.</param> /// <param name="parameter">A <see cref="System.Linq.Expressions.ParameterExpression"/> containing the parameter for the expression.</param> /// <param name="errorMessages">A <see cref="System.Collections.Generic.List{String}"/> that contains any error/exception messages that are returned.</param> /// <returns></returns> public virtual Expression GetExpression(Type filteredEntityType, IService serviceInstance, ParameterExpression parameter, List <string> errorMessages) { switch (ExpressionType) { case FilterExpressionType.Filter: if (this.EntityTypeId.HasValue) { var entityType = Rock.Web.Cache.EntityTypeCache.Read(this.EntityTypeId.Value); if (entityType != null) { var component = Rock.Reporting.DataFilterContainer.GetComponent(entityType.Name); if (component != null) { try { return(component.GetExpression(filteredEntityType, serviceInstance, parameter, this.Selection)); } catch (SystemException ex) { ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); errorMessages.Add(string.Format("{0}: {1}", component.FormatSelection(filteredEntityType, this.Selection), ex.Message)); } } } } return(null); case FilterExpressionType.GroupAll: case FilterExpressionType.GroupAnyFalse: Expression andExp = null; foreach (var filter in this.ChildFilters) { Expression exp = filter.GetExpression(filteredEntityType, serviceInstance, parameter, errorMessages); if (exp != null) { if (andExp == null) { andExp = exp; } else { andExp = Expression.AndAlso(andExp, exp); } } } if (ExpressionType == FilterExpressionType.GroupAnyFalse && andExp != null) { // If only one of the conditions must be false, invert the expression so that it becomes the logical equivalent of "NOT ALL". andExp = Expression.Not(andExp); } return(andExp); case FilterExpressionType.GroupAny: case FilterExpressionType.GroupAllFalse: Expression orExp = null; foreach (var filter in this.ChildFilters) { Expression exp = filter.GetExpression(filteredEntityType, serviceInstance, parameter, errorMessages); if (exp != null) { if (orExp == null) { orExp = exp; } else { orExp = Expression.OrElse(orExp, exp); } } } if (ExpressionType == FilterExpressionType.GroupAllFalse && orExp != null) { // If all of the conditions must be false, invert the expression so that it becomes the logical equivalent of "NOT ANY". orExp = Expression.Not(orExp); } return(orExp); } return(null); }
/// <summary> /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); if ( !Page.IsPostBack ) { //show the detail int? exceptionId = PageParameter( "ExceptionId" ).AsIntegerOrNull(); if (!exceptionId.HasValue) { Guid? exceptionGuid = PageParameter( "ExceptionGuid" ).AsGuidOrNull(); if (exceptionGuid.HasValue) { exceptionId = new ExceptionLogService( new RockContext() ).Queryable().Where( a => a.Guid == exceptionGuid.Value ).Select( a => a.Id ).FirstOrDefault(); } } ShowDetail( exceptionId ?? 0 ); } }
/// <summary> /// Job that executes routine Rock cleanup tasks /// /// 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) { // get the job map JobDataMap dataMap = context.JobDetail.JobDataMap; // delete accounts that have not been confirmed in X hours int userExpireHours = Int32.Parse( dataMap.GetString( "HoursKeepUnconfirmedAccounts" ) ); DateTime userAccountExpireDate = DateTime.Now.Add( new TimeSpan( userExpireHours * -1,0,0 ) ); var userLoginService = new UserLoginService(); foreach (var user in userLoginService.Queryable().Where(u => u.IsConfirmed == false && u.CreationDateTime < userAccountExpireDate).ToList() ) { userLoginService.Delete( user, null ); userLoginService.Save( user, null ); } // purge exception log int exceptionExpireDays = Int32.Parse( dataMap.GetString( "DaysKeepExceptions" ) ); DateTime exceptionExpireDate = DateTime.Now.Add( new TimeSpan( exceptionExpireDays * -1, 0, 0, 0 ) ); ExceptionLogService exceptionLogService = new ExceptionLogService(); foreach ( var exception in exceptionLogService.Queryable().Where( e => e.ExceptionDateTime < exceptionExpireDate ).ToList() ) { exceptionLogService.Delete( exception, null ); exceptionLogService.Save( exception, null ); } // purge audit log int auditExpireDays = Int32.Parse( dataMap.GetString( "AuditLogExpirationDays" ) ); DateTime auditExpireDate = DateTime.Now.Add( new TimeSpan( auditExpireDays * -1, 0, 0, 0 ) ); AuditService auditService = new AuditService(); foreach( var audit in auditService.Queryable().Where( a => a.DateTime < auditExpireDate ).ToList() ) { auditService.Delete( audit, null ); auditService.Save( audit, null ); } // clean the cached file directory //get the attributes string cacheDirectoryPath = dataMap.GetString( "BaseCacheDirectory" ); int cacheExpirationDays = int.Parse( dataMap.GetString( "DaysKeepCachedFiles" ) ); DateTime cacheExpirationDate = DateTime.Now.Add( new TimeSpan( cacheExpirationDays * -1, 0, 0, 0 ) ); //if job is being run by the IIS scheduler and path is not null if ( context.Scheduler.SchedulerName == "RockSchedulerIIS" && !String.IsNullOrEmpty( cacheDirectoryPath ) ) { //get the physical path of the cache directory cacheDirectoryPath = System.Web.Hosting.HostingEnvironment.MapPath( cacheDirectoryPath ); } //if directory is not blank and cache expiration date not in the future if ( !String.IsNullOrEmpty( cacheDirectoryPath ) && cacheExpirationDate <= DateTime.Now ) { //Clean cache directory CleanCacheDirectory( cacheDirectoryPath, cacheExpirationDate ); } // clean out any temporary binary files BinaryFileService binaryFileService = new BinaryFileService(); foreach( var binaryFile in binaryFileService.Queryable().Where( bf => bf.IsTemporary == true ).ToList() ) { if ( binaryFile.LastModifiedDateTime < DateTime.Now.AddDays(-1) ) { binaryFileService.Delete( binaryFile, null ); binaryFileService.Save( binaryFile, null ); } } }
/// <summary> /// Returns a list of each person and their GroupRequiremnt status for this group requirement /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="personQry">The person qry.</param> /// <param name="groupId">The group identifier.</param> /// <param name="groupRoleId">The group role identifier.</param> /// <returns></returns> /// <exception cref="System.Exception">No dataview assigned to Group Requirement Type: " + this.GroupRequirementType.Name</exception> public IEnumerable <PersonGroupRequirementStatus> PersonQueryableMeetsGroupRequirement(RockContext rockContext, IQueryable <Person> personQry, int groupId, int?groupRoleId) { if ((this.GroupRoleId != null) && (groupRoleId != null) && (this.GroupRoleId != groupRoleId)) { // if this GroupRequirement is for a specific role, the groupRole we are checking for is something different var result = personQry.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a.Id, GroupRequirement = this, MeetsGroupRequirement = MeetsGroupRequirement.NotApplicable }); return(result); } if (this.GroupRequirementType.RequirementCheckType == RequirementCheckType.Dataview) { if (this.GroupRequirementType.DataViewId.HasValue) { var errorMessages = new List <string>(); var personService = new PersonService(rockContext); var paramExpression = personService.ParameterExpression; var dataViewWhereExpression = this.GroupRequirementType.DataView.GetExpression(personService, paramExpression, out errorMessages); var dataViewQry = personService.Get(paramExpression, dataViewWhereExpression); IQueryable <Person> warningDataViewQry = null; if (this.GroupRequirementType.WarningDataViewId.HasValue) { var warningDataViewWhereExpression = this.GroupRequirementType.WarningDataView.GetExpression(personService, paramExpression, out errorMessages); warningDataViewQry = personService.Get(paramExpression, warningDataViewWhereExpression); } if (dataViewQry != null) { var personWithRequirements = from p in personQry join d in dataViewQry on p equals d into oj from d in oj.DefaultIfEmpty() select new { PersonId = p.Id, Included = d != null, WarningIncluded = false }; // if a Warning Database was specified, set the WarningIncluded flag to true if they are included in the Warning Dataview if (warningDataViewQry != null) { personWithRequirements = personWithRequirements.Select(a => new { a.PersonId, a.Included, WarningIncluded = warningDataViewQry.Any(w => w.Id == a.PersonId) }); } var result = personWithRequirements.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a.PersonId, GroupRequirement = this, MeetsGroupRequirement = a.Included ? (a.WarningIncluded ? MeetsGroupRequirement.MeetsWithWarning : MeetsGroupRequirement.Meets) : MeetsGroupRequirement.NotMet }); return(result); } } else { throw new Exception("No dataview assigned to Group Requirement Type: " + this.GroupRequirementType.Name); } } else if (this.GroupRequirementType.RequirementCheckType == RequirementCheckType.Sql) { // if requirement set on GroupType, this.Group is null var targetGroup = this.Group ?? new GroupService(rockContext).Get(groupId); string formattedSql = this.GroupRequirementType.SqlExpression.ResolveMergeFields(this.GroupRequirementType.GetMergeObjects(targetGroup)); string warningFormattedSql = this.GroupRequirementType.WarningSqlExpression.ResolveMergeFields(this.GroupRequirementType.GetMergeObjects(targetGroup)); try { var tableResult = DbService.GetDataTable(formattedSql, System.Data.CommandType.Text, null); if (tableResult.Columns.Count > 0) { IEnumerable <int> personIds = tableResult.Rows.OfType <System.Data.DataRow>().Select(r => Convert.ToInt32(r[0])); IEnumerable <int> warningPersonIds = null; // if a Warning SQL was specified, get a list of PersonIds that should have a warning with their status if (!string.IsNullOrWhiteSpace(warningFormattedSql)) { var warningTableResult = DbService.GetDataTable(warningFormattedSql, System.Data.CommandType.Text, null); if (warningTableResult.Columns.Count > 0) { warningPersonIds = warningTableResult.Rows.OfType <System.Data.DataRow>().Select(r => Convert.ToInt32(r[0])); } } var result = personQry.Select(a => a.Id).ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a, GroupRequirement = this, MeetsGroupRequirement = personIds.Contains(a) ? ((warningPersonIds != null && warningPersonIds.Contains(a)) ? MeetsGroupRequirement.MeetsWithWarning : MeetsGroupRequirement.Meets ) : MeetsGroupRequirement.NotMet, }); return(result); } } catch (Exception ex) { // Exception occurred (probably due to bad SQL) ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); var result = personQry.Select(a => a.Id).ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a, GroupRequirement = this, MeetsGroupRequirement = MeetsGroupRequirement.Error }); return(result); } } else { // manual var groupMemberRequirementQry = new GroupMemberRequirementService(rockContext).Queryable().Where(a => a.GroupMember.GroupId == groupId && a.GroupRequirementId == this.Id && a.RequirementMetDateTime.HasValue); var result = personQry.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a.Id, GroupRequirement = this, MeetsGroupRequirement = groupMemberRequirementQry.Any(r => r.GroupMember.PersonId == a.Id) ? MeetsGroupRequirement.Meets : MeetsGroupRequirement.NotMet }); return(result); } // shouldn't happen return(null); }
/// <summary> /// Registers any entity-based block types that are not currently registered in Rock. /// </summary> /// <param name="refreshAll">if set to <c>true</c> will refresh name, category, and description for all block types (not just the new ones)</param> private static void RegisterEntityBlockTypes(bool refreshAll = false) { var rockBlockTypes = Reflection.FindTypes(typeof(Blocks.IRockBlockType)); List <Type> registeredTypes; using (var rockContext = new RockContext()) { registeredTypes = new BlockTypeService(rockContext) .Queryable().AsNoTracking() .Where(b => b.EntityTypeId.HasValue && !string.IsNullOrEmpty(b.EntityType.AssemblyName)) .ToList() .Select(b => Type.GetType(b.EntityType.AssemblyName, false)) .Where(b => b != null) .ToList(); } // Get the Block Entity Type int?blockEntityTypeId = EntityTypeCache.Get(typeof(Block)).Id; // for each BlockType foreach (var type in rockBlockTypes.Values) { if (refreshAll || !registeredTypes.Any(t => t == type)) { // Attempt to load the control try { using (var rockContext = new RockContext()) { var entityTypeId = EntityTypeCache.Get(type, true, rockContext).Id; var blockTypeService = new BlockTypeService(rockContext); var blockType = blockTypeService.Queryable() .FirstOrDefault(b => b.EntityTypeId == entityTypeId); if (blockType == null) { // Create new BlockType record and save it blockType = new BlockType(); blockType.EntityTypeId = entityTypeId; blockTypeService.Add(blockType); } // Update Name, Category, and Description based on block's attribute definitions blockType.Name = Reflection.GetDisplayName(type) ?? string.Empty; if (string.IsNullOrWhiteSpace(blockType.Name)) { blockType.Name = type.FullName; } if (blockType.Name.Length > 100) { blockType.Name = blockType.Name.Truncate(100); } blockType.Category = Rock.Reflection.GetCategory(type) ?? string.Empty; blockType.Description = Rock.Reflection.GetDescription(type) ?? string.Empty; rockContext.SaveChanges(); // Update the attributes used by the block Rock.Attribute.Helper.UpdateAttributes(type, blockEntityTypeId, "BlockTypeId", blockType.Id.ToString(), rockContext); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"RegisterEntityBlockTypes failed for {type.FullName} with exception: {ex.Message}"); ExceptionLogService.LogException(new Exception(string.Format("Problem processing block with path '{0}'.", type.FullName), ex), null); } } } }
/// <summary> /// Registers any block types that are not currently registered in Rock. /// </summary> /// <param name="physWebAppPath">A <see cref="System.String" /> containing the physical path to Rock on the server.</param> /// <param name="page">The <see cref="System.Web.UI.Page" />.</param> /// <param name="refreshAll">if set to <c>true</c> will refresh name, category, and description for all block types (not just the new ones)</param> public static void RegisterBlockTypes(string physWebAppPath, System.Web.UI.Page page, bool refreshAll = false) { // Dictionary for block types. Key is path, value is friendly name var list = new Dictionary <string, string>(); RegisterEntityBlockTypes(refreshAll); // Find all the blocks in the Blocks folder... FindAllBlocksInPath(physWebAppPath, list, "Blocks"); // Now do the exact same thing for the Plugins folder... FindAllBlocksInPath(physWebAppPath, list, "Plugins"); // Get a list of the BlockTypes already registered (via the path) var registeredPaths = new List <string>(); using (var rockContext = new RockContext()) { registeredPaths = new BlockTypeService(rockContext) .Queryable().AsNoTracking() .Where(b => !string.IsNullOrEmpty(b.Path)) .Select(b => b.Path) .ToList(); } // Get the Block Entity Type int?blockEntityTypeId = EntityTypeCache.Get(typeof(Block)).Id; // for each BlockType foreach (string path in list.Keys) { if (refreshAll || !registeredPaths.Any(b => b.Equals(path, StringComparison.OrdinalIgnoreCase))) { // Attempt to load the control try { var blockCompiledType = System.Web.Compilation.BuildManager.GetCompiledType(path); if (blockCompiledType != null && typeof(Web.UI.RockBlock).IsAssignableFrom(blockCompiledType)) { using (var rockContext = new RockContext()) { var blockTypeService = new BlockTypeService(rockContext); var blockType = blockTypeService.Queryable() .FirstOrDefault(b => b.Path == path); if (blockType == null) { // Create new BlockType record and save it blockType = new BlockType(); blockType.Path = path; blockTypeService.Add(blockType); } Type controlType = blockCompiledType; // Update Name, Category, and Description based on block's attribute definitions blockType.Name = Reflection.GetDisplayName(controlType) ?? string.Empty; if (string.IsNullOrWhiteSpace(blockType.Name)) { // Parse the relative path to get the name var nameParts = list[path].Split('/'); for (int i = 0; i < nameParts.Length; i++) { if (i == nameParts.Length - 1) { nameParts[i] = Path.GetFileNameWithoutExtension(nameParts[i]); } nameParts[i] = nameParts[i].SplitCase(); } blockType.Name = string.Join(" > ", nameParts); } if (blockType.Name.Length > 100) { blockType.Name = blockType.Name.Truncate(100); } blockType.Category = Rock.Reflection.GetCategory(controlType) ?? string.Empty; blockType.Description = Rock.Reflection.GetDescription(controlType) ?? string.Empty; rockContext.SaveChanges(); // Update the attributes used by the block Rock.Attribute.Helper.UpdateAttributes(controlType, blockEntityTypeId, "BlockTypeId", blockType.Id.ToString(), rockContext); } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"RegisterBlockTypes failed for {path} with exception: {ex.Message}"); ExceptionLogService.LogException(new Exception(string.Format("Problem processing block with path '{0}'.", path), ex), null); } } } }
/// <summary> /// Builds the base query for the Exception List grid data /// </summary> /// <returns>IQueryable containing filtered ExceptionLog records</returns> private IQueryable<ExceptionLog> BuildBaseExceptionListQuery() { ExceptionLogService exceptionLogService = new ExceptionLogService( new RockContext() ); IQueryable<ExceptionLog> query = exceptionLogService.Queryable(); int siteId; if ( int.TryParse( fExceptionList.GetUserPreference( "Site" ), out siteId ) && siteId > 0 ) { query = query.Where( e => e.SiteId == siteId ); } int pageId; if ( int.TryParse( fExceptionList.GetUserPreference( "Page" ), out pageId ) && pageId > 0 ) { query = query.Where( e => e.PageId == pageId ); } int userPersonID; if ( int.TryParse( fExceptionList.GetUserPreference( "User" ), out userPersonID ) && userPersonID > 0 ) { query = query.Where( e => e.CreatedByPersonAlias != null && e.CreatedByPersonAlias.PersonId == userPersonID ); } string statusCode = fExceptionList.GetUserPreference( "Status Code" ); if ( !String.IsNullOrEmpty( statusCode ) ) { query = query.Where( e => e.StatusCode == statusCode ); } DateTime startDate; if ( DateTime.TryParse( fExceptionList.GetUserPreference( "Start Date" ), out startDate ) ) { startDate = startDate.Date; query = query.Where( e => e.CreatedDateTime.HasValue && e.CreatedDateTime.Value >= startDate ); } DateTime endDate; if ( DateTime.TryParse( fExceptionList.GetUserPreference( "End Date" ), out endDate ) ) { endDate = endDate.Date.AddDays( 1 ); query = query.Where( e => e.CreatedDateTime.HasValue && e.CreatedDateTime.Value < endDate ); } //Only look for inner exceptions query = query.Where( e => e.HasInnerException == null || e.HasInnerException == false ); return query; }
protected override void PreSave() { if (Entry.State == EntityContextState.Deleted) { if (Entity.StorageProvider != null) { Entity.BinaryFileTypeId = Entry.OriginalValues[nameof(Entity.BinaryFileTypeId)].ToString().AsInteger(); try { Entity.StorageProvider.DeleteContent(Entity); } catch (Exception ex) { // If an exception occurred while trying to delete provider's file, log the exception, but continue with the delete. ExceptionLogService.LogException(ex); } Entity.BinaryFileTypeId = null; } } else { if (Entity.BinaryFileType == null && Entity.BinaryFileTypeId.HasValue) { Entity.BinaryFileType = new BinaryFileTypeService(( RockContext )DbContext).Get(Entity.BinaryFileTypeId.Value); } if (Entity.MimeType.StartsWith("image/")) { try { using (Bitmap bm = new Bitmap(Entity.ContentStream)) { if (bm != null) { Entity.Width = bm.Width; Entity.Height = bm.Height; } } Entity.ContentStream.Seek(0, SeekOrigin.Begin); if (!Entity.IsTemporary) { var BinaryFileType = Entity.BinaryFileType; if (BinaryFileType.MaxHeight.HasValue && BinaryFileType.MaxHeight != 0 && BinaryFileType.MaxWidth.HasValue && BinaryFileType.MaxWidth != 0) { ResizeSettings settings = new ResizeSettings(); MemoryStream resizedStream = new MemoryStream(); if (BinaryFileType.MaxWidth.Value < Entity.Width || BinaryFileType.MaxHeight < Entity.Height) { settings.Add("mode", "max"); if (BinaryFileType.MaxHeight < Entity.Height && BinaryFileType.MaxWidth < Entity.Width) { if (BinaryFileType.MaxHeight >= BinaryFileType.MaxWidth) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } if (BinaryFileType.MaxHeight <= BinaryFileType.MaxWidth) { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } } else if (BinaryFileType.MaxHeight < Entity.Height) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } else { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } ImageBuilder.Current.Build(Entity.ContentStream, resizedStream, settings); Entity.ContentStream = resizedStream; using (Bitmap bm = new Bitmap(Entity.ContentStream)) { if (bm != null) { Entity.Width = bm.Width; Entity.Height = bm.Height; } } } } } } catch (Exception) { } // if the file is an invalid photo keep moving } if (Entry.State == EntityContextState.Added) { // when a file is saved (unless it is getting Deleted/Saved), it should use the StoredEntityType that is associated with the BinaryFileType if (Entity.BinaryFileType != null) { // Persist the storage type Entity.StorageEntityTypeId = Entity.BinaryFileType.StorageEntityTypeId; // Persist the storage type's settings specific to this binary file type var settings = new Dictionary <string, string>(); if (Entity.BinaryFileType.Attributes == null) { Entity.BinaryFileType.LoadAttributes(); } foreach (var attributeValue in Entity.BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } Entity.StorageEntitySettings = settings.ToJson(); if (Entity.StorageProvider != null) { // save the file to the provider's new storage medium, and if the medium returns a filesize, save that value. long?outFileSize = null; Entity.StorageProvider.SaveContent(Entity, out outFileSize); if (outFileSize.HasValue) { Entity.FileSize = outFileSize; } Entity.Path = Entity.StorageProvider.GetPath(Entity); } } } else if (Entry.State == EntityContextState.Modified) { // when a file is saved (unless it is getting Deleted/Added), // it should use the StorageEntityType that is associated with the BinaryFileType if (Entity.BinaryFileType != null) { // if the storage provider changed, or any of its settings specific // to the binary file type changed, delete the original provider's content if (Entity.StorageEntityTypeId.HasValue && Entity.BinaryFileType.StorageEntityTypeId.HasValue) { var settings = new Dictionary <string, string>(); if (Entity.BinaryFileType.Attributes == null) { Entity.BinaryFileType.LoadAttributes(); } foreach (var attributeValue in Entity.BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } string settingsJson = settings.ToJson(); if (Entity.StorageProvider != null && ( Entity.StorageEntityTypeId.Value != Entity.BinaryFileType.StorageEntityTypeId.Value || Entity.StorageEntitySettings != settingsJson)) { var ms = new MemoryStream(); Entity.ContentStream.Position = 0; Entity.ContentStream.CopyTo(ms); Entity.ContentStream.Dispose(); // Delete the current provider's storage Entity.StorageProvider.DeleteContent(Entity); // Set the new storage provider with its settings Entity.StorageEntityTypeId = Entity.BinaryFileType.StorageEntityTypeId; Entity.StorageEntitySettings = settingsJson; Entity.ContentStream = new MemoryStream(); ms.Position = 0; ms.CopyTo(Entity.ContentStream); Entity.ContentStream.Position = 0; Entity.FileSize = Entity.ContentStream.Length; } } } if (Entity.ContentIsDirty && Entity.StorageProvider != null) { /* * SK - 12/11/2021 * Path should always be reset in case when there is any change in Storage Provider from previous value. Otherwise new storage provider may still be refering the older path. */ Entity.Path = null; long?fileSize = null; Entity.StorageProvider.SaveContent(Entity, out fileSize); Entity.FileSize = fileSize; Entity.Path = Entity.StorageProvider.GetPath(Entity); } } } base.PreSave(); }
/// <summary> /// Ensures that each Metric that has EnableAnalytics has a SQL View for it, and also deletes any AnalyticsFactMetric** views that no longer have metric (based on Metric.Name) /// </summary> public void EnsureMetricAnalyticsViews() { string analyticMetricViewsPrefix = "AnalyticsFactMetric"; string getAnalyticMetricViewsSQL = string.Format( @"SELECT OBJECT_NAME(sm.object_id) [view_name] ,sm.DEFINITION [view_definition] FROM sys.sql_modules AS sm JOIN sys.objects AS o ON sm.object_id = o.object_id WHERE o.type = 'V' AND OBJECT_NAME(sm.object_id) LIKE '{0}%'", analyticMetricViewsPrefix); var dataTable = DbService.GetDataTable(getAnalyticMetricViewsSQL, System.Data.CommandType.Text, null); var databaseAnalyticMetricViews = dataTable.Rows.OfType <DataRow>() .Select(row => new { ViewName = row["view_name"] as string, ViewDefinition = row["view_definition"] as string }).ToList(); var metricsWithAnalyticsEnabled = this.Queryable().Where(a => a.EnableAnalytics).Include(a => a.MetricPartitions).AsNoTracking().ToList(); var metricViewNames = metricsWithAnalyticsEnabled.Select(a => $"{analyticMetricViewsPrefix}{a.Title.RemoveSpecialCharacters()}").ToList(); var orphanedDatabaseViews = databaseAnalyticMetricViews.Where(a => !metricViewNames.Contains(a.ViewName)).ToList(); // DROP any Metric Analytic Views that are orphaned. In other words, there are views named 'AnalyticsFactMetric***' that don't have a metric. // This could happen if Metric.EnableAnalytics changed from True to False, Metric Title changed, or if a Metric was deleted. foreach (var orphanedView in orphanedDatabaseViews) { this.Context.Database.ExecuteSqlCommand($"DROP VIEW [{orphanedView.ViewName}]"); } // Make sure that each Metric with EnableAnalytics=True has a SQL View and that the View Definition is correct foreach (var metric in metricsWithAnalyticsEnabled) { string metricViewName = $"{analyticMetricViewsPrefix}{metric.Title.RemoveSpecialCharacters()}"; var metricEntityPartitions = metric.MetricPartitions.Where(a => a.EntityTypeId.HasValue).OrderBy(a => a.Order).ThenBy(a => a.Label).Select(a => new { a.Label, a.EntityTypeId }); var viewPartitionSELECTClauses = metricEntityPartitions.Select(a => $" ,pvt.[{a.EntityTypeId}] as [{a.Label}Id]").ToList().AsDelimited("\n"); List <string> partitionEntityLookupSELECTs = new List <string>(); List <string> partitionEntityLookupJOINs = new List <string>(); foreach (var metricPartition in metricEntityPartitions) { var metricPartitionEntityType = EntityTypeCache.Read(metricPartition.EntityTypeId.Value); if (metricPartitionEntityType != null) { var tableAttribute = metricPartitionEntityType.GetEntityType().GetCustomAttribute <TableAttribute>(); if (tableAttribute != null) { if (metricPartitionEntityType.Id == EntityTypeCache.GetId <DefinedValue>()) { partitionEntityLookupSELECTs.Add($"j{metricPartition.EntityTypeId}.Value [{metricPartition.Label.RemoveSpecialCharacters()}Name]"); } else if (metricPartitionEntityType.GetEntityType().GetProperty("Name") != null) { partitionEntityLookupSELECTs.Add($"j{metricPartition.EntityTypeId}.Name [{metricPartition.Label.RemoveSpecialCharacters()}Name]"); } partitionEntityLookupJOINs.Add($"LEFT JOIN [{tableAttribute.Name}] j{metricPartition.EntityTypeId} ON p.{metricPartition.Label.RemoveSpecialCharacters()}Id = j{metricPartition.EntityTypeId}.Id"); } } } var viewPIVOTInClauses = metricEntityPartitions.Select(a => $" [{a.EntityTypeId}]").ToList().AsDelimited(",\n"); if (string.IsNullOrEmpty(viewPIVOTInClauses)) { // This metric only has the default partition, and with no EntityTypeId, so put in a dummy Pivot Clause viewPIVOTInClauses = "[0]"; } var viewJoinsSELECT = partitionEntityLookupSELECTs.Select(a => $" ,{a}").ToList().AsDelimited("\n"); var viewJoinsFROM = partitionEntityLookupJOINs.AsDelimited("\n"); var viewDefinition = $@" /* <auto-generated> This view was generated by the Rock's MetricService.EnsureMetricAnalyticsViews() which gets called when a Metric is saved. Changes to this view definition will be lost when the view is regenerated. NOTE: Any Views with the prefix '{analyticMetricViewsPrefix}' are assumed to be Code Generated and may be deleted if there isn't a Metric associated with it </auto-generated> <doc> <summary> This VIEW helps present the data for the {metric.Title} metric. </summary> </doc> */ CREATE VIEW [{metricViewName}] AS SELECT p.* {viewJoinsSELECT} FROM ( SELECT pvt.Id ,cast(pvt.MetricValueDateTime AS DATE) AS [MetricValueDateTime] ,pvt.YValue {viewPartitionSELECTClauses} FROM ( SELECT mv.Id ,mv.YValue ,mv.MetricValueDateTime ,mvp.EntityId ,mp.EntityTypeId FROM MetricValue mv JOIN MetricValuePartition mvp ON mvp.MetricValueId = mv.Id JOIN MetricPartition mp ON mvp.MetricPartitionId = mp.Id WHERE mv.MetricId = {metric.Id} ) src pivot(min(EntityId) FOR EntityTypeId IN ({viewPIVOTInClauses})) pvt ) p {viewJoinsFROM} "; var databaseViewDefinition = databaseAnalyticMetricViews.Where(a => a.ViewName == metricViewName).FirstOrDefault(); try { if (databaseViewDefinition != null) { if (databaseViewDefinition.ViewDefinition != viewDefinition) { // view already exists, but something has changed, so drop and recreate it this.Context.Database.ExecuteSqlCommand($"DROP VIEW [{metricViewName}]"); this.Context.Database.ExecuteSqlCommand(viewDefinition); } } else { this.Context.Database.ExecuteSqlCommand(viewDefinition); } } catch (Exception ex) { // silently log the exception ExceptionLogService.LogException(new Exception("Error creating Analytics view for " + metric.Title, ex), System.Web.HttpContext.Current); } } }
/// <summary> /// Job that executes routine Rock cleanup tasks /// /// 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 ) { var rockContext = new Rock.Data.RockContext(); // get the job map JobDataMap dataMap = context.JobDetail.JobDataMap; // delete accounts that have not been confirmed in X hours int? userExpireHours = dataMap.GetString( "HoursKeepUnconfirmedAccounts" ).AsIntegerOrNull(); if ( userExpireHours.HasValue ) { DateTime userAccountExpireDate = RockDateTime.Now.Add( new TimeSpan( userExpireHours.Value * -1, 0, 0 ) ); var userLoginService = new UserLoginService(rockContext); foreach ( var user in userLoginService.Queryable().Where( u => u.IsConfirmed == false && ( u.CreatedDateTime ?? DateTime.MinValue ) < userAccountExpireDate ).ToList() ) { userLoginService.Delete( user ); } rockContext.SaveChanges(); } // purge exception log int? exceptionExpireDays = dataMap.GetString( "DaysKeepExceptions" ).AsIntegerOrNull(); if ( exceptionExpireDays.HasValue ) { DateTime exceptionExpireDate = RockDateTime.Now.Add( new TimeSpan( exceptionExpireDays.Value * -1, 0, 0, 0 ) ); ExceptionLogService exceptionLogService = new ExceptionLogService( rockContext ); foreach ( var exception in exceptionLogService.Queryable().Where( e => e.CreatedDateTime.HasValue && e.CreatedDateTime < exceptionExpireDate ).ToList() ) { exceptionLogService.Delete( exception ); } rockContext.SaveChanges(); } // purge audit log int? auditExpireDays = dataMap.GetString( "AuditLogExpirationDays" ).AsIntegerOrNull(); if ( auditExpireDays.HasValue ) { DateTime auditExpireDate = RockDateTime.Now.Add( new TimeSpan( auditExpireDays.Value * -1, 0, 0, 0 ) ); AuditService auditService = new AuditService(rockContext); foreach ( var audit in auditService.Queryable().Where( a => a.DateTime < auditExpireDate ).ToList() ) { auditService.Delete( audit ); } rockContext.SaveChanges(); } // clean the cached file directory // get the attributes string cacheDirectoryPath = dataMap.GetString( "BaseCacheDirectory" ); int? cacheExpirationDays = dataMap.GetString( "DaysKeepCachedFiles" ).AsIntegerOrNull(); if ( cacheExpirationDays.HasValue ) { DateTime cacheExpirationDate = RockDateTime.Now.Add( new TimeSpan( cacheExpirationDays.Value * -1, 0, 0, 0 ) ); // if job is being run by the IIS scheduler and path is not null if ( context.Scheduler.SchedulerName == "RockSchedulerIIS" && !string.IsNullOrEmpty( cacheDirectoryPath ) ) { // get the physical path of the cache directory cacheDirectoryPath = System.Web.Hosting.HostingEnvironment.MapPath( cacheDirectoryPath ); } // if directory is not blank and cache expiration date not in the future if ( !string.IsNullOrEmpty( cacheDirectoryPath ) && cacheExpirationDate <= RockDateTime.Now ) { // Clean cache directory CleanCacheDirectory( cacheDirectoryPath, cacheExpirationDate ); } } // clean out any temporary binary files BinaryFileService binaryFileService = new BinaryFileService(rockContext); foreach ( var binaryFile in binaryFileService.Queryable().Where( bf => bf.IsTemporary == true ).ToList() ) { if ( binaryFile.ModifiedDateTime < RockDateTime.Now.AddDays( -1 ) ) { binaryFileService.Delete( binaryFile ); } } rockContext.SaveChanges(); // Add any missing person aliases PersonService personService = new PersonService(rockContext); foreach ( var person in personService.Queryable( "Aliases" ) .Where( p => !p.Aliases.Any() ) .Take( 300 ) ) { person.Aliases.Add( new PersonAlias { AliasPersonId = person.Id, AliasPersonGuid = person.Guid } ); } rockContext.SaveChanges(); // Add any missing metaphones int namesToProcess = dataMap.GetString( "MaxMetaphoneNames" ).AsInteger(); if ( namesToProcess > 0 ) { var firstNameQry = personService.Queryable().Select( p => p.FirstName ); var nickNameQry = personService.Queryable().Select( p => p.NickName ); var lastNameQry = personService.Queryable().Select( p => p.LastName ); var nameQry = firstNameQry.Union( nickNameQry.Union( lastNameQry ) ); var metaphones = rockContext.Metaphones; var existingNames = metaphones.Select( m => m.Name ).Distinct(); // Get the names that have not yet been processed var namesToUpdate = nameQry .Where( n => !existingNames.Contains( n ) ) .Take( namesToProcess ) .ToList(); foreach ( string name in namesToUpdate ) { string mp1 = string.Empty; string mp2 = string.Empty; Rock.Utility.DoubleMetaphone.doubleMetaphone( name, ref mp1, ref mp2 ); var metaphone = new Metaphone(); metaphone.Name = name; metaphone.Metaphone1 = mp1; metaphone.Metaphone2 = mp2; metaphones.Add( metaphone ); } rockContext.SaveChanges(); } }
protected override void PreSave() { if (Entry.State == EntityContextState.Deleted) { if (Entity.StorageProvider != null) { Entity.BinaryFileTypeId = Entry.OriginalValues[nameof(Entity.BinaryFileTypeId)].ToString().AsInteger(); try { Entity.StorageProvider.DeleteContent(Entity); } catch (Exception ex) { // If an exception occurred while trying to delete provider's file, log the exception, but continue with the delete. ExceptionLogService.LogException(ex); } Entity.BinaryFileTypeId = null; } } else { if (Entity.BinaryFileType == null && Entity.BinaryFileTypeId.HasValue) { Entity.BinaryFileType = new BinaryFileTypeService(( RockContext )DbContext).Get(Entity.BinaryFileTypeId.Value); } if (Entity.MimeType.StartsWith("image/")) { try { using (Bitmap bm = new Bitmap(Entity.ContentStream)) { if (bm != null) { Entity.Width = bm.Width; Entity.Height = bm.Height; } } Entity.ContentStream.Seek(0, SeekOrigin.Begin); var binaryFileType = Entity.BinaryFileType; var binaryFileTypeMaxHeight = binaryFileType.MaxHeight ?? 0; var binaryFileTypeMaxWidth = binaryFileType.MaxWidth ?? 0; var binaryFileTypeMaxHeightIsValid = binaryFileTypeMaxHeight > 0; var binaryFileTypeMaxWidthIsValid = binaryFileTypeMaxWidth > 0; var binaryFileTypeDimensionsAreValid = binaryFileTypeMaxHeightIsValid && binaryFileTypeMaxWidthIsValid; ResizeSettings settings = new ResizeSettings(); MemoryStream resizedStream = new MemoryStream(); if ((binaryFileTypeMaxWidthIsValid && binaryFileTypeMaxWidth < Entity.Width) || (binaryFileTypeMaxHeightIsValid && binaryFileTypeMaxHeight < Entity.Height)) { /* How to handle aspect-ratio conflicts between the image and width+height. * 'pad' adds whitespace, * 'crop' crops minimally, * 'carve' uses seam carving, * 'stretch' loses aspect-ratio, stretching the image. * 'max' behaves like maxwidth/maxheight */ settings.Add("mode", "max"); // Height and width are both set. if (binaryFileTypeDimensionsAreValid) { // A valid max height and width but the max height is greater or equal than the width. if (binaryFileTypeMaxHeight >= binaryFileTypeMaxWidth) { settings.Add("height", binaryFileTypeMaxHeight.ToString()); } // A valid max height and width but the max height is less or equal the width. else if (binaryFileTypeMaxHeight <= binaryFileTypeMaxWidth) { settings.Add("width", binaryFileTypeMaxWidth.ToString()); } } else { // A valid max height but less than the binary file height. if (binaryFileTypeMaxHeightIsValid && binaryFileTypeMaxHeight < Entity.Height) { settings.Add("height", binaryFileTypeMaxHeight.ToString()); } else { // A Valid max width. settings.Add("width", binaryFileTypeMaxWidth.ToString()); } } if (settings.HasKeys()) { ImageBuilder.Current.Build(Entity.ContentStream, resizedStream, settings); Entity.ContentStream = resizedStream; using (Bitmap bm = new Bitmap(Entity.ContentStream)) { if (bm != null) { Entity.Width = bm.Width; Entity.Height = bm.Height; } } } } } catch (Exception ex) { RockLogger.Log.Error(RockLogDomains.Core, ex, "Error trying to resize the file {0}.", Entity?.FileName); } } if (Entry.State == EntityContextState.Added) { // when a file is saved (unless it is getting Deleted/Saved), it should use the StoredEntityType that is associated with the BinaryFileType if (Entity.BinaryFileType != null) { // Persist the storage type Entity.StorageEntityTypeId = Entity.BinaryFileType.StorageEntityTypeId; // Persist the storage type's settings specific to this binary file type var settings = new Dictionary <string, string>(); if (Entity.BinaryFileType.Attributes == null) { Entity.BinaryFileType.LoadAttributes(); } foreach (var attributeValue in Entity.BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } Entity.StorageEntitySettings = settings.ToJson(); if (Entity.StorageProvider != null) { // save the file to the provider's new storage medium, and if the medium returns a filesize, save that value. long?outFileSize = null; Entity.StorageProvider.SaveContent(Entity, out outFileSize); if (outFileSize.HasValue) { Entity.FileSize = outFileSize; } Entity.Path = Entity.StorageProvider.GetPath(Entity); } else { throw new Rock.Web.FileUploadException("A storage provider has not been registered for this file type or the current storage provider is inactive.", System.Net.HttpStatusCode.BadRequest); } } } else if (Entry.State == EntityContextState.Modified) { // when a file is saved (unless it is getting Deleted/Added), // it should use the StorageEntityType that is associated with the BinaryFileType if (Entity.BinaryFileType != null) { // if the storage provider changed, or any of its settings specific // to the binary file type changed, delete the original provider's content if (Entity.StorageEntityTypeId.HasValue && Entity.BinaryFileType.StorageEntityTypeId.HasValue) { var settings = new Dictionary <string, string>(); if (Entity.BinaryFileType.Attributes == null) { Entity.BinaryFileType.LoadAttributes(); } foreach (var attributeValue in Entity.BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } string settingsJson = settings.ToJson(); if (Entity.StorageProvider != null && ( Entity.StorageEntityTypeId.Value != Entity.BinaryFileType.StorageEntityTypeId.Value || Entity.StorageEntitySettings != settingsJson)) { var ms = new MemoryStream(); Entity.ContentStream.Position = 0; Entity.ContentStream.CopyTo(ms); Entity.ContentStream.Dispose(); // Delete the current provider's storage Entity.StorageProvider.DeleteContent(Entity); // Set the new storage provider with its settings Entity.StorageEntityTypeId = Entity.BinaryFileType.StorageEntityTypeId; Entity.StorageEntitySettings = settingsJson; Entity.ContentStream = new MemoryStream(); ms.Position = 0; ms.CopyTo(Entity.ContentStream); Entity.ContentStream.Position = 0; Entity.FileSize = Entity.ContentStream.Length; } } } if (Entity.ContentIsDirty && Entity.StorageProvider != null) { /* * SK - 12/11/2021 * Path should always be reset in case when there is any change in Storage Provider from previous value. Otherwise new storage provider may still be refering the older path. */ Entity.Path = null; long?fileSize = null; Entity.StorageProvider.SaveContent(Entity, out fileSize); Entity.FileSize = fileSize; Entity.Path = Entity.StorageProvider.GetPath(Entity); } } } base.PreSave(); }
/// <summary> /// Gets the Linq expression for the DataViewFilter. /// </summary> /// <param name="filteredEntityType">Type of the filtered entity.</param> /// <param name="serviceInstance">The service instance.</param> /// <param name="parameter">The parameter.</param> /// <param name="dataViewFilterOverrides">The data view filter overrides.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public virtual Expression GetExpression(Type filteredEntityType, IService serviceInstance, ParameterExpression parameter, DataViewFilterOverrides dataViewFilterOverrides, List <string> errorMessages) { switch (ExpressionType) { case FilterExpressionType.Filter: if (this.EntityTypeId.HasValue) { var entityType = EntityTypeCache.Get(this.EntityTypeId.Value); if (entityType != null) { var component = Rock.Reporting.DataFilterContainer.GetComponent(entityType.Name); if (component != null) { try { string selection; // A formatted string representing the filter settings: FieldName, <see cref="ComparisonType">Comparison Type</see>, (optional) Comparison Value(s) var dataViewFilterOverride = dataViewFilterOverrides?.GetOverride(this.Guid); if (dataViewFilterOverride != null) { if (dataViewFilterOverride.IncludeFilter == false) { return(null); } else { selection = dataViewFilterOverride.Selection; } } else { selection = this.Selection; } if (component is IDataFilterWithOverrides) { return((component as IDataFilterWithOverrides).GetExpressionWithOverrides(filteredEntityType, serviceInstance, parameter, dataViewFilterOverrides, selection)); } else { return(component.GetExpression(filteredEntityType, serviceInstance, parameter, selection)); } } catch (SystemException ex) { ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); errorMessages.Add(string.Format("{0}: {1}", component.FormatSelection(filteredEntityType, this.Selection), ex.Message)); } } } } return(null); case FilterExpressionType.GroupAll: case FilterExpressionType.GroupAnyFalse: Expression andExp = null; foreach (var filter in this.ChildFilters) { Expression exp = filter.GetExpression(filteredEntityType, serviceInstance, parameter, dataViewFilterOverrides, errorMessages); if (exp != null) { if (andExp == null) { andExp = exp; } else { andExp = Expression.AndAlso(andExp, exp); } } } if (ExpressionType == FilterExpressionType.GroupAnyFalse && andExp != null) { // If only one of the conditions must be false, invert the expression so that it becomes the logical equivalent of "NOT ALL". andExp = Expression.Not(andExp); } return(andExp); case FilterExpressionType.GroupAny: case FilterExpressionType.GroupAllFalse: Expression orExp = null; foreach (var filter in this.ChildFilters) { Expression exp = filter.GetExpression(filteredEntityType, serviceInstance, parameter, dataViewFilterOverrides, errorMessages); if (exp != null) { if (orExp == null) { orExp = exp; } else { orExp = Expression.OrElse(orExp, exp); } } } if (ExpressionType == FilterExpressionType.GroupAllFalse && orExp != null) { // If all of the conditions must be false, invert the expression so that it becomes the logical equivalent of "NOT ANY". orExp = Expression.Not(orExp); } return(orExp); } return(null); }
/// <summary> /// Recursively logs exception and any children. /// </summary> /// <param name="ex">The <see cref="System.Exception"/> to log.</param> /// <param name="log">The parent <see cref="Rock.Model.ExceptionLog"/> of the exception being logged. This value is nullable.</param> /// <param name="isParent">A <see cref="System.Boolean"/> flag indicating if this Exception is a parent exception. This value is /// <c>true</c> if the exception that is being logged is a parent exception, otherwise <c>false</c>. /// </param> private static void LogExceptions(Exception ex, ExceptionLog log, bool isParent) { // First, attempt to log exception to the database. try { ExceptionLog exceptionLog; // If this is a recursive call and not the originating exception being logged, // attempt to clone the initial one, and populate it with Exception Type and Message // from the inner exception, while retaining the contextual information from where // the exception originated. if (!isParent) { exceptionLog = log.Clone(false); if (exceptionLog != null) { // Populate with inner exception type, message and update whether or not there is another inner exception. exceptionLog.ExceptionType = ex.GetType().ToString(); exceptionLog.Description = ex.Message; exceptionLog.HasInnerException = ex.InnerException != null; // Ensure EF properly recognizes this as a new record. exceptionLog.Id = 0; exceptionLog.Guid = Guid.NewGuid(); exceptionLog.ParentId = log.Id; } } else { exceptionLog = log; } // The only reason this should happen is if the `log.Clone()` operation failed. Compiler sugar. if (exceptionLog == null) { return; } // Write ExceptionLog record to database. var exceptionLogService = new ExceptionLogService(); exceptionLogService.Add(exceptionLog, exceptionLog.CreatedByPersonId); exceptionLogService.Save(exceptionLog, exceptionLog.CreatedByPersonId); // Recurse if inner exception is found if (exceptionLog.HasInnerException.GetValueOrDefault(false)) { LogExceptions(ex.InnerException, exceptionLog, false); } } catch (Exception) { // If logging the exception fails, write the exception to a file try { string directory = AppDomain.CurrentDomain.BaseDirectory; directory = Path.Combine(directory, "App_Data", "Logs"); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } string filePath = Path.Combine(directory, "RockExceptions.csv"); File.AppendAllText(filePath, string.Format("{0},{1},\"{2}\"\r\n", DateTime.Now.ToString(), ex.GetType(), ex.Message)); } catch { // failed to write to database and also failed to write to log file, so there is nowhere to log this error } } }
/// <summary> /// Returns a list of each person and their GroupRequirement status for this group requirement /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="personQry">The person qry.</param> /// <param name="groupId">The group identifier.</param> /// <param name="groupRoleId">The group role identifier.</param> /// <returns></returns> /// <exception cref="System.Exception">No dataview assigned to Group Requirement Type: " + this.GroupRequirementType.Name</exception> public IEnumerable <PersonGroupRequirementStatus> PersonQueryableMeetsGroupRequirement(RockContext rockContext, IQueryable <Person> personQry, int groupId, int?groupRoleId) { if ((this.GroupRoleId != null) && (groupRoleId != null) && (this.GroupRoleId != groupRoleId)) { // if this GroupRequirement is for a specific role, the groupRole we are checking for is something different var result = personQry.Select(p => p.Id).ToList().Select(a => new PersonGroupRequirementStatus { PersonId = Id, GroupRequirement = this, MeetsGroupRequirement = MeetsGroupRequirement.NotApplicable }); return(result); } if (this.GroupRequirementType.RequirementCheckType == RequirementCheckType.Dataview) { var personService = new PersonService(rockContext); var paramExpression = personService.ParameterExpression; List <int> warningDataViewPersonIdList = null; if (this.GroupRequirementType.WarningDataViewId.HasValue) { var warningDataViewWhereExpression = this.GroupRequirementType.WarningDataView.GetExpression(personService, paramExpression); warningDataViewPersonIdList = personService.Get(paramExpression, warningDataViewWhereExpression).Where(a => personQry.Any(p => p.Id == a.Id)).Select(a => a.Id).ToList(); } if (this.GroupRequirementType.DataViewId.HasValue) { var dataViewWhereExpression = this.GroupRequirementType.DataView.GetExpression(personService, paramExpression); var dataViewQry = personService.Get(paramExpression, dataViewWhereExpression); if (dataViewQry != null) { var personWithRequirementsQuery = from p in personQry join d in dataViewQry on p.Id equals d.Id into oj from d in oj.DefaultIfEmpty() select new { PersonId = p.Id, Included = d != null }; var personWithRequirementsList = personWithRequirementsQuery.Select(p => new { PersonId = p.PersonId, Included = p.Included }).ToList(); var result = personWithRequirementsList.Select(a => { var personGroupRequirementStatus = new PersonGroupRequirementStatus { PersonId = a.PersonId, GroupRequirement = this }; var hasWarning = warningDataViewPersonIdList?.Contains(a.PersonId) == true; if (a.Included) { if (hasWarning) { personGroupRequirementStatus.MeetsGroupRequirement = MeetsGroupRequirement.MeetsWithWarning; } else { personGroupRequirementStatus.MeetsGroupRequirement = MeetsGroupRequirement.Meets; } } else { personGroupRequirementStatus.MeetsGroupRequirement = MeetsGroupRequirement.NotMet; } return(personGroupRequirementStatus); } ); return(result); } } else { var personWithIdRequirements = personQry.Select(p => p.Id); var result = personWithIdRequirements.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a, GroupRequirement = this, MeetsGroupRequirement = warningDataViewPersonIdList.Contains(a) == true ? MeetsGroupRequirement.MeetsWithWarning : MeetsGroupRequirement.Meets }); return(result); } } else if (this.GroupRequirementType.RequirementCheckType == RequirementCheckType.Sql) { // if requirement set on GroupType, this.Group is null var targetGroup = this.Group ?? new GroupService(rockContext).Get(groupId); var personQryIdList = personQry.Select(a => a.Id).ToList(); Person personMergeField = null; if (personQryIdList.Count == 1) { var personId = personQryIdList[0]; personMergeField = new PersonService(rockContext).GetNoTracking(personId); } string formattedSql = this.GroupRequirementType.SqlExpression.ResolveMergeFields(this.GroupRequirementType.GetMergeObjects(targetGroup, personMergeField)); string warningFormattedSql = this.GroupRequirementType.WarningSqlExpression.ResolveMergeFields(this.GroupRequirementType.GetMergeObjects(targetGroup, personMergeField)); try { var tableResult = DbService.GetDataTable(formattedSql, System.Data.CommandType.Text, null); if (tableResult.Columns.Count > 0) { IEnumerable <int> personIds = tableResult.Rows.OfType <System.Data.DataRow>().Select(r => Convert.ToInt32(r[0])); IEnumerable <int> warningPersonIds = null; // if a Warning SQL was specified, get a list of PersonIds that should have a warning with their status if (!string.IsNullOrWhiteSpace(warningFormattedSql)) { var warningTableResult = DbService.GetDataTable(warningFormattedSql, System.Data.CommandType.Text, null); if (warningTableResult.Columns.Count > 0) { warningPersonIds = warningTableResult.Rows.OfType <System.Data.DataRow>().Select(r => Convert.ToInt32(r[0])); } } var result = personQryIdList.Select(a => new PersonGroupRequirementStatus { PersonId = a, GroupRequirement = this, MeetsGroupRequirement = personIds.Contains(a) ? ((warningPersonIds != null && warningPersonIds.Contains(a)) ? MeetsGroupRequirement.MeetsWithWarning : MeetsGroupRequirement.Meets ) : MeetsGroupRequirement.NotMet, }); return(result); } } catch (Exception ex) { // Exception occurred (probably due to bad SQL) ExceptionLogService.LogException(ex, System.Web.HttpContext.Current); var result = personQry.Select(a => a.Id).ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a, GroupRequirement = this, MeetsGroupRequirement = MeetsGroupRequirement.Error, CalculationException = ex }); return(result); } } else { // manual var groupMemberRequirementQry = new GroupMemberRequirementService(rockContext).Queryable().Where(a => a.GroupMember.GroupId == groupId && a.GroupRequirementId == this.Id && a.RequirementMetDateTime.HasValue); var result = personQry.ToList().Select(a => new PersonGroupRequirementStatus { PersonId = a.Id, GroupRequirement = this, MeetsGroupRequirement = groupMemberRequirementQry.Any(r => r.GroupMember.PersonId == a.Id) ? MeetsGroupRequirement.Meets : MeetsGroupRequirement.NotMet }); return(result); } // shouldn't happen return(null); }
/// <summary> /// Recursively logs exception and any children. /// </summary> /// <param name="ex">The <see cref="System.Exception"/> to log.</param> /// <param name="log">The parent <see cref="Rock.Model.ExceptionLog"/> of the exception being logged. This value is nullable.</param> /// <param name="isParent">A <see cref="System.Boolean"/> flag indicating if this Exception is a parent exception. This value is /// <c>true</c> if the exception that is being logged is a parent exception, otherwise <c>false</c>. /// </param> private static void LogExceptions(Exception ex, ExceptionLog log, bool isParent) { bool logToFile = AlwaysLogToFile; // First, attempt to log exception to the database. try { ExceptionLog exceptionLog; // If this is a recursive call and not the originating exception being logged, // attempt to clone the initial one, and populate it with Exception Type and Message // from the inner exception, while retaining the contextual information from where // the exception originated. if (!isParent) { exceptionLog = log.Clone(false); if (exceptionLog != null) { // Populate with inner exception type, message and update whether or not there is another inner exception. exceptionLog.ExceptionType = ex.GetType().ToString(); exceptionLog.Description = ex.Message; exceptionLog.Source = ex.Source; exceptionLog.StackTrace = ex.StackTrace; exceptionLog.HasInnerException = ex.InnerException != null; // Ensure EF properly recognizes this as a new record. exceptionLog.Id = 0; exceptionLog.Guid = Guid.NewGuid(); exceptionLog.ParentId = log.Id; } } else { exceptionLog = log; } // The only reason this should happen is if the `log.Clone()` operation failed. Compiler sugar. if (exceptionLog == null) { return; } // Write ExceptionLog record to database. using (var rockContext = new Rock.Data.RockContext()) { var exceptionLogService = new ExceptionLogService(rockContext); exceptionLogService.Add(exceptionLog); // make sure to call the regular SaveChanges so that CreatedBy,CreatedByDateTime, etc get set properly. If any of the post processing happens to also create an exception, we can just log to the exception file instead rockContext.SaveChanges(); } // Recurse if inner exception is found if (exceptionLog.HasInnerException.GetValueOrDefault(false)) { LogExceptions(ex.InnerException, exceptionLog, false); } if (ex is AggregateException) { // if an AggregateException occurs, log the exceptions individually var aggregateException = (ex as AggregateException); foreach (var innerException in aggregateException.InnerExceptions) { LogExceptions(innerException, exceptionLog, false); } } } catch (Exception) { // If logging the exception fails, write the exceptions to a file logToFile = true; } if (logToFile) { try { string directory = AppDomain.CurrentDomain.BaseDirectory; directory = Path.Combine(directory, "App_Data", "Logs"); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } string filePath = Path.Combine(directory, "RockExceptions.csv"); string when = RockDateTime.Now.ToString(); while (ex != null) { File.AppendAllText(filePath, string.Format("{0},{1},\"{2}\",\"{3}\"\r\n", when, ex.GetType(), ex.Message, ex.StackTrace)); ex = ex.InnerException; } } catch { // failed to write to database and also failed to write to log file, so there is nowhere to log this error } } }
/// <summary> /// Loads the control. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { base.OnLoad( e ); if ( !Page.IsPostBack ) { //Set Exception Panel visibility to show Exception List SetExceptionPanelVisibility( None.Id ); } lcExceptions.Options.SetChartStyle( this.ChartStyle ); lcExceptions.Options.legend = lcExceptions.Options.legend ?? new Legend(); lcExceptions.Options.legend.show = this.GetAttributeValue( "ShowLegend" ).AsBooleanOrNull(); lcExceptions.Options.legend.position = this.GetAttributeValue( "LegendPosition" ); // get data for graphs ExceptionLogService exceptionLogService = new ExceptionLogService( new RockContext() ); var exceptionList = exceptionLogService.Queryable() .Where(x => x.HasInnerException == false && x.CreatedDateTime != null) .GroupBy( x => DbFunctions.TruncateTime(x.CreatedDateTime.Value )) .Select( eg => new { DateValue = eg.Key, ExceptionCount = eg.Count(), UniqueExceptionCount = eg.Select( y => y.ExceptionType ).Distinct().Count() } ).OrderBy(eg => eg.DateValue).ToList(); if ( exceptionList.Count == 1 ) { // if there is only one datapoint for the Chart, the yaxis labeling gets messed up, plus the graph wouldn't be useful anyways lcExceptions.Visible = false; } }
/// <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 (HistoryChanges != null) { foreach (var historyItem in HistoryChanges) { int personId = historyItem.PersonId > 0 ? historyItem.PersonId : Entity.PersonId; // if GroupId is 0, it is probably a Group that wasn't saved yet, so get the GroupId from historyItem.Group.Id instead if (historyItem.GroupId == 0) { historyItem.GroupId = historyItem.Group?.Id; } var changes = HistoryService.GetChanges( typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_GROUP_MEMBERSHIP.AsGuid(), personId, historyItem.PersonHistoryChangeList, historyItem.Caption, typeof(Group), historyItem.GroupId, Entity.ModifiedByPersonAliasId, rockContext.SourceOfChange); if (changes.Any()) { Task.Run(async() => { // Wait 1 second to allow all post save actions to complete await Task.Delay(1000); try { using (var insertRockContext = new RockContext()) { insertRockContext.BulkInsert(changes); } } catch (SystemException ex) { ExceptionLogService.LogException(ex, null); } }); } var groupMemberChanges = HistoryService.GetChanges( typeof(GroupMember), Rock.SystemGuid.Category.HISTORY_GROUP_CHANGES.AsGuid(), Entity.Id, historyItem.GroupMemberHistoryChangeList, historyItem.Caption, typeof(Group), historyItem.GroupId, Entity.ModifiedByPersonAliasId, rockContext.SourceOfChange); if (groupMemberChanges.Any()) { Task.Run(async() => { // Wait 1 second to allow all post save actions to complete await Task.Delay(1000); try { using (var insertRockContext = new RockContext()) { insertRockContext.BulkInsert(groupMemberChanges); } } catch (SystemException ex) { ExceptionLogService.LogException(ex, null); } }); } } } base.PostSave(); // if this is a GroupMember record on a Family, ensure that AgeClassification, PrimaryFamily, // GivingLeadId, and GroupSalution is updated // NOTE: This is also done on Person.PostSaveChanges in case Birthdate changes var groupTypeFamilyRoleIds = GroupTypeCache.GetFamilyGroupType()?.Roles?.Select(a => a.Id).ToList(); if (groupTypeFamilyRoleIds?.Any() == true) { if (groupTypeFamilyRoleIds.Contains(Entity.GroupRoleId)) { PersonService.UpdatePersonAgeClassification(Entity.PersonId, rockContext); PersonService.UpdatePrimaryFamily(Entity.PersonId, rockContext); PersonService.UpdateGivingLeaderId(Entity.PersonId, rockContext); GroupService.UpdateGroupSalutations(Entity.GroupId, rockContext); if (_preSaveChangesOldGroupId.HasValue && _preSaveChangesOldGroupId.Value != Entity.GroupId) { // if person was moved to a different family, the old family will need its GroupSalutations updated GroupService.UpdateGroupSalutations(_preSaveChangesOldGroupId.Value, rockContext); } } } if (State == EntityContextState.Added || State == EntityContextState.Modified) { if (Entity.Group != null && Entity.Person != null) { if (Entity.Group?.IsSecurityRoleOrSecurityGroupType() == true) { /* 09/27/2021 MDP * * If this GroupMember record results in making this Person having a higher AccountProtectionProfile level, * update the Person's AccountProtectionProfile. * Note: If this GroupMember record could result in making this Person having a *lower* AccountProtectionProfile level, * don't lower the AccountProtectionProfile here, because other rules have to be considered before * lowering the AccountProtectionProfile level. So we'll let the RockCleanup job take care of making sure the * AccountProtectionProfile is updated after factoring in all the rules. * */ if (Entity.Group.ElevatedSecurityLevel >= Utility.Enums.ElevatedSecurityLevel.Extreme && Entity.Person.AccountProtectionProfile < Utility.Enums.AccountProtectionProfile.Extreme) { Entity.Person.AccountProtectionProfile = Utility.Enums.AccountProtectionProfile.Extreme; rockContext.SaveChanges(); } else if (Entity.Group.ElevatedSecurityLevel >= Utility.Enums.ElevatedSecurityLevel.High && Entity.Person.AccountProtectionProfile < Utility.Enums.AccountProtectionProfile.High) { Entity.Person.AccountProtectionProfile = Utility.Enums.AccountProtectionProfile.High; rockContext.SaveChanges(); } } } } }
/// <summary> /// Recursively logs exception and any children. /// </summary> /// <param name="ex">The <see cref="System.Exception"/> to log.</param> /// <param name="log">The parent <see cref="Rock.Model.ExceptionLog"/> of the exception being logged. This value is nullable.</param> /// <param name="isParent">A <see cref="System.Boolean"/> flag indicating if this Exception is a parent exception. This value is /// <c>true</c> if the exception that is being logged is a parent exception, otherwise <c>false</c>. /// </param> private static void LogExceptions( Exception ex, ExceptionLog log, bool isParent ) { // First, attempt to log exception to the database. try { ExceptionLog exceptionLog; // If this is a recursive call and not the originating exception being logged, // attempt to clone the initial one, and populate it with Exception Type and Message // from the inner exception, while retaining the contextual information from where // the exception originated. if ( !isParent ) { exceptionLog = log.Clone( false ); if ( exceptionLog != null ) { // Populate with inner exception type, message and update whether or not there is another inner exception. exceptionLog.ExceptionType = ex.GetType().ToString(); exceptionLog.Description = ex.Message; exceptionLog.Source = ex.Source; exceptionLog.StackTrace = ex.StackTrace; exceptionLog.HasInnerException = ex.InnerException != null; // Ensure EF properly recognizes this as a new record. exceptionLog.Id = 0; exceptionLog.Guid = Guid.NewGuid(); exceptionLog.ParentId = log.Id; } } else { exceptionLog = log; } // The only reason this should happen is if the `log.Clone()` operation failed. Compiler sugar. if ( exceptionLog == null ) { return; } // Write ExceptionLog record to database. var rockContext = new Rock.Data.RockContext(); var exceptionLogService = new ExceptionLogService( rockContext ); exceptionLogService.Add( exceptionLog ); rockContext.SaveChanges(); // Recurse if inner exception is found if ( exceptionLog.HasInnerException.GetValueOrDefault( false ) ) { LogExceptions( ex.InnerException, exceptionLog, false ); } if (ex is AggregateException) { // if an AggregateException occurs, log the exceptions individually var aggregateException = ( ex as AggregateException ); foreach ( var innerException in aggregateException.InnerExceptions ) { LogExceptions( innerException, exceptionLog, false ); } } } catch ( Exception ) { // If logging the exception fails, write the exceptions to a file try { string directory = AppDomain.CurrentDomain.BaseDirectory; directory = Path.Combine( directory, "App_Data", "Logs" ); if ( !Directory.Exists( directory ) ) { Directory.CreateDirectory( directory ); } string filePath = Path.Combine( directory, "RockExceptions.csv" ); string when = RockDateTime.Now.ToString(); while ( ex != null ) { File.AppendAllText( filePath, string.Format( "{0},{1},\"{2}\"\r\n", when, ex.GetType(), ex.Message ) ); ex = ex.InnerException; } } catch { // failed to write to database and also failed to write to log file, so there is nowhere to log this error } } }
/// <summary> /// Called before the save operation is executed. /// </summary> protected override void PreSave() { var rockContext = ( RockContext )this.RockContext; string errorMessage; if (State != EntityContextState.Deleted && Entity.IsArchived == false && Entity.GroupMemberStatus != GroupMemberStatus.Inactive) { if (!Entity.ValidateGroupMembership(rockContext, out errorMessage)) { var ex = new GroupMemberValidationException(errorMessage); ExceptionLogService.LogException(ex); throw ex; } } var updateGroupMemberMsg = new UpdateGroupMember.Message { State = State, GroupId = Entity.GroupId, PersonId = Entity.PersonId, GroupMemberStatus = Entity.GroupMemberStatus, GroupMemberRoleId = Entity.GroupRoleId, IsArchived = Entity.IsArchived }; if (Entity.Group != null) { updateGroupMemberMsg.GroupTypeId = Entity.Group.GroupTypeId; } // If this isn't a new group member, get the previous status and role values if (State == EntityContextState.Modified) { updateGroupMemberMsg.PreviousGroupMemberStatus = ( GroupMemberStatus )OriginalValues[nameof(GroupMember.GroupMemberStatus)].ToStringSafe().ConvertToEnum <GroupMemberStatus>(); updateGroupMemberMsg.PreviousGroupMemberRoleId = OriginalValues[nameof(GroupMember.GroupRoleId)].ToStringSafe().AsInteger(); updateGroupMemberMsg.PreviousIsArchived = OriginalValues[nameof(GroupMember.IsArchived)].ToStringSafe().AsBoolean(); } // If this isn't a deleted group member, get the group member guid if (State != EntityContextState.Deleted) { updateGroupMemberMsg.GroupMemberGuid = Entity.Guid; } updateGroupMemberMsg.Send(); int?oldPersonId = null; int?newPersonId = null; int?oldGroupId = null; int?newGroupId = null; switch (State) { case EntityContextState.Added: { oldPersonId = null; newPersonId = Entity.PersonId; oldGroupId = null; newGroupId = Entity.GroupId; if (!Entity.DateTimeAdded.HasValue) { Entity.DateTimeAdded = RockDateTime.Now; } // if this is a new record, but is saved with IsActive=False, set the InactiveDateTime if it isn't set already if (Entity.GroupMemberStatus == GroupMemberStatus.Inactive) { Entity.InactiveDateTime = Entity.InactiveDateTime ?? RockDateTime.Now; } break; } case EntityContextState.Modified: { oldPersonId = OriginalValues[nameof(GroupMember.PersonId)].ToStringSafe().AsIntegerOrNull(); newPersonId = Entity.PersonId; oldGroupId = OriginalValues[nameof(GroupMember.GroupId)].ToStringSafe().AsIntegerOrNull(); newGroupId = Entity.GroupId; var originalStatus = OriginalValues[nameof(GroupMember.GroupMemberStatus)].ToStringSafe().ConvertToEnum <GroupMemberStatus>(); // IsActive was modified, set the InactiveDateTime if it changed to Inactive, or set it to NULL if it changed to Active if (originalStatus != Entity.GroupMemberStatus) { if (Entity.GroupMemberStatus == GroupMemberStatus.Inactive) { // if the caller didn't already set InactiveDateTime, set it to now Entity.InactiveDateTime = Entity.InactiveDateTime ?? RockDateTime.Now; } else { Entity.InactiveDateTime = null; } } break; } case EntityContextState.Deleted: { oldPersonId = Entity.PersonId; newPersonId = null; oldGroupId = Entity.GroupId; newGroupId = null; break; } } Group group = Entity.Group; if (group == null) { group = new GroupService(rockContext).Get(Entity.GroupId); } if (group != null) { string oldGroupName = group.Name; if (oldGroupId.HasValue && oldGroupId.Value != group.Id) { var oldGroup = new GroupService(rockContext).Get(oldGroupId.Value); if (oldGroup != null) { oldGroupName = oldGroup.Name; } } HistoryChanges = new List <HistoryItem>(); if (newPersonId.HasValue) { HistoryChanges.Add(new HistoryItem() { PersonId = newPersonId.Value, Caption = group.Name, GroupId = group.Id, Group = group }); } if (oldPersonId.HasValue) { HistoryChanges.Add(new HistoryItem() { PersonId = oldPersonId.Value, Caption = oldGroupName, GroupId = oldGroupId }); } if (newPersonId.HasValue && newGroupId.HasValue && (!oldPersonId.HasValue || oldPersonId.Value != newPersonId.Value || !oldGroupId.HasValue || oldGroupId.Value != newGroupId.Value)) { // New Person in group var historyItem = HistoryChanges.First(h => h.PersonId == newPersonId.Value && h.GroupId == newGroupId.Value); historyItem.PersonHistoryChangeList.AddChange(History.HistoryVerb.AddedToGroup, History.HistoryChangeType.Record, $"'{group.Name}' Group"); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Role", ( int? )null, Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Note", string.Empty, Entity.Note); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Status", null, Entity.GroupMemberStatus); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Communication Preference", null, Entity.CommunicationPreference); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Guest Count", ( int? )null, Entity.GuestCount); var addedMemberPerson = Entity.Person ?? new PersonService(rockContext).Get(Entity.PersonId); // add the Person's Name as ValueName and Caption (just in case the groupmember record is deleted later) historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.AddedToGroup, History.HistoryChangeType.Record, $"{addedMemberPerson?.FullName}").SetCaption($"{addedMemberPerson?.FullName}"); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Role", ( int? )null, Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Note", string.Empty, Entity.Note); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Status", null, Entity.GroupMemberStatus); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Communication Preference", null, Entity.CommunicationPreference); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Guest Count", ( int? )null, Entity.GuestCount); } if (newPersonId.HasValue && oldPersonId.HasValue && oldPersonId.Value == newPersonId.Value && newGroupId.HasValue && oldGroupId.HasValue && oldGroupId.Value == newGroupId.Value) { // Updated same person in group var historyItem = HistoryChanges.First(h => h.PersonId == newPersonId.Value && h.GroupId == newGroupId.Value); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Role", OriginalValues["GroupRoleId"].ToStringSafe().AsIntegerOrNull(), Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Note", OriginalValues["Note"].ToStringSafe(), Entity.Note); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Status", OriginalValues["GroupMemberStatus"].ToStringSafe().ConvertToEnum <GroupMemberStatus>(), Entity.GroupMemberStatus); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Communication Preference", OriginalValues["CommunicationPreference"].ToStringSafe().ConvertToEnum <CommunicationType>(), Entity.CommunicationPreference); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Guest Count", OriginalValues["GuestCount"].ToStringSafe().AsIntegerOrNull(), Entity.GuestCount); History.EvaluateChange(historyItem.PersonHistoryChangeList, $"{historyItem.Caption} Archived", OriginalValues["IsArchived"].ToStringSafe().AsBoolean(), Entity.IsArchived); // If the groupmember was Archived, make sure it is the first GroupMember History change (since they get summarized when doing a HistoryLog and Timeline bool origIsArchived = OriginalValues[nameof(GroupMember.IsArchived)].ToStringSafe().AsBoolean(); if (origIsArchived != Entity.IsArchived) { var memberPerson = Entity.Person ?? new PersonService(rockContext).Get(Entity.PersonId); if (Entity.IsArchived == true) { // GroupMember changed to Archived historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.RemovedFromGroup, History.HistoryChangeType.Record, $"{memberPerson?.FullName}").SetCaption($"{memberPerson?.FullName}"); } else { // GroupMember changed to Not archived historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.AddedToGroup, History.HistoryChangeType.Record, $"{memberPerson?.FullName}").SetCaption($"{memberPerson?.FullName}"); } } History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Role", OriginalValues[nameof(GroupMember.GroupRoleId)].ToStringSafe().AsIntegerOrNull(), Entity.GroupRole, Entity.GroupRoleId, rockContext); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Note", OriginalValues[nameof(GroupMember.Note)].ToStringSafe(), Entity.Note); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Status", OriginalValues[nameof(GroupMember.GroupMemberStatus)].ToStringSafe().ConvertToEnum <GroupMemberStatus>(), Entity.GroupMemberStatus); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Communication Preference", OriginalValues[nameof(GroupMember.CommunicationPreference)].ToStringSafe().ConvertToEnum <CommunicationType>(), Entity.CommunicationPreference); History.EvaluateChange(historyItem.GroupMemberHistoryChangeList, $"Guest Count", OriginalValues[nameof(GroupMember.GuestCount)].ToStringSafe().AsIntegerOrNull(), Entity.GuestCount); } if (oldPersonId.HasValue && oldGroupId.HasValue && (!newPersonId.HasValue || newPersonId.Value != oldPersonId.Value || !newGroupId.HasValue || newGroupId.Value != oldGroupId.Value)) { // Removed a person/groupmember in group var historyItem = HistoryChanges.First(h => h.PersonId == oldPersonId.Value && h.GroupId == oldGroupId.Value); historyItem.PersonHistoryChangeList.AddChange(History.HistoryVerb.RemovedFromGroup, History.HistoryChangeType.Record, $"{oldGroupName} Group"); var deletedMemberPerson = Entity.Person ?? new PersonService(rockContext).Get(Entity.PersonId); historyItem.GroupMemberHistoryChangeList.AddChange(History.HistoryVerb.RemovedFromGroup, History.HistoryChangeType.Record, $"{deletedMemberPerson?.FullName}").SetCaption($"{deletedMemberPerson?.FullName}"); } // process universal search indexing if required var groupType = GroupTypeCache.Get(group.GroupTypeId); if (groupType != null && groupType.IsIndexEnabled) { var processEntityTypeIndexMsg = new ProcessEntityTypeIndex.Message { EntityTypeId = groupType.Id, EntityId = group.Id }; processEntityTypeIndexMsg.Send(); } } _preSaveChangesOldGroupId = oldGroupId; base.PreSave(); }
/// <summary> /// Builds the base query for the Exception List grid data /// </summary> /// <returns>IQueryable containing filtered ExceptionLog records</returns> private IQueryable<ExceptionLog> BuildBaseExceptionListQuery( RockContext rockContext ) { ExceptionLogService exceptionLogService = new ExceptionLogService( rockContext ); IQueryable<ExceptionLog> query = exceptionLogService.Queryable(); int siteId; if ( int.TryParse( fExceptionList.GetUserPreference( "Site" ), out siteId ) && siteId > 0 ) { query = query.Where( e => e.SiteId == siteId ); } int pageId; if ( int.TryParse( fExceptionList.GetUserPreference( "Page" ), out pageId ) && pageId > 0 ) { query = query.Where( e => e.PageId == pageId ); } int userPersonID; if ( int.TryParse( fExceptionList.GetUserPreference( "User" ), out userPersonID ) && userPersonID > 0 ) { query = query.Where( e => e.CreatedByPersonAlias != null && e.CreatedByPersonAlias.PersonId == userPersonID ); } string statusCode = fExceptionList.GetUserPreference( "Status Code" ); if ( !String.IsNullOrEmpty( statusCode ) ) { query = query.Where( e => e.StatusCode == statusCode ); } var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( fExceptionList.GetUserPreference( "Date Range" ) ); if ( dateRange.Start.HasValue ) { query = query.Where( e => e.CreatedDateTime.HasValue && e.CreatedDateTime.Value >= dateRange.Start.Value ); } if ( dateRange.End.HasValue ) { query = query.Where( e => e.CreatedDateTime.HasValue && e.CreatedDateTime.Value < dateRange.End.Value ); } //Only look for inner exceptions query = query.Where( e => e.HasInnerException == null || e.HasInnerException == false ); return query; }
/// <summary> /// Shows the detail of the exception /// </summary> /// <param name="itemKey">Item Key (should be ExceptionId in this instance).</param> /// <param name="itemKeyValue">Item key value (should be ExceptionId).</param> public void ShowDetail( string itemKey, int itemKeyValue ) { //if item key is not ExceptionId return if ( !itemKey.Equals( "ExceptionId" ) ) { return; } //Get exception var baseException = new ExceptionLogService().Get( itemKeyValue ); //set fields if ( baseException == null ) { return; } DescriptionList dl = new DescriptionList(); dl.Add( "Site", baseException.Site != null ? baseException.Site.Name : String.Empty, true ); dl.Add( "Page", baseException.Page != null ? string.Format( "{0} <a href=\"{1}\" class=\"btn btn-mini\" target=\"_blank\"><i class=\"fa fa-arrow-right\"></i></a>", baseException.Page.InternalName, baseException.PageUrl ) : String.Empty, true ); //If query string is not empty build query string list if ( !String.IsNullOrWhiteSpace( baseException.QueryString ) ) { dl.Add( "Query String", BuildQueryStringList( baseException.QueryString ) ); } dl.Add( "User", baseException.CreatedByPersonId != null ? baseException.CreatedByPerson.FullName : "Anonymous" ); dl.Add( "Exception Date", string.Format( "{0:g}", baseException.ExceptionDateTime ) ); lExceptionSummary.Text = dl.Html; lCookies.Text = baseException.Cookies; lServerVariables.Text = baseException.ServerVariables; //check to see if Show Cookies attribute is true if( Convert.ToBoolean( GetAttributeValue( "ShowCookies" ) ) ) { //if so check check box and register script to show cookies div chkShowCookies.Checked = true; ScriptManager.RegisterStartupScript( upExcpetionDetail, upExcpetionDetail.GetType(), "ShowCookiesOnLoad" + DateTime.Now.Ticks, "$(\"#divCookies\").css(\"display\", \"inherit\");", true ); } else { chkShowCookies.Checked = false; } //check to see if show server variables attribute is checked if ( Convert.ToBoolean( GetAttributeValue( "ShowServerVariables" ) ) ) { chkShowServerVariables.Checked = true; ScriptManager.RegisterStartupScript( upExcpetionDetail, upExcpetionDetail.GetType(), "ShowServerVariablesOnLoad" + DateTime.Now.Ticks, "$(\"#divServerVariables\").css(\"display\", \"inherit\");", true ); } else { chkShowServerVariables.Checked = false; } rptExcpetionDetails.DataSource = GetExceptionLogs( baseException ).OrderBy( e => e.Id ); rptExcpetionDetails.DataBind(); pnlSummary.Visible = true; }
/// <summary> /// Binds the exception occurrence grid. /// </summary> /// <param name="baseException">Exception to base the occurrence grid off of.</param> private void BindExceptionOccurrenceGrid( ExceptionLog baseException ) { ExceptionLogService exceptionService = new ExceptionLogService( new RockContext() ); var query = exceptionService.Queryable() .Where( e => e.HasInnerException == null || e.HasInnerException == false ) .Where( e => e.SiteId == baseException.SiteId ) .Where( e => e.PageId == baseException.PageId ) .Where( e => e.Description == baseException.Description ) .Select( e => new { Id = e.Id, CreatedDateTime = e.CreatedDateTime, FullName = ( e.CreatedByPersonAlias != null && e.CreatedByPersonAlias.Person != null ) ? e.CreatedByPersonAlias.Person.LastName + ", " + e.CreatedByPersonAlias.Person.NickName : "", Description = e.Description } ).OrderBy(e => e.CreatedDateTime); if ( gExceptionOccurrences.SortProperty == null ) { gExceptionOccurrences.DataSource = query.OrderByDescending( e => e.CreatedDateTime ).ToList(); } else { gExceptionOccurrences.DataSource = query.Sort( gExceptionOccurrences.SortProperty ).ToList(); } gExceptionOccurrences.DataBind(); }
/// <summary> /// Binds the exception occurrence grid. /// </summary> /// <param name="baseException">Exception to base the occurrence grid off of.</param> private void BindExceptionOccurrenceGrid( ExceptionLog baseException ) { ExceptionLogService exceptionService = new ExceptionLogService( new RockContext() ); string url = String.Format( "{0}?ExceptionId=", LinkedPageUrl( "DetailPage" ) ); var query = exceptionService.Queryable() .Where( e => e.HasInnerException == null || e.HasInnerException == false ) .Where( e => e.Description.Substring( 0, 28 ) == baseException.Description.Substring( 0, 28 ) ) .Select( e => new { Id = e.Id, CreatedDateTime = e.CreatedDateTime, PageName = e.Page.InternalName ?? e.PageUrl, FullName = ( e.CreatedByPersonAlias != null && e.CreatedByPersonAlias.Person != null ) ? e.CreatedByPersonAlias.Person.LastName + ", " + e.CreatedByPersonAlias.Person.NickName : "", Description = "<a href='" + url + e.Id + "'>" + e.Description + "</a>" } ).OrderBy( e => e.CreatedDateTime ); if ( gExceptionOccurrences.SortProperty == null ) { query = query.OrderByDescending( e => e.CreatedDateTime ); } else { query = query.Sort( gExceptionOccurrences.SortProperty ); } gExceptionOccurrences.EntityTypeId = EntityTypeCache.Read<ExceptionLog>().Id; gExceptionOccurrences.SetLinqDataSource( query ); gExceptionOccurrences.DataBind(); }
/// <summary> /// Loads the exception occurrences panel /// </summary> /// <param name="exceptionId">The Id of the base exception for the grid</param> private void LoadExceptionOccurrences( int exceptionId ) { //get the base exception ExceptionLogService exceptionService = new ExceptionLogService( new RockContext() ); ExceptionLog exception = exceptionService.Get( exceptionId ); //set the summary fields for the base exception if ( exception != null ) { if ( Page.IsPostBack && Page.IsAsync ) { this.AddHistory( "Exception", exceptionId.ToString(), string.Format( "Exception Occurrences {0}", exception.Description ) ); } hfBaseExceptionID.Value = exceptionId.ToString(); var descriptionList = new Rock.Web.DescriptionList(); // set detail title with formating lDetailTitle.Text = String.Format( "Occurrences of {0}", exception.ExceptionType ).FormatAsHtmlTitle(); if ( !string.IsNullOrEmpty( exception.ExceptionType ) ) { descriptionList.Add( "Type", exception.ExceptionType ); } if ( exception.Site != null ) { descriptionList.Add( "Site", exception.Site.Name ); } if ( exception.Page != null ) { descriptionList.Add( "Page", exception.Page.InternalName ); } lblMainDetails.Text = descriptionList.Html; //Load the occurrences for the selected exception BindExceptionOccurrenceGrid( exception ); } }
/// <summary> /// Pres the save. /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry">The entry.</param> public override void PreSaveChanges(DbContext dbContext, System.Data.Entity.Infrastructure.DbEntityEntry entry) { if (entry.State == System.Data.Entity.EntityState.Deleted) { if (StorageProvider != null) { this.BinaryFileTypeId = entry.OriginalValues["BinaryFileTypeId"].ToString().AsInteger(); try { StorageProvider.DeleteContent(this); } catch (Exception ex) { // If an exception occurred while trying to delete provider's file, log the exception, but continue with the delete. ExceptionLogService.LogException(ex); } this.BinaryFileTypeId = null; } } else { if (BinaryFileType == null && BinaryFileTypeId.HasValue) { BinaryFileType = new BinaryFileTypeService(( RockContext )dbContext).Get(BinaryFileTypeId.Value); } if (this.MimeType.StartsWith("image/")) { try { using (Bitmap bm = new Bitmap(this.ContentStream)) { if (bm != null) { this.Width = bm.Width; this.Height = bm.Height; } } ContentStream.Seek(0, SeekOrigin.Begin); if (!IsTemporary) { if (BinaryFileType.MaxHeight.HasValue && BinaryFileType.MaxHeight != 0 && BinaryFileType.MaxWidth.HasValue && BinaryFileType.MaxWidth != 0) { ResizeSettings settings = new ResizeSettings(); MemoryStream resizedStream = new MemoryStream(); if (BinaryFileType.MaxWidth.Value < Width || BinaryFileType.MaxHeight < Height) { settings.Add("mode", "max"); if (BinaryFileType.MaxHeight < Height && BinaryFileType.MaxWidth < Width) { if (BinaryFileType.MaxHeight >= BinaryFileType.MaxWidth) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } if (BinaryFileType.MaxHeight <= BinaryFileType.MaxWidth) { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } } else if (BinaryFileType.MaxHeight < Height) { settings.Add("height", BinaryFileType.MaxHeight.Value.ToString()); } else { settings.Add("width", BinaryFileType.MaxWidth.Value.ToString()); } ImageBuilder.Current.Build(this.ContentStream, resizedStream, settings); ContentStream = resizedStream; using (Bitmap bm = new Bitmap(this.ContentStream)) { if (bm != null) { this.Width = bm.Width; this.Height = bm.Height; } } } } } } catch (Exception) { } // if the file is an invalid photo keep moving } if (entry.State == System.Data.Entity.EntityState.Added) { // when a file is saved (unless it is getting Deleted/Saved), it should use the StoredEntityType that is associated with the BinaryFileType if (BinaryFileType != null) { // Persist the storage type StorageEntityTypeId = BinaryFileType.StorageEntityTypeId; // Persist the storage type's settings specific to this binary file type var settings = new Dictionary <string, string>(); if (BinaryFileType.Attributes == null) { BinaryFileType.LoadAttributes(); } foreach (var attributeValue in BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } StorageEntitySettings = settings.ToJson(); if (StorageProvider != null) { // save the file to the provider's new storage medium, and if the medium returns a filesize, save that value. long?outFileSize = null; StorageProvider.SaveContent(this, out outFileSize); if (outFileSize.HasValue) { FileSize = outFileSize; } Path = StorageProvider.GetPath(this); } } } else if (entry.State == System.Data.Entity.EntityState.Modified) { // when a file is saved (unless it is getting Deleted/Added), // it should use the StorageEntityType that is associated with the BinaryFileType if (BinaryFileType != null) { // if the storage provider changed, or any of its settings specific // to the binary file type changed, delete the original provider's content if (StorageEntityTypeId.HasValue && BinaryFileType.StorageEntityTypeId.HasValue) { var settings = new Dictionary <string, string>(); if (BinaryFileType.Attributes == null) { BinaryFileType.LoadAttributes(); } foreach (var attributeValue in BinaryFileType.AttributeValues) { settings.Add(attributeValue.Key, attributeValue.Value.Value); } string settingsJson = settings.ToJson(); if (StorageProvider != null && ( StorageEntityTypeId.Value != BinaryFileType.StorageEntityTypeId.Value || StorageEntitySettings != settingsJson)) { var ms = new MemoryStream(); ContentStream.Position = 0; ContentStream.CopyTo(ms); ContentStream.Dispose(); // Delete the current provider's storage StorageProvider.DeleteContent(this); // Set the new storage provider with its settings StorageEntityTypeId = BinaryFileType.StorageEntityTypeId; StorageEntitySettings = settingsJson; ContentStream = new MemoryStream(); ms.Position = 0; ms.CopyTo(ContentStream); ContentStream.Position = 0; FileSize = ContentStream.Length; } } } if (_contentIsDirty && StorageProvider != null) { long?fileSize = null; StorageProvider.SaveContent(this, out fileSize); FileSize = fileSize; Path = StorageProvider.GetPath(this); } } } base.PreSaveChanges(dbContext, entry); }