/// <summary>
 /// Construct a processed callstack.
 /// </summary>
 /// <param name="CurrentCrash"></param>
 public CallStackContainer( Crash CurrentCrash )
 {
     using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")" ) )
     {
         ParseCallStack( CurrentCrash );
     }
 }
        /// <summary>
        /// Add a crash passed in the payload as Xml to the database.
        /// </summary>
        /// <param name="id">Unused.</param>
        /// <returns>The row id of the newly added crash.</returns>
        public ActionResult AddCrash( int id )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(NewCrashId=" + id + ")" ) )
            {
                CrashRepository Crashes = new CrashRepository();

                CrashReporterResult NewCrashResult = new CrashReporterResult();
                NewCrashResult.ID = -1;

                try
                {
                    using( StreamReader Reader = new StreamReader( Request.InputStream, Request.ContentEncoding ) )
                    {
                        string Result = Reader.ReadToEnd();
                        CrashDescription NewCrash = XmlHandler.FromXmlString<CrashDescription>( Result );
                        NewCrashResult.ID = Crashes.AddNewCrash( NewCrash );
                        NewCrashResult.bSuccess = true;
                    }
                }
                catch( Exception Ex )
                {
                    NewCrashResult.Message = Ex.ToString();
                    NewCrashResult.bSuccess = false;
                }

                string ReturnResult = XmlHandler.ToXmlString<CrashReporterResult>( NewCrashResult );
                return Content( ReturnResult, "text/xml" );
            }
        }
		/// <summary>
		/// Return a dictionary of crashes per group grouped by week.
		/// </summary>
		/// <param name="Crashes">A set of crashes to interrogate.</param>
		/// <param name="UserGroupId">The id of the user group to interrogate.</param>
		/// <returns>A dictionary of week vs. crash count.</returns>
		public Dictionary<DateTime, int> GetWeeklyCountsByGroup( List<FCrashMinimal> Crashes, int UserGroupId )
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(UserGroupId=" + UserGroupId + ")" ) )
			{
				Dictionary<DateTime, int> Results = new Dictionary<DateTime, int>();

			    var UsersIds = new HashSet<int>(_entities.Users.Distinct().Select(data => data.Id));

				// Trim crashes to user group.
				if( UserGroupId != DashboardController.AllUserGroupId )
				{
					Crashes = Crashes.Where( Crash => UsersIds.Contains( Crash.UserId ) ).ToList();
				}

				try
				{
					Results =
					(
						from CrashDetail in Crashes
						group CrashDetail by CrashDetail.TimeOfCrash.AddDays( -(int)CrashDetail.TimeOfCrash.DayOfWeek ).Date into GroupCount
						orderby GroupCount.Key
						select new { Count = GroupCount.Count(), Date = GroupCount.Key }
					).ToDictionary( x => x.Date, y => y.Count );
				}
				catch( Exception Ex )
				{
					Debug.WriteLine( "Exception in GetWeeklyCountsByGroup: " + Ex.ToString() );
				}

				return Results;
			}
		}
Exemple #4
0
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public EntitySet<Crash> GetCrashes()
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
            {
                int CrashCount = Crashes.Count;
                if( NumberOfCrashes != CrashCount )
                {
                    NumberOfCrashes = CrashCount;

                    if( NumberOfCrashes > 0 )
                    {
                        BuggRepository LocalBuggRepository = new BuggRepository();
                        LocalBuggRepository.UpdateBuggData( this, Crashes );
                    }
                }

                // Just fill the CallStackContainers
                foreach( Crash CurrentCrash in Crashes )
                {
                    if( CurrentCrash.CallStackContainer == null )
                    {
                        CurrentCrash.CallStackContainer = CurrentCrash.GetCallStack();
                    }

                    if( SourceContext == null )
                    {
                        SourceContext = CurrentCrash.SourceContext;
                    }
                }

                return Crashes;
            }
        }
Exemple #5
0
		/// <summary>
		/// The Index action.
		/// </summary>
		/// <param name="BuggsForm">The form of user data passed up from the client.</param>
		/// <returns>The view to display a list of Buggs on the client.</returns>
		public ActionResult Index( FormCollection BuggsForm )
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
			{
				FormHelper FormData = new FormHelper( Request, BuggsForm, "CrashesInTimeFrameGroup" );
				BuggsViewModel Results = LocalBuggRepository.GetResults( FormData );
				return View( "Index", Results );
			}
		}
 /// <summary>
 /// The main view of the home page.
 /// </summary>
 public ActionResult Index()
 {
     using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ))
     {
         CrashesViewModel Result = new CrashesViewModel();
         Result.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
         return View( "Index", Result );
     }
 }
Exemple #7
0
		/// <summary>
		/// Create html with links to represent last page, next page, current page etc.
		/// </summary>
		/// <param name="Html">The html document writer for the current page.</param>
		/// <param name="WebPagingInfo">Information about the paging of the current page.</param>
		/// <param name="PageUrl">An Url to link to the correct page.</param>
		/// <returns>A string suitable for MVC to render.</returns>
		public static MvcHtmlString PageLinks( this HtmlHelper Html, PagingInfo WebPagingInfo, Func<int, string> PageUrl )
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( "PagingHelper" ) )
			{
				StringBuilder ResultString = new StringBuilder();

				// Go to first page
				TagBuilder FirstTag = new TagBuilder( "a" ); // Construct an <a> Tag
				FirstTag.MergeAttribute( "href", PageUrl( WebPagingInfo.FirstPage ) );
				FirstTag.InnerHtml = "<<";

				ResultString.AppendLine( FirstTag.ToString() );

				// Go to previous page
				TagBuilder PreviousTag = new TagBuilder( "a" ); // Construct an <a> Tag
				PreviousTag.MergeAttribute( "href", PageUrl( WebPagingInfo.PreviousPageIndex ) );
				PreviousTag.InnerHtml = "<";

				ResultString.AppendLine( PreviousTag.ToString() );

				for( int PageIndex = WebPagingInfo.FirstPageIndex; PageIndex <= WebPagingInfo.LastPageIndex; PageIndex++ )
				{
					TagBuilder Tag = new TagBuilder( "a" ); // Construct an <a> Tag
					Tag.MergeAttribute( "href", PageUrl( PageIndex ) );
					Tag.InnerHtml = PageIndex.ToString();
					if( PageIndex == WebPagingInfo.CurrentPage )
					{
						Tag.AddCssClass( "selectedPage" );
					}

					ResultString.AppendLine( Tag.ToString() );
				}

				// Go to next page
				TagBuilder NextTag = new TagBuilder( "a" ); // Construct an <a> Tag
				NextTag.MergeAttribute( "href", PageUrl( WebPagingInfo.NextPageIndex ) );
				NextTag.InnerHtml = ">";

				ResultString.AppendLine( NextTag.ToString() );

				// Go to last page
				TagBuilder LastTag = new TagBuilder( "a" ); // Construct an <a> Tag
				LastTag.MergeAttribute( "href", PageUrl( WebPagingInfo.LastPage ) );
				LastTag.InnerHtml = ">>";

				ResultString.AppendLine( LastTag.ToString() );

				return MvcHtmlString.Create( ResultString.ToString() );
			}
		}
		/// <summary>
		/// Display a summary list of crashes based on the search criteria.
		/// </summary>
		/// <param name="crashesForm">A form of user data passed up from the client.</param>
		/// <returns>A view to display a list of crash reports.</returns>
		public ActionResult Index( FormCollection crashesForm )
		{
            using( var logTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ) )
			{
				// Handle any edits made in the Set form fields
				foreach( var Entry in crashesForm )
				{
					int Id = 0;
					if( int.TryParse( Entry.ToString(), out Id ) )
					{
                        Crash currentCrash = _unitOfWork.CrashRepository.GetById(Id);
						if( currentCrash != null )
						{
							if( !string.IsNullOrEmpty( crashesForm["SetStatus"] ) )
							{
								currentCrash.Status = crashesForm["SetStatus"];
							}

							if( !string.IsNullOrEmpty( crashesForm["SetFixedIn"] ) )
							{
								currentCrash.FixedChangeList = crashesForm["SetFixedIn"];
							}

							if( !string.IsNullOrEmpty( crashesForm["SetTTP"] ) )
							{
								currentCrash.Jira = crashesForm["SetTTP"];
							}
						}
					}

				    _unitOfWork.Save();
				}

				// <STATUS>

				// Parse the contents of the query string, and populate the form
				var formData = new FormHelper( Request, crashesForm, "TimeOfCrash" );
				var result = GetResults( formData );
                result.BranchNames = _unitOfWork.CrashRepository.GetBranchesAsListItems();
                result.VersionNames = _unitOfWork.CrashRepository.GetVersionsAsListItems();
                result.PlatformNames = _unitOfWork.CrashRepository.GetPlatformsAsListItems();
                result.EngineModes = _unitOfWork.CrashRepository.GetEngineModesAsListItems();
                result.EngineVersions = _unitOfWork.CrashRepository.GetEngineVersionsAsListItems();

				// Add the FromCollection to the CrashesViewModel since we don't need it for the get results function but we do want to post it back to the page.
				result.FormCollection = crashesForm;
				result.GenerationTime = logTimer.GetElapsedSeconds().ToString( "F2" );
				return View( "Index", result );
			}
		}
		/// <summary>
		/// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache.
		/// </summary>
		/// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param>
		/// <returns>A parsed callstack.</returns>
		public DataModels.CallStackContainer GetCallStackFast( DataModels.Crash CurrentCrash )
		{
			using( var logTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")" ) )
			{
				var key = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id;
				var callStack = (CallStackContainer)CacheInstance[key];
			    if (callStack != null) return callStack;
			    callStack = new CallStackContainer( CurrentCrash );
			    callStack.bDisplayFunctionNames = true;
			    CacheInstance.Insert( key, callStack );

			    return callStack;
			}
		}
		/// <summary>
		/// The main view of the home page.
		/// </summary>
		public ActionResult Index()
		{
            using (var logTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ))
			{
				var result = new CrashesViewModel();
                result.BranchNames = _unitOfWork.CrashRepository.GetBranchesAsListItems();
                result.VersionNames = _unitOfWork.CrashRepository.GetVersionsAsListItems();
                result.PlatformNames = _unitOfWork.CrashRepository.GetPlatformsAsListItems();
                result.EngineModes = _unitOfWork.CrashRepository.GetEngineModesAsListItems();
                result.EngineVersions = _unitOfWork.CrashRepository.GetEngineVersionsAsListItems();
				result.GenerationTime = logTimer.GetElapsedSeconds().ToString( "F2" );
				return View( "Index", result );
			}
		}
        /// <summary>
        /// Retrieve a cached (and pre-parsed) callstack container from the cache, or parse the raw callstack, and add to the cache.
        /// </summary>
        /// <param name="CurrentCrash">The crash to retrieve the parsed callstack for.</param>
        /// <returns>A parsed callstack.</returns>
        public CallStackContainer GetCallStackFast( Crash CurrentCrash )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(CrashId=" + CurrentCrash.Id + ")" ) )
            {
                string Key = CacheKeyPrefix + CallstackKeyPrefix + CurrentCrash.Id;
                CallStackContainer CallStack = (CallStackContainer)CacheInstance[Key];
                if( CallStack == null )
                {
                    CallStack = new CallStackContainer( CurrentCrash );
                    CallStack.bDisplayFunctionNames = true;
                    CacheInstance.Insert( Key, CallStack );
                }

                return CallStack;
            }
        }
        /// <summary>
        /// Display a summary list of crashes based on the search criteria.
        /// </summary>
        /// <param name="CrashesForm">A form of user data passed up from the client.</param>
        /// <returns>A view to display a list of crash reports.</returns>
        public ActionResult Index( FormCollection CrashesForm )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ) )
            {
                CrashRepository Crashes = new CrashRepository();

                // Handle any edits made in the Set form fields
                foreach( var Entry in CrashesForm )
                {
                    int Id = 0;
                    if( int.TryParse( Entry.ToString(), out Id ) )
                    {
                        Crash CurrentCrash = Crashes.GetCrash( Id );
                        if( CurrentCrash != null )
                        {
                            if( !string.IsNullOrEmpty( CrashesForm["SetStatus"] ) )
                            {
                                CurrentCrash.Status = CrashesForm["SetStatus"];
                            }

                            if( !string.IsNullOrEmpty( CrashesForm["SetFixedIn"] ) )
                            {
                                CurrentCrash.FixedChangeList = CrashesForm["SetFixedIn"];
                            }

                            if( !string.IsNullOrEmpty( CrashesForm["SetTTP"] ) )
                            {
                                CurrentCrash.Jira = CrashesForm["SetTTP"];
                            }
                        }
                    }

                    Crashes.SubmitChanges();
                }

                // <STATUS>

                // Parse the contents of the query string, and populate the form
                FormHelper FormData = new FormHelper( Request, CrashesForm, "TimeOfCrash" );
                CrashesViewModel Result = Crashes.GetResults( FormData );

                // Add the FromCollection to the CrashesViewModel since we don't need it for the get results function but we do want to post it back to the page.
                Result.FormCollection = CrashesForm;
                Result.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Index", Result );
            }
        }
        /*
        /// <summary>
        /// The empty view of the buggs page.
        /// </summary>
        ///
        public ActionResult Index()
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ))
            {
                BuggsViewModel Results = new BuggsViewModel();
                Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Index", Results );
            }
        }*/
        /// <summary>
        /// The Index action.
        /// </summary>
        /// <param name="BuggsForm">The form of user data passed up from the client.</param>
        /// <returns>The view to display a list of Buggs on the client.</returns>
        public ActionResult Index( FormCollection BuggsForm )
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ))
            {
                BuggRepository Buggs = new BuggRepository();

                FormHelper FormData = new FormHelper( Request, BuggsForm, "CrashesInTimeFrameGroup" );
                BuggsViewModel Results = Buggs.GetResults( FormData );
                foreach (var Bugg in Results.Results)
                {
                    // Populate function calls.
                    Bugg.GetFunctionCalls();
                }
                Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
                return View( "Index", Results );
            }
        }
        /// <summary>
        /// Sets the JIRA for all crashes in a Bugg.
        /// </summary>
        /// <param name="JIRA">A string representing a TTP.</param>
        /// <param name="BuggId">The id of the Bugg to update the crashes for.</param>
        public void SetJIRAForBuggAndCrashes(string JIRA, int BuggId)
        {
            try
            {
                using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer("SetJIRAForBuggAndCrashes (" + BuggId + ")"))
                {
                    string Query = "UPDATE Crashes SET TTPID = {0} WHERE Id IN ( SELECT CrashId FROM Buggs_Crashes WHERE BuggId = {1} )";
                    Context.ExecuteCommand(Query, JIRA, BuggId);

                    Query = "UPDATE Buggs SET TTPID = {0} WHERE id = {1}";
                    Context.ExecuteCommand(Query, JIRA, BuggId);
                }
            }
            catch (Exception Ex)
            {
                FLogger.Global.WriteException("SetBuggTTPID: " + Ex.ToString());
            }
        }
        /// <summary>
        /// Filter a set of Buggs to a date range.
        /// </summary>
        /// <param name="Results">The unfiltered set of Buggs.</param>
        /// <param name="DateFrom">The earliest date to filter by.</param>
        /// <param name="DateTo">The latest date to filter by.</param>
        /// <returns>The set of Buggs between the earliest and latest date.</returns>
        public IEnumerable <Bugg> FilterByDate(IQueryable <Bugg> Results, DateTime DateFrom, DateTime DateTo)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + " SQL"))
            {
                var DateTo1 = DateTo.AddDays(1);

                IQueryable <Bugg> BuggsInTimeFrame = Results
                                                     .Where(Bugg =>
                                                            (Bugg.TimeOfFirstCrash <= DateFrom && Bugg.TimeOfLastCrash >= DateTo1) ||
                                                            (Bugg.TimeOfFirstCrash >= DateFrom && Bugg.TimeOfLastCrash <= DateTo1) ||
                                                            (Bugg.TimeOfFirstCrash >= DateFrom && Bugg.TimeOfFirstCrash <= DateTo1 && Bugg.TimeOfLastCrash >= DateTo1) ||
                                                            (Bugg.TimeOfFirstCrash <= DateFrom && Bugg.TimeOfLastCrash <= DateTo1 && Bugg.TimeOfLastCrash >= DateFrom)
                                                            );

                IEnumerable <Bugg> BuggsInTimeFrameEnumerable = BuggsInTimeFrame.ToList();
                return(BuggsInTimeFrameEnumerable);
            }
        }
Exemple #16
0
		/// <summary>
		/// Sets the JIRA for all crashes in a Bugg.
		/// </summary>
		/// <param name="JIRA">A string representing a TTP.</param>
		/// <param name="BuggId">The id of the Bugg to update the crashes for.</param>
		public static void SetJIRAForBuggAndCrashes( string JIRA, int BuggId )
		{
			try
			{
				using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( "SetJIRAForBuggAndCrashes (" + BuggId + ")" ) )
				{
					string Query = "UPDATE Crashes SET TTPID = {0} WHERE Id IN ( SELECT CrashId FROM Buggs_Crashes WHERE BuggId = {1} )";
					Context.ExecuteCommand( Query, JIRA, BuggId );

					Query = "UPDATE Buggs SET TTPID = {0} WHERE id = {1}";
					Context.ExecuteCommand( Query, JIRA, BuggId );
				}
			}
			catch( Exception Ex )
			{
				FLogger.WriteException( "SetBuggTTPID: " + Ex.ToString() );
			}
		}
        /// <summary>
        /// Gets a container of crash counts per user group for the set of crashes passed in.
        /// </summary>
        /// <param name="EnumerableCrashes">The set of crashes to tabulate by user group.</param>
        /// <returns>A dictionary of user group names, and the count of Buggs for each group.</returns>
        public Dictionary <string, int> GetCountsByGroupFromCrashes(IEnumerable <Crash> EnumerableCrashes)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                Dictionary <string, int> Results = new Dictionary <string, int>();

                try
                {
                    var UsersIDsAndGroupIDs = Context.Users.Select(User => new { UserId = User.Id, UserGroupId = User.UserGroupId }).ToList();
                    var UserGroupArray      = Context.UserGroups.ToList();
                    UserGroupArray.Sort((UG1, UG2) => UG1.Name.CompareTo(UG2.Name));

                    // Initialize all groups to 0.
                    foreach (var UserGroup in UserGroupArray)
                    {
                        Results.Add(UserGroup.Name, 0);
                    }

                    Dictionary <int, string> UserIdToGroupName = new Dictionary <int, string>();
                    foreach (var UserIds in UsersIDsAndGroupIDs)
                    {
                        // Find group name for the user id.
                        string UserGroupName = UserGroupArray.Where(UG => UG.Id == UserIds.UserGroupId).First().Name;
                        UserIdToGroupName.Add(UserIds.UserId, UserGroupName);
                    }

                    //Get list of user Ids foreach crash range
                    List <int> UserIdCrashes = EnumerableCrashes.Select(Crash => Crash.UserNameId.Value).ToList();

                    //count the number of crashes in each group using the mapping of user id to crash.
                    foreach (int UserId in UserIdCrashes)
                    {
                        string UserGroupName = UserIdToGroupName[UserId];
                        Results[UserGroupName]++;
                    }
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetCountsByGroupFromCrashes: " + Ex.ToString());
                }

                return(Results);
            }
        }
        /// <summary>
        /// Retrieves a list of distinct UE4 Versions from the CrashRepository
        /// </summary>
        public static List <SelectListItem> GetVersionsAsListItems()
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer("CrashRepository.GetVersions"))
            {
                CrashReportDataContext Context = new CrashReportDataContext();
                DateTime Now = DateTime.UtcNow;

                if (Now - LastVersionDate > TimeSpan.FromHours(1))
                {
                    var BuildVersions = Context.Crashes
                                        .Where(c => c.TimeOfCrash > DateTime.Now.AddDays(-14))
                                        .Where(c => c.CrashType != 3) // Ignore ensures
                                        .Select(c => c.BuildVersion)
                                        .Distinct()
                                        .ToList();

                    DistinctBuildVersions = new HashSet <string>();

                    foreach (var BuildVersion in BuildVersions)
                    {
                        var BVParts = BuildVersion.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                        if (BVParts.Length > 2 && BVParts[0] != "0")
                        {
                            string CleanBV = string.Format("{0}.{1}.{2}", BVParts[0], BVParts[1], BVParts[2]);
                            DistinctBuildVersions.Add(CleanBV);
                        }
                    }


                    VersionsAsSelectList = DistinctBuildVersions
                                           .Select(listitem => new SelectListItem {
                        Selected = false, Text = listitem, Value = listitem
                    })
                                           .ToList();
                    VersionsAsSelectList.Insert(0, new SelectListItem {
                        Selected = true, Text = "", Value = ""
                    });

                    LastVersionDate = Now;
                }

                return(VersionsAsSelectList);
            }
        }
        /// <summary>
        /// Apply a dynamic query to a set of results.
        /// </summary>
        /// <param name="Results">The initial set of results.</param>
        /// <param name="Query">The query to apply.</param>
        /// <returns>A set of results filtered by the query.</returns>
        public IEnumerable <Crash> Search(IEnumerable <Crash> Results, string Query)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Query=" + Query + ")"))
            {
                IEnumerable <Crash> Crashes = null;
                var IntermediateQueryable   = Results.AsQueryable();
                try
                {
                    string[] Terms = Query.Split("-, ;+".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

                    // Iterate over all crashes.
                    // Brute force search.
                    foreach (string Term in Terms)
                    {
                        Results = Results.Where(X =>

                                                (!string.IsNullOrEmpty(X.BuiltFromCL) ? X.BuiltFromCL.ToLower().Contains(Term) : false) ||
                                                (!string.IsNullOrEmpty(X.PlatformName) ? X.PlatformName.ToLower().Contains(Term) : false) ||
                                                (!string.IsNullOrEmpty(X.Summary) ? X.Summary.ToLower().Contains(Term) : false) ||
                                                (!string.IsNullOrEmpty(X.Description) ? X.Description.ToLower().Contains(Term) : false) ||
                                                (!string.IsNullOrEmpty(X.RawCallStack) ? X.RawCallStack.ToLower().Contains(Term) : false) ||
                                                (!string.IsNullOrEmpty(X.CommandLine) ? X.CommandLine.ToLower().Contains(Term) : false) ||
                                                (!string.IsNullOrEmpty(X.MachineId) ? X.MachineId.ToLower().Contains(Term) : false) ||

                                                (!string.IsNullOrEmpty(X.Module) ? X.Module.ToLower().Contains(Term) : false) ||

                                                (!string.IsNullOrEmpty(X.BaseDir) ? X.BaseDir.ToLower().Contains(Term) : false) ||
                                                (!string.IsNullOrEmpty(X.Jira) ? X.Jira.ToLower().Contains(Term) : false)
                                                );
                    }


                    Crashes = Results;
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in Search: " + Ex.ToString());
                    Crashes = Results;
                }

                return(Crashes);
            }
        }
Exemple #20
0
        /// <summary>
        /// Add a crash passed in the payload as Xml to the database.
        /// </summary>
        /// <param name="id">Unused.</param>
        /// <returns>The row id of the newly added crash.</returns>
        public ActionResult AddCrash(int id)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(NewCrashId=" + id + ")"))
            {
                CrashRepository Crashes = new CrashRepository();

                CrashReporterResult NewCrashResult = new CrashReporterResult();
                NewCrashResult.ID = -1;

                for (int Index = 0; Index < 3; Index++)
                {
                    try
                    {
                        UnsafeAddCrash(NewCrashResult, Crashes);
                        break;
                    }
                    catch (SqlException SqlExc)
                    {
                        if (SqlExc.Number == -2)
                        {
                            FLogger.Global.WriteEvent(string.Format("AddCrash:Timeout, retrying {0} of 3", Index + 1));
                        }
                        else
                        {
                            NewCrashResult.Message  = SqlExc.ToString();
                            NewCrashResult.bSuccess = false;
                            break;
                        }
                    }
                    catch (Exception Ex)
                    {
                        NewCrashResult.Message  = Ex.ToString();
                        NewCrashResult.bSuccess = false;
                        break;
                    }
                    System.Threading.Thread.Sleep(5000 * (Index + 1));
                }

                string ReturnResult = XmlHandler.ToXmlString <CrashReporterResult>(NewCrashResult);
                return(Content(ReturnResult, "text/xml"));
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <returns></returns>
        public List <SelectListItem> GetBranchesAsListItems()
        {
            var branchesAsSelectList = cache["branches"] as List <SelectListItem>;

            if (branchesAsSelectList == null)
            {
                using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer("CrashRepository.GetBranches"))
                {
                    var date = DateTime.Now.AddDays(-14);

                    var BranchList = _entityContext.Crashes
                                     .Where(n => n.TimeOfCrash > date)
                                     .Where(c => c.CrashType != 3) // Ignore ensures
                                                                   // Depot - //depot/UE4* || Stream //UE4, //Something etc.
                                     .Where(n => n.Branch.StartsWith("UE4") || n.Branch.StartsWith("//"))
                                     .Select(n => n.Branch)
                                     .Distinct()
                                     .ToList();

                    branchesAsSelectList =
                        BranchList
                        .Select(listItem => new SelectListItem {
                        Selected = false, Text = listItem, Value = listItem
                    })
                        .OrderBy(listItem => listItem.Text)
                        .ToList();

                    branchesAsSelectList.Insert(0, new SelectListItem {
                        Selected = true, Text = "", Value = ""
                    });
                }

                var searchFilterCachePolicy = new CacheItemPolicy()
                {
                    AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(Settings.Default.SearchFilterCacheInMinutes)
                };
                cache.Set("branches", branchesAsSelectList, searchFilterCachePolicy);
            }

            return(branchesAsSelectList);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="ReportsForm"></param>
        /// <returns></returns>
        public ActionResult Index(FormCollection ReportsForm)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                FormHelper FormData = new FormHelper(Request, ReportsForm, "JustReport");

                // Handle 'CopyToJira' button
                int BuggIDToBeAddedToJira = 0;
                foreach (var Entry in ReportsForm)
                {
                    if (int.TryParse(Entry.ToString(), out BuggIDToBeAddedToJira))
                    {
                        break;
                    }
                }

                ReportsViewModel Results = GetResults(FormData, BuggIDToBeAddedToJira);
                Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2");
                return(View("Index", Results));
            }
        }
Exemple #23
0
        /// <summary>
        /// Gets a container of crash counts per user group for all crashes.
        /// </summary>
        /// <returns>A dictionary of user group names, and the count of crashes for each group.</returns>
        public Dictionary <string, int> GetCountsByGroup()
        {
            // @TODO 2014-11-06 Optimize?
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + " SQL OPT"))
            {
                Dictionary <string, int> Results = new Dictionary <string, int>();

                try
                {
                    var GroupCounts =
                        (
                            from UserDetail in Context.Users
                            join UserGroupDetail in Context.UserGroups on UserDetail.UserGroupId equals UserGroupDetail.Id
                            group UserDetail by UserGroupDetail.Name into GroupCount
                            select new { Key = GroupCount.Key, Count = GroupCount.Count() }
                        );

                    foreach (var GroupCount in GroupCounts)
                    {
                        Results.Add(GroupCount.Key, GroupCount.Count);
                    }

                    // Add in all groups, even though there are no crashes associated
                    IEnumerable <string> UserGroups = (from UserGroupDetail in Context.UserGroups select UserGroupDetail.Name);
                    foreach (string UserGroupName in UserGroups)
                    {
                        if (!Results.Keys.Contains(UserGroupName))
                        {
                            Results[UserGroupName] = 0;
                        }
                    }
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetCountsByGroup: " + Ex.ToString());
                }

                return(Results);
            }
        }
		/// <summary>
		/// Get a report with the default form data and return the reports index view
		/// </summary>
		/// <param name="ReportsForm"></param>
		/// <returns></returns>
		public ActionResult Index( FormCollection ReportsForm )
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ) )
			{
				FormHelper FormData = new FormHelper( Request, ReportsForm, "JustReport" );

				// Handle 'CopyToJira' button
				int BuggIDToBeAddedToJira = 0;
				foreach( var Entry in ReportsForm )
				{
                    if (Entry.ToString().Contains("CopyToJira-"))
					{
                        int.TryParse(Entry.ToString().Substring("CopyToJira-".Length), out BuggIDToBeAddedToJira);
						break;
					}
				}
                
				var results = GetResults( FormData, BuggIDToBeAddedToJira );
				results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
				return View( "Index", results );
			}
		}
Exemple #25
0
        /// <summary>
        /// Return to the index view with a report for a specific branch
        /// </summary>
        /// <param name="ReportsForm"></param>
        /// <returns></returns>
        public ActionResult BranchReport(FormCollection ReportsForm)
        {
            using (var logTimer = new FAutoScopedLogTimer(this.GetType().ToString(), bCreateNewLog: true))
            {
                var formData = new FormHelper(Request, ReportsForm, "JustReport");

                var buggIdToBeAddedToJira = 0;
                // Handle 'CopyToJira' button
                foreach (var Entry in ReportsForm)
                {
                    if (Entry.ToString().Contains("CopyToJira-"))
                    {
                        int.TryParse(Entry.ToString().Substring("CopyToJira-".Length), out buggIdToBeAddedToJira);
                        break;
                    }
                }

                var results = GetResults(formData, buggIdToBeAddedToJira);
                results.GenerationTime = logTimer.GetElapsedSeconds().ToString("F2");
                return(View("Index", results));
            }
        }
Exemple #26
0
        /// <summary>
        /// Retrieves a list of function names from a list of function name ids.
        /// Primarily used to fill GetFunctionCalls in CachedDataService
        /// </summary>
        /// <param name="Ids">A list of unique function name ids.</param>
        /// <returns>A list of strings that make up a callstack.</returns>
        public List <string> GetFunctionCalls(List <int> Ids)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Ids.Count=" + Ids.Count + ")"))
            {
                List <string> FunctionCalls = new List <string>();
                try
                {
                    List <FunctionCall> Funcs = Context.FunctionCalls.Where(FuncCall => Ids.Contains(FuncCall.Id)).ToList();
                    // Order by Ids
                    foreach (int Id in Ids)
                    {
                        var Found = Funcs.Find(FC => FC.Id == Id);
                        FunctionCalls.Add(Found.Call);
                    }
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetFunctionCalls: " + Ex.ToString());
                }

                return(FunctionCalls);
            }
        }
Exemple #27
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="UserGroupId"></param>
        /// <returns></returns>
        public List <string> GetUsersForGroupId(int UserGroupId)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(UserGroupId=" + UserGroupId + ")"))
            {
                List <string> Users = new List <string>();
                try
                {
                    Users =
                        (
                            from UserDetail in Context.Users
                            where UserDetail.UserGroupId == UserGroupId
                            orderby UserDetail.UserName
                            select UserDetail.UserName
                        ).ToList();
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetUsersForGroup: " + Ex.ToString());
                }

                return(Users);
            }
        }
Exemple #28
0
        /// <summary>
        /// Gets the crash from an id.
        /// </summary>
        /// <param name="Id">The id of the crash we wish to examine.</param>
        /// <returns>The crash with the requested id.</returns>
        public Crash GetCrash(int Id)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + Id + ")"))
            {
                try
                {
                    IQueryable <Crash> Crashes =
                        (
                            from CrashDetail in Context.Crashes
                            where CrashDetail.Id == Id
                            select CrashDetail
                        );

                    return(Crashes.FirstOrDefault());
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetCrash: " + Ex.ToString());
                }

                return(null);
            }
        }
Exemple #29
0
        /// <summary>
        /// Get a Bugg from an id
        /// </summary>
        /// <param name="Id">The id of a Bugg.</param>
        /// <returns>A Bugg representing a group of crashes.</returns>
        public Bugg GetBugg(int Id)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(" + Id + ")"))
            {
                Bugg Result = null;

                try
                {
                    Result =
                        (
                            from BuggDetail in Context.Buggs
                            where BuggDetail.Id == Id
                            select BuggDetail
                        ).FirstOrDefault();
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetBugg: " + Ex.ToString());
                }

                return(Result);
            }
        }
Exemple #30
0
        /// <summary>
        /// Bucket the Buggs by user group.
        /// </summary>
        /// <param name="Buggs">A list of Buggs to bucket.</param>
        /// <returns>A dictionary of user group names, and the count of Buggs for each group.</returns>
        public SortedDictionary <string, int> GetCountsByGroup(IEnumerable <Bugg> Buggs)
        {
            // @TODO yrx 2014-11-06 Optimize
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + " SQL OPT"))
            {
                Dictionary <string, int> Results = new Dictionary <string, int>();

                try
                {
                    Results =
                        (
                            from BuggDetail in Buggs
                            join BuggsUserGroupDetail in Context.Buggs_UserGroups on BuggDetail.Id equals BuggsUserGroupDetail.BuggId
                            join UserGroupDetail in Context.UserGroups on BuggsUserGroupDetail.UserGroupId equals UserGroupDetail.Id
                            group 0 by UserGroupDetail.Name into GroupCount
                            select new { Key = GroupCount.Key, Count = GroupCount.Count() }
                        ).ToDictionary(x => x.Key, y => y.Count);

                    // Add in all groups, even though there are no crashes associated
                    IEnumerable <string> UserGroups = (from UserGroupDetail in Context.UserGroups select UserGroupDetail.Name);
                    foreach (string UserGroupName in UserGroups)
                    {
                        if (!Results.Keys.Contains(UserGroupName))
                        {
                            Results[UserGroupName] = 0;
                        }
                    }
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetCountsByGroup: " + Ex.ToString());
                }

                SortedDictionary <string, int> SortedResults = new SortedDictionary <string, int>(Results);
                return(SortedResults);
            }
        }
Exemple #31
0
        /// <summary>
        /// Gets a container of crash counts per user group for the set of crashes passed in.
        /// </summary>
        /// <param name="Crashes">The set of crashes to tabulate by user group.</param>
        /// <returns>A dictionary of user group names, and the count of Buggs for each group.</returns>
        public Dictionary <string, int> GetCountsByGroupFromCrashes(IQueryable <Crash> Crashes)
        {
            // @TODO yrx 2014-11-06 Optimize?
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                Dictionary <string, int> Results = new Dictionary <string, int>();

                try
                {
                    Results =
                        (
                            from CrashDetail in Crashes
                            from UserDetail in CrashRepositoryDataContext.Users
                            join UserGroupDetail in CrashRepositoryDataContext.UserGroups on UserDetail.UserGroupId equals UserGroupDetail.Id
                            where CrashDetail.UserNameId == UserDetail.Id || CrashDetail.UserName == UserDetail.UserName
                            group CrashDetail by UserGroupDetail.Name into GroupCount
                            select new { Key = GroupCount.Key, Count = GroupCount.Count() }
                        ).ToDictionary(x => x.Key, y => y.Count);

                    // Add in all groups, even though there are no crashes associated
                    IEnumerable <string> UserGroups = (from UserGroupDetail in CrashRepositoryDataContext.UserGroups select UserGroupDetail.Name);
                    foreach (string UserGroupName in UserGroups)
                    {
                        if (!Results.Keys.Contains(UserGroupName))
                        {
                            Results[UserGroupName] = 0;
                        }
                    }
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in GetCountsByGroupFromCrashes: " + Ex.ToString());
                }

                return(Results);
            }
        }
        /// <summary>
        /// Retrieve a list of function call names from an encoded pattern. This is either from the cache, or from the database and then added to the cache.
        /// </summary>
        /// <param name="Pattern">A callstack pattern in the form '1+3+34+2'.</param>
        /// <returns>A list of function names.</returns>
        public List <string> GetFunctionCalls(string Pattern)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Count=" + CacheInstance.Count + ")"))
            {
                string        Key           = CacheKeyPrefix + FunctionCallKeyPrefix + Pattern;
                List <string> FunctionCalls = (List <string>)CacheInstance[Key];
                if (FunctionCalls == null)
                {
                    string[]   Ids    = Pattern.Split("+".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    List <int> IdList = new List <int>();
                    foreach (string id in Ids)
                    {
                        int i;
                        if (int.TryParse(id, out i))
                        {
                            IdList.Add(i);
                        }
                    }

                    // These function calls don't add any new information.
                    IdList.Remove(63039);                       // 63039	KERNELBASE!RaiseException()
                    IdList.Remove(63138);                       // 63138	UE4Editor_Core!FDebug::EnsureFailed()
                    IdList.Remove(63137);                       // 63137	UE4Editor_Core!NewReportEnsure()
                    IdList.Remove(63149);                       // 63149	UE4Editor_Core!FOutputDeviceWindowsError::Serialize()
                    IdList.Remove(63151);                       // 63151	UE4Editor_Core!FDebug::AssertFailed()
                    IdList.Remove(63445);                       // 63445	UE4Editor_Core!FDebug::EnsureNotFalseFormatted()
                    IdList.Remove(64334);                       // 64334	UE4Editor_Core!FOutputDevice::Logf__VA()


                    FunctionCalls = BuggRepositoryInstance.GetFunctionCalls(IdList);
                    CacheInstance.Insert(Key, FunctionCalls);
                }

                return(FunctionCalls);
            }
        }
        /// <summary>
        /// Filter the list of Buggs by a search query.
        /// </summary>
        /// <param name="Results">The unfiltered set of Buggs.</param>
        /// <param name="Query">The query to use as a filter.</param>
        /// <returns>A filtered set of Buggs.</returns>
        public IQueryable <Bugg> Search(IQueryable <Bugg> Results, string Query)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(Query=" + Query + ")"))
            {
                // Also may want to revisit how we search since this could get inefficient for a big search set.
                IQueryable <Bugg> Buggs;
                try
                {
                    string QueryString = HttpUtility.HtmlDecode(Query.ToString());
                    if (QueryString == null)
                    {
                        QueryString = "";
                    }

                    // Take out terms starting with a -
                    string[] Terms      = QueryString.Split("-, ;+".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    string   TermsToUse = "";
                    foreach (string Term in Terms)
                    {
                        string CallId = GetFunctionCallId(Term).ToString();
                        if (!TermsToUse.Contains(CallId))
                        {
                            TermsToUse = TermsToUse + "+" + CallId;
                        }
                    }

                    Buggs = (IQueryable <Bugg>)Results.Search(new string[] { "Pattern" }, TermsToUse.Split("+".ToCharArray()));
                }
                catch (Exception Ex)
                {
                    Debug.WriteLine("Exception in Search: " + Ex.ToString());
                    Buggs = Results;
                }
                return(Buggs);
            }
        }
        /// <summary>
        /// Get the id of a function from its name.
        /// </summary>
        /// <param name="FunctionCallName">The name of the function to look up.</param>
        /// <returns>The unique id of the function name, or zero if none is found.</returns>
        public int GetFunctionCallId( string FunctionCallName )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
            {
                try
                {
                    FunctionCall FunctionCall = BuggsDataContext.FunctionCalls.Where( FunctionCallInstance => FunctionCallInstance.Call.Contains( FunctionCallName ) ).First();
                    return FunctionCall.Id;
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in GetFunctionCallId: " + Ex.ToString() );
                }

                return 0;
            }
        }
        /// <summary>
        /// Bucket the Buggs by user group.
        /// </summary>
        /// <param name="Buggs">A list of Buggs to bucket.</param>
        /// <returns>A dictionary of user group names, and the count of Buggs for each group.</returns>
        public Dictionary<string, int> GetCountsByGroup( IQueryable<Bugg> Buggs )
        {
            // @TODO yrx 2014-11-06 Optimize
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
            {
                Dictionary<string, int> Results = new Dictionary<string, int>();

                try
                {
                    Results =
                    (
                        from BuggDetail in Buggs
                        join BuggsUserGroupDetail in BuggsDataContext.Buggs_UserGroups on BuggDetail.Id equals BuggsUserGroupDetail.BuggId
                        join UserGroupDetail in BuggsDataContext.UserGroups on BuggsUserGroupDetail.UserGroupId equals UserGroupDetail.Id
                        group 0 by UserGroupDetail.Name into GroupCount
                        select new { Key = GroupCount.Key, Count = GroupCount.Count() }
                    ).ToDictionary( x => x.Key, y => y.Count );

                    // Add in all groups, even though there are no crashes associated
                    IEnumerable<string> UserGroups = ( from UserGroupDetail in BuggsDataContext.UserGroups select UserGroupDetail.Name );
                    foreach( string UserGroupName in UserGroups )
                    {
                        if( !Results.Keys.Contains( UserGroupName ) )
                        {
                            Results[UserGroupName] = 0;
                        }
                    }
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in GetCountsByGroup: " + Ex.ToString() );
                }

                return Results;
            }
        }
Exemple #36
0
        /// <summary>
        /// Retrieve all Buggs matching the search criteria.
        /// </summary>
        /// <param name="FormData">The incoming form of search criteria from the client.</param>
        /// <param name="BuggIDToBeAddedToJira">ID of the bugg that will be added to JIRA</param>
        /// <returns>A view to display the filtered Buggs.</returns>
        public ReportsViewModel GetResults(FormHelper FormData, int BuggIDToBeAddedToJira)
        {
            BuggRepository  BuggsRepo = new BuggRepository();
            CrashRepository CrashRepo = new CrashRepository();

            // @TODO yrx 2015-02-17 BuggIDToBeAddedToJira replace with List<int> based on check box and Submit?
            // Enumerate JIRA projects if needed.
            // https://jira.ol.epicgames.net//rest/api/2/project
            var JC             = JiraConnection.Get();
            var JiraComponents = JC.GetNameToComponents();
            var JiraVersions   = JC.GetNameToVersions();

            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                string AnonumousGroup = "Anonymous";
                //List<String> Users = FRepository.Get().GetUserNamesFromGroupName( AnonumousGroup );
                int              AnonymousGroupID      = FRepository.Get(BuggsRepo).FindOrAddGroup(AnonumousGroup);
                HashSet <int>    AnonumousIDs          = FRepository.Get(BuggsRepo).GetUserIdsFromUserGroup(AnonumousGroup);
                int              AnonymousID           = AnonumousIDs.First();
                HashSet <string> UserNamesForUserGroup = FRepository.Get(BuggsRepo).GetUserNamesFromGroupName(AnonumousGroup);

                //FormData.DateFrom = DateTime.Now.AddDays( -1 );

                var Crashes = CrashRepo
                              .FilterByDate(CrashRepo.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays(1))
                              // Only crashes and asserts
                              .Where(Crash => Crash.CrashType == 1 || Crash.CrashType == 2)
                              // Only anonymous user
                              .Where(Crash => Crash.UserNameId.Value == AnonymousID)
                              .Select(Crash => new
                {
                    ID          = Crash.Id,
                    TimeOfCrash = Crash.TimeOfCrash.Value,
                    //UserID = Crash.UserNameId.Value,
                    BuildVersion = Crash.BuildVersion,
                    JIRA         = Crash.TTPID,
                    Platform     = Crash.PlatformName,
                    FixCL        = Crash.FixedChangeList,
                    BuiltFromCL  = Crash.ChangeListVersion,
                    Pattern      = Crash.Pattern,
                    MachineID    = Crash.ComputerName,
                    Branch       = Crash.Branch,
                    Description  = Crash.Description,
                    RawCallStack = Crash.RawCallStack,
                })
                              .ToList();
                int NumCrashes = Crashes.Count;

                /*
                 * // Build patterns for crashes where patters is null.
                 * var CrashesWithoutPattern = FRepository.Get().Crashes
                 *      .FilterByDate( FRepository.Get().Crashes.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays( 1 ) )
                 *      // Only crashes and asserts
                 *      .Where( Crash => Crash.Pattern == null || Crash.Pattern == "" )
                 *      .Select( Crash => Crash )
                 *      .ToList();
                 *
                 * foreach( var Crash in CrashesWithoutPattern )
                 * {
                 *      Crash.BuildPattern();
                 * }
                 */

                // Total # of ALL (Anonymous) crashes in timeframe
                int TotalAnonymousCrashes = NumCrashes;

                // Total # of UNIQUE (Anonymous) crashes in timeframe
                HashSet <string>         UniquePatterns = new HashSet <string>();
                HashSet <string>         UniqueMachines = new HashSet <string>();
                Dictionary <string, int> PatternToCount = new Dictionary <string, int>();

                //List<int> CrashesWithoutPattern = new List<int>();
                //List<DateTime> CrashesWithoutPatternDT = new List<DateTime>();

                foreach (var Crash in Crashes)
                {
                    if (string.IsNullOrEmpty(Crash.Pattern))
                    {
                        //CrashesWithoutPattern.Add( Crash.ID );
                        //CrashesWithoutPatternDT.Add( Crash.TimeOfCrash );
                        continue;
                    }

                    UniquePatterns.Add(Crash.Pattern);
                    UniqueMachines.Add(Crash.MachineID);

                    bool bAdd = !PatternToCount.ContainsKey(Crash.Pattern);
                    if (bAdd)
                    {
                        PatternToCount.Add(Crash.Pattern, 1);
                    }
                    else
                    {
                        PatternToCount[Crash.Pattern]++;
                    }
                }
                var PatternToCountOrdered = PatternToCount.OrderByDescending(X => X.Value).ToList();
                // The 100 top.
                var PatternAndCount = PatternToCountOrdered.Take(100).ToDictionary(X => X.Key, Y => Y.Value);

                int TotalUniqueAnonymousCrashes = UniquePatterns.Count;

                // Total # of AFFECTED USERS (Anonymous) in timeframe
                int TotalAffectedUsers = UniqueMachines.Count;

                var RealBuggs = BuggsRepo.Context.Buggs.Where(Bugg => PatternAndCount.Keys.Contains(Bugg.Pattern)).ToList();

                // Build search string.
                HashSet <string> FoundJiras = new HashSet <string>();
                Dictionary <string, List <Bugg> > JiraIDtoBugg = new Dictionary <string, List <Bugg> >();

                List <Bugg> Buggs = new List <Bugg>(100);
                foreach (var Top in PatternAndCount)
                {
                    Bugg NewBugg = RealBuggs.Where(X => X.Pattern == Top.Key).FirstOrDefault();
                    if (NewBugg != null)
                    {
                        using (FAutoScopedLogTimer TopTimer = new FAutoScopedLogTimer(string.Format("{0}:{1}", Buggs.Count + 1, NewBugg.Id)))
                        {
                            var CrashesForBugg = Crashes.Where(Crash => Crash.Pattern == Top.Key).ToList();

                            // Convert anonymous to full type;
                            var FullCrashesForBugg = new List <Crash>(CrashesForBugg.Count);
                            foreach (var Anon in CrashesForBugg)
                            {
                                FullCrashesForBugg.Add(new Crash()
                                {
                                    ID           = Anon.ID,
                                    TimeOfCrash  = Anon.TimeOfCrash,
                                    BuildVersion = Anon.BuildVersion,
                                    JIRA         = Anon.JIRA,
                                    Platform     = Anon.Platform,
                                    FixCL        = Anon.FixCL,
                                    BuiltFromCL  = Anon.BuiltFromCL,
                                    Pattern      = Anon.Pattern,
                                    MachineID    = Anon.MachineID,
                                    Branch       = Anon.Branch,
                                    Description  = Anon.Description,
                                    RawCallStack = Anon.RawCallStack,
                                });
                            }

                            NewBugg.PrepareBuggForJira(FullCrashesForBugg);

                            // Verify valid JiraID, this may be still a TTP
                            if (!string.IsNullOrEmpty(NewBugg.TTPID))
                            {
                                int TTPID = 0;
                                int.TryParse(NewBugg.TTPID, out TTPID);

                                if (TTPID == 0)
                                {
                                    AddBuggJiraMapping(NewBugg, ref FoundJiras, ref JiraIDtoBugg);
                                }
                            }

                            Buggs.Add(NewBugg);
                        }
                    }
                    else
                    {
                        FLogger.Global.WriteEvent("Bugg for pattern " + Top.Key + " not found");
                    }
                }

                if (BuggIDToBeAddedToJira > 0)
                {
                    var Bugg = Buggs.Where(X => X.Id == BuggIDToBeAddedToJira).FirstOrDefault();
                    if (Bugg != null)
                    {
                        Bugg.CopyToJira();
                        AddBuggJiraMapping(Bugg, ref FoundJiras, ref JiraIDtoBugg);
                    }
                }

                if (JC.CanBeUsed())
                {
                    var BuggsCopy = new List <Bugg>(Buggs);

                    // Grab the data form JIRA.
                    string JiraSearchQuery = string.Join(" OR ", FoundJiras);

                    using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("JiraResults"))
                    {
                        var JiraResults = JC.SearchJiraTickets(
                            JiraSearchQuery,
                            new string[]
                        {
                            "key",                                          // string
                            "summary",                                      // string
                            "components",                                   // System.Collections.ArrayList, Dictionary<string,object>, name
                            "resolution",                                   // System.Collections.Generic.Dictionary`2[System.String,System.Object], name
                            "fixVersions",                                  // System.Collections.ArrayList, Dictionary<string,object>, name
                            "customfield_11200"                             // string
                        });


                        // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
                        foreach (var Jira in JiraResults)
                        {
                            string JiraID = Jira.Key;

                            string Summary = (string)Jira.Value["summary"];

                            string ComponentsText = "";
                            System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"];
                            foreach (Dictionary <string, object> Component in Components)
                            {
                                ComponentsText += (string)Component["name"];
                                ComponentsText += " ";
                            }

                            Dictionary <string, object> ResolutionFields = (Dictionary <string, object>)Jira.Value["resolution"];
                            string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : "";

                            string FixVersionsText = "";
                            System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"];
                            foreach (Dictionary <string, object> FixVersion in FixVersions)
                            {
                                FixVersionsText += (string)FixVersion["name"];
                                FixVersionsText += " ";
                            }

                            int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0;

                            List <Bugg> BuggsForJira;
                            JiraIDtoBugg.TryGetValue(JiraID, out BuggsForJira);

                            //var BuggsForJira = JiraIDtoBugg[JiraID];

                            if (BuggsForJira != null)
                            {
                                foreach (Bugg Bugg in BuggsForJira)
                                {
                                    Bugg.JiraSummary         = Summary;
                                    Bugg.JiraComponentsText  = ComponentsText;
                                    Bugg.JiraResolution      = Resolution;
                                    Bugg.JiraFixVersionsText = FixVersionsText;
                                    if (FixCL != 0)
                                    {
                                        Bugg.JiraFixCL = FixCL.ToString();
                                    }

                                    BuggsCopy.Remove(Bugg);
                                }
                            }
                        }
                    }

                    // If there are buggs, we need to update the summary to indicate an error.
                    // Usually caused when bugg's project has changed.
                    foreach (var Bugg in BuggsCopy.Where(b => !string.IsNullOrEmpty(b.TTPID)))
                    {
                        Bugg.JiraSummary         = "JIRA MISMATCH";
                        Bugg.JiraComponentsText  = "JIRA MISMATCH";
                        Bugg.JiraResolution      = "JIRA MISMATCH";
                        Bugg.JiraFixVersionsText = "JIRA MISMATCH";
                        Bugg.JiraFixCL           = "JIRA MISMATCH";
                    }
                }

                Buggs = Buggs.OrderByDescending(b => b.NumberOfCrashes).ToList();

                return(new ReportsViewModel
                {
                    Buggs = Buggs,
                    /*Crashes = Crashes,*/
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    TotalAffectedUsers = TotalAffectedUsers,
                    TotalAnonymousCrashes = TotalAnonymousCrashes,
                    TotalUniqueAnonymousCrashes = TotalUniqueAnonymousCrashes
                });
            }
        }
Exemple #37
0
        /// <summary>
        /// The Show action.
        /// </summary>
        /// <param name="BuggsForm">The form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the Bugg.</param>
        /// <returns>The view to display a Bugg on the client.</returns>
        public ActionResult Show(FormCollection BuggsForm, int id)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(BuggId=" + id + ")", bCreateNewLog: true))
            {
                // Handle 'CopyToJira' button
                int BuggIDToBeAddedToJira = 0;
                foreach (var Entry in BuggsForm)
                {
                    if (Entry.ToString().Contains(Bugg.JiraSubmitName))
                    {
                        int.TryParse(Entry.ToString().Substring(Bugg.JiraSubmitName.Length), out BuggIDToBeAddedToJira);
                        break;
                    }
                }

                BuggRepository Buggs = new BuggRepository();

                // Set the display properties based on the radio buttons
                bool DisplayModuleNames = false;
                if (BuggsForm["DisplayModuleNames"] == "true")
                {
                    DisplayModuleNames = true;
                }

                bool DisplayFunctionNames = false;
                if (BuggsForm["DisplayFunctionNames"] == "true")
                {
                    DisplayFunctionNames = true;
                }

                bool DisplayFileNames = false;
                if (BuggsForm["DisplayFileNames"] == "true")
                {
                    DisplayFileNames = true;
                }

                bool DisplayFilePathNames = false;
                if (BuggsForm["DisplayFilePathNames"] == "true")
                {
                    DisplayFilePathNames = true;
                    DisplayFileNames     = false;
                }

                bool DisplayUnformattedCallStack = false;
                if (BuggsForm["DisplayUnformattedCallStack"] == "true")
                {
                    DisplayUnformattedCallStack = true;
                }

                // Create a new view and populate with crashes
                List <Crash> Crashes = null;

                BuggViewModel Model   = new BuggViewModel();
                Bugg          NewBugg = Buggs.GetBugg(id);
                if (NewBugg == null)
                {
                    return(RedirectToAction(""));
                }

                Crashes = NewBugg.GetCrashes();

                using (FAutoScopedLogTimer GetCrashesTimer = new FAutoScopedLogTimer("Bugg.PrepareBuggForJira"))
                {
                    if (Crashes.Count > 0)
                    {
                        NewBugg.PrepareBuggForJira(Crashes);

                        if (BuggIDToBeAddedToJira != 0)
                        {
                            NewBugg.CopyToJira();
                        }
                    }
                }

                using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("Bugg.GrabJira"))
                {
                    var  JC         = JiraConnection.Get();
                    bool bValidJira = false;

                    // Verify valid JiraID, this may be still a TTP
                    if (!string.IsNullOrEmpty(NewBugg.Jira))
                    {
                        int TTPID = 0;
                        int.TryParse(NewBugg.Jira, out TTPID);

                        if (TTPID == 0)
                        {
                            //AddBuggJiraMapping( NewBugg, ref FoundJiras, ref JiraIDtoBugg );
                            bValidJira = true;
                        }
                    }

                    if (JC.CanBeUsed() && bValidJira)
                    {
                        // Grab the data form JIRA.
                        string JiraSearchQuery = "key = " + NewBugg.Jira;

                        var JiraResults = JC.SearchJiraTickets(
                            JiraSearchQuery,
                            new string[]
                        {
                            "key",                                                  // string
                            "summary",                                              // string
                            "components",                                           // System.Collections.ArrayList, Dictionary<string,object>, name
                            "resolution",                                           // System.Collections.Generic.Dictionary`2[System.String,System.Object], name
                            "fixVersions",                                          // System.Collections.ArrayList, Dictionary<string,object>, name
                            "customfield_11200"                                     // string
                        });


                        // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
                        foreach (var Jira in JiraResults)
                        {
                            string JiraID = Jira.Key;

                            string Summary = (string)Jira.Value["summary"];

                            string ComponentsText = "";
                            System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"];
                            foreach (Dictionary <string, object> Component in Components)
                            {
                                ComponentsText += (string)Component["name"];
                                ComponentsText += " ";
                            }

                            Dictionary <string, object> ResolutionFields = (Dictionary <string, object>)Jira.Value["resolution"];
                            string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : "";

                            string FixVersionsText = "";
                            System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"];
                            foreach (Dictionary <string, object> FixVersion in FixVersions)
                            {
                                FixVersionsText += (string)FixVersion["name"];
                                FixVersionsText += " ";
                            }

                            int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0;

                            NewBugg.JiraSummary         = Summary;
                            NewBugg.JiraComponentsText  = ComponentsText;
                            NewBugg.JiraResolution      = Resolution;
                            NewBugg.JiraFixVersionsText = FixVersionsText;
                            if (FixCL != 0)
                            {
                                NewBugg.JiraFixCL = FixCL.ToString();
                            }

                            break;
                        }
                    }
                }

                // Apply any user settings
                if (BuggsForm.Count > 0)
                {
                    if (!string.IsNullOrEmpty(BuggsForm["SetStatus"]))
                    {
                        NewBugg.Status = BuggsForm["SetStatus"];
                        Buggs.SetBuggStatus(NewBugg.Status, id);
                    }

                    if (!string.IsNullOrEmpty(BuggsForm["SetFixedIn"]))
                    {
                        NewBugg.FixedChangeList = BuggsForm["SetFixedIn"];
                        Buggs.SetBuggFixedChangeList(NewBugg.FixedChangeList, id);
                    }

                    if (!string.IsNullOrEmpty(BuggsForm["SetTTP"]))
                    {
                        NewBugg.Jira = BuggsForm["SetTTP"];
                        Buggs.SetJIRAForBuggAndCrashes(NewBugg.Jira, id);
                    }

                    // <STATUS>
                }

                // Set up the view model with the crash data
                Model.Bugg    = NewBugg;
                Model.Crashes = Crashes;

                Crash NewCrash = Model.Crashes.FirstOrDefault();
                if (NewCrash != null)
                {
                    using (FScopedLogTimer LogTimer2 = new FScopedLogTimer("CallstackTrimming"))
                    {
                        CallStackContainer CallStack = new CallStackContainer(NewCrash);

                        // Set callstack properties
                        CallStack.bDisplayModuleNames          = DisplayModuleNames;
                        CallStack.bDisplayFunctionNames        = DisplayFunctionNames;
                        CallStack.bDisplayFileNames            = DisplayFileNames;
                        CallStack.bDisplayFilePathNames        = DisplayFilePathNames;
                        CallStack.bDisplayUnformattedCallStack = DisplayUnformattedCallStack;

                        Model.CallStack = CallStack;

                        // Shorten very long function names.
                        foreach (CallStackEntry Entry in Model.CallStack.CallStackEntries)
                        {
                            Entry.FunctionName = Entry.GetTrimmedFunctionName(128);
                        }

                        Model.SourceContext = NewCrash.SourceContext;
                    }

                    Model.Bugg.LatestCrashSummary = NewCrash.Summary;
                }

                Model.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2");
                return(View("Show", Model));
            }
        }
        /// <summary>
        /// Sort the container of Buggs by the requested criteria.
        /// </summary>
        /// <param name="Results">A container of unsorted Buggs.</param>
        /// <param name="SortTerm">The term to sort by.</param>
        /// <param name="bSortDescending">Whether to sort by descending or ascending.</param>
        /// <param name="DateFrom">The date of the earliest Bugg to examine.</param>
        /// <param name="DateTo">The date of the most recent Bugg to examine.</param>
        /// <returns>A sorted container of Buggs.</returns>
        public IQueryable<Bugg> GetSortedResults( IQueryable<Bugg> Results, string SortTerm, bool bSortDescending, DateTime DateFrom, DateTime DateTo )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
            {
                try
                {

                    var IntermediateResults =
                    (
                        from BuggCrashDetail in BuggsDataContext.Buggs_Crashes
                        where BuggCrashDetail.Crash.TimeOfCrash >= DateFrom && BuggCrashDetail.Crash.TimeOfCrash <= AddOneDayToDate( DateTo )
                        group BuggCrashDetail by BuggCrashDetail.BuggId into CrashesGrouped
                        join BuggDetail in Results on CrashesGrouped.Key equals BuggDetail.Id
                        select new { Bugg = BuggDetail, Count = CrashesGrouped.Count() }
                    );

                    using( FScopedLogTimer LogTimer2 = new FScopedLogTimer( "BuggRepository.GetSortedResults.CrashesInTimeFrame" ) )
                    {
                        foreach( var Result in IntermediateResults )
                        {
                            Result.Bugg.CrashesInTimeFrame = Result.Count;
                        }
                    }

                    switch( SortTerm )
                    {
                        case "CrashesInTimeFrame":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Count, bSortDescending );
                            break;

                        case "Id":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.Id, bSortDescending );
                            break;

                        case "BuildVersion":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.BuildVersion, bSortDescending );
                            break;

                        case "LatestCrash":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.TimeOfLastCrash, bSortDescending );
                            break;

                        case "FirstCrash":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.TimeOfFirstCrash, bSortDescending );
                            break;

                        case "NumberOfCrashes":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.NumberOfCrashes, bSortDescending );
                            break;

                        case "NumberOfUsers":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.NumberOfUsers, bSortDescending );
                            break;

                        case "Pattern":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.Pattern, bSortDescending );
                            break;

                        case "Status":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.Status, bSortDescending );
                            break;

                        case "FixedChangeList":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.FixedChangeList, bSortDescending );
                            break;

                        case "TTPID":
                            IntermediateResults = CrashRepository.OrderBy( IntermediateResults, BuggCrashInstance => BuggCrashInstance.Bugg.TTPID, bSortDescending );
                            break;

                    }
                    return IntermediateResults.Select( x => x.Bugg );
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in GetSortedResults: " + Ex.ToString() );
                }
                return Results;
            }
        }
        /// <summary>
        /// Associate a set of crashes and their owners with a Bugg.
        /// </summary>
        /// <param name="Bugg">The Bugg to get the data.</param>
        /// <param name="Crashes">The set of crashes to add to the Bugg.</param>
        public void UpdateBuggData( Bugg Bugg, IEnumerable<Crash> Crashes )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString()+ "(" + Bugg.Id + ")" ) )
            {
                FLogger.WriteEvent( "UpdateBuggData Bugg.Id=" + Bugg.Id );

                DateTime? TimeOfFirstCrash = null;
                DateTime? TimeOfLastCrash = null;
                string BuildVersion = null;
                List<int> UserNameIds = new List<int>();
                int CrashCount = 0;

                // Set or return min date max date while we're iterating through the crashes
                bool bHasChanges = false;
                try
                {
                    foreach( Crash CurrentCrash in Crashes )
                    {
                        CrashCount++;
                        if( TimeOfFirstCrash == null || CurrentCrash.TimeOfCrash < TimeOfFirstCrash )
                        {
                            TimeOfFirstCrash = CurrentCrash.TimeOfCrash;
                        }

                        if( TimeOfLastCrash == null || CurrentCrash.TimeOfCrash > TimeOfLastCrash )
                        {
                            TimeOfLastCrash = CurrentCrash.TimeOfCrash;
                        }

                        if( BuildVersion == null || CurrentCrash.BuildVersion.CompareTo( BuildVersion ) > 0 )
                        {
                            BuildVersion = CurrentCrash.BuildVersion;
                        }

                        // Handle user count
                        if( Bugg.Id != 0 )
                        {
                            if( !UserNameIds.Contains( CurrentCrash.User.Id ) )
                            {
                                // Add username to local users variable that we will use later to set user count and associate users and user groups to the bugg.
                                UserNameIds.Add( CurrentCrash.User.Id );
                            }
                        }

                        CurrentCrash.FixedChangeList = Bugg.FixedChangeList;
                        CurrentCrash.TTPID = Bugg.TTPID;
                        CurrentCrash.Status = Bugg.Status;

                        if( Bugg.Id != 0 )
                        {
                            bHasChanges |= LinkCrashToBugg( Bugg, CurrentCrash );
                        }
                    }

                    if( CrashCount > 1 )
                    {
                        Bugg.TimeOfLastCrash = TimeOfLastCrash;
                        Bugg.TimeOfFirstCrash = TimeOfFirstCrash;
                        Bugg.NumberOfUsers = UserNameIds.Count();
                        Bugg.NumberOfCrashes = CrashCount;
                        Bugg.BuildVersion = BuildVersion;

                        foreach( int UserNameId in UserNameIds )
                        {
                            // Link user to Bugg
                            bHasChanges |= LinkUserToBugg( Bugg, UserNameId );
                        }
                    }

                    if( bHasChanges )
                    {
                        BuggsDataContext.SubmitChanges();
                    }
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in UpdateBuggData: " + Ex.ToString() );
                }

            }
        }
        /// <summary>
        /// The Show action.
        /// </summary>
        /// <param name="buggsForm">The form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the Bugg.</param>
        /// <returns>The view to display a Bugg on the client.</returns>
        public ActionResult Show(FormCollection buggsForm, int id, int page = 0)
        {
            using (var logTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(BuggId=" + id + ")"))
            {
                using (var unitOfWork = new UnitOfWork(new CrashReportEntities()))
                {
                    // Set the display properties based on the radio buttons
                    var displayModuleNames   = buggsForm["DisplayModuleNames"] == "true";
                    var displayFunctionNames = buggsForm["DisplayFunctionNames"] == "true";
                    var displayFileNames     = buggsForm["DisplayFileNames"] == "true";
                    var displayFilePathNames = false;


                    // Set up the view model with the Crash data
                    if (buggsForm["Page"] != null)
                    {
                        int.TryParse(buggsForm["Page"], out page);
                    }

                    if (buggsForm["DisplayFilePathNames"] == "true")
                    {
                        displayFilePathNames = true;
                        displayFileNames     = false;
                    }

                    var displayUnformattedCallStack = buggsForm["DisplayUnformattedCallStack"] == "true";

                    var model = GetResult(id, page, pageSize, unitOfWork);
                    model.SourceContext = model.CrashData.First().SourceContext;
                    model.Bugg.PrepareBuggForJira(model.CrashData);
                    // Handle 'CopyToJira' button
                    var buggIdToBeAddedToJira = 0;
                    foreach (var entry in buggsForm.Cast <object>().Where(entry => entry.ToString().Contains("CopyToJira-")))
                    {
                        int.TryParse(entry.ToString().Substring("CopyToJira-".Length), out buggIdToBeAddedToJira);
                        break;
                    }
                    if (buggIdToBeAddedToJira != 0)
                    {
                        model.Bugg.JiraProject = buggsForm["JiraProject"];
                        model.Bugg.CopyToJira();
                    }

                    var jc         = JiraConnection.Get();
                    var bValidJira = false;

                    // Verify valid JiraID, this may be still a TTP
                    if (!string.IsNullOrEmpty(model.Bugg.TTPID))
                    {
                        var jira = 0;
                        int.TryParse(model.Bugg.TTPID, out jira);

                        if (jira == 0)
                        {
                            bValidJira = true;
                        }
                    }

                    if (jc.CanBeUsed() && bValidJira)
                    {
                        // Grab the data form JIRA.
                        var jiraSearchQuery = "key = " + model.Bugg.TTPID;
                        var jiraResults     = new Dictionary <string, Dictionary <string, object> >();

                        try
                        {
                            jiraResults = jc.SearchJiraTickets(
                                jiraSearchQuery,
                                new string[]
                            {
                                "key",                 // string
                                "summary",             // string
                                "components",          // System.Collections.ArrayList, Dictionary<string,object>, name
                                "resolution",          // System.Collections.Generic.Dictionary`2[System.String,System.Object], name
                                "fixVersions",         // System.Collections.ArrayList, Dictionary<string,object>, name
                                "customfield_11200"    // string
                            });
                        }
                        catch (System.Exception)
                        {
                            model.Bugg.JiraSummary         = "JIRA MISMATCH";
                            model.Bugg.JiraComponentsText  = "JIRA MISMATCH";
                            model.Bugg.JiraResolution      = "JIRA MISMATCH";
                            model.Bugg.JiraFixVersionsText = "JIRA MISMATCH";
                            model.Bugg.JiraFixCL           = "JIRA MISMATCH";
                        }

                        // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
                        if (jiraResults.Any())
                        {
                            var jira           = jiraResults.First();
                            var summary        = (string)jira.Value["summary"];
                            var componentsText = "";
                            var components     = (System.Collections.ArrayList)jira.Value["components"];
                            foreach (Dictionary <string, object> component in components)
                            {
                                componentsText += (string)component["name"];
                                componentsText += " ";
                            }

                            var resolutionFields = (Dictionary <string, object>)jira.Value["resolution"];
                            var resolution       = resolutionFields != null ? (string)resolutionFields["name"] : "";

                            var fixVersionsText = "";
                            var fixVersions     = (System.Collections.ArrayList)jira.Value["fixVersions"];
                            foreach (Dictionary <string, object> fixVersion in fixVersions)
                            {
                                fixVersionsText += (string)fixVersion["name"];
                                fixVersionsText += " ";
                            }

                            var fixCl = jira.Value["customfield_11200"] != null
                                            ? (int)(decimal)jira.Value["customfield_11200"]
                                            : 0;

                            //Conversion to ado.net entity framework

                            model.Bugg.JiraSummary         = summary;
                            model.Bugg.JiraComponentsText  = componentsText;
                            model.Bugg.JiraResolution      = resolution;
                            model.Bugg.JiraFixVersionsText = fixVersionsText;
                            if (fixCl != 0)
                            {
                                model.Bugg.FixedChangeList = fixCl.ToString();
                            }
                        }
                    }

                    // Apply any user settings
                    if (buggsForm.Count > 0)
                    {
                        if (!string.IsNullOrEmpty(buggsForm["SetStatus"]))
                        {
                            model.Bugg.Status = buggsForm["SetStatus"];
                            unitOfWork.CrashRepository.SetStatusByBuggId(model.Bugg.Id, buggsForm["SetFixedIn"]);
                        }

                        if (!string.IsNullOrEmpty(buggsForm["SetFixedIn"]))
                        {
                            model.Bugg.FixedChangeList = buggsForm["SetFixedIn"];
                            unitOfWork.CrashRepository.SetFixedCLByBuggId(model.Bugg.Id, buggsForm["SetFixedIn"]);
                        }

                        if (!string.IsNullOrEmpty(buggsForm["SetTTP"]))
                        {
                            model.Bugg.TTPID = buggsForm["SetTTP"];
                            unitOfWork.CrashRepository.SetJiraByBuggId(model.Bugg.Id, buggsForm["SetTTP"]);
                        }
                        unitOfWork.BuggRepository.Update(model.Bugg);

                        unitOfWork.Save();
                    }

                    var newCrash = model.CrashData.FirstOrDefault();
                    if (newCrash != null)
                    {
                        var callStack = new CallStackContainer(newCrash.CrashType, newCrash.RawCallStack, newCrash.PlatformName);

                        // Set callstack properties
                        callStack.bDisplayModuleNames          = displayModuleNames;
                        callStack.bDisplayFunctionNames        = displayFunctionNames;
                        callStack.bDisplayFileNames            = displayFileNames;
                        callStack.bDisplayFilePathNames        = displayFilePathNames;
                        callStack.bDisplayUnformattedCallStack = displayUnformattedCallStack;

                        model.CallStack = callStack;

                        // Shorten very long function names.
                        foreach (var entry in model.CallStack.CallStackEntries)
                        {
                            entry.FunctionName = entry.GetTrimmedFunctionName(128);
                        }

                        model.SourceContext = newCrash.SourceContext;

                        model.LatestCrashSummary = newCrash.Summary;
                    }

                    model.LatestCrashSummary      = newCrash.Summary;
                    model.Bugg.LatestCrashSummary = newCrash.Summary;
                    model.GenerationTime          = logTimer.GetElapsedSeconds().ToString("F2");

                    //Populate Jira Projects
                    var jiraConnection = JiraConnection.Get();
                    var response       = jiraConnection.JiraRequest("/issue/createmeta", JiraConnection.JiraMethod.GET, null,
                                                                    HttpStatusCode.OK);

                    using (var responseReader = new StreamReader(response.GetResponseStream()))
                    {
                        var responseText = responseReader.ReadToEnd();

                        JObject jsonObject = JObject.Parse(responseText);

                        JToken fields = jsonObject["projects"];

                        foreach (var project in fields)
                        {
                            model.JiraProjects.Add(new SelectListItem()
                            {
                                Text  = project["name"].ToObject <string>(),
                                Value = project["key"].ToObject <string>()
                            });
                        }
                    }

                    model.PagingInfo = new PagingInfo
                    {
                        CurrentPage  = page,
                        PageSize     = pageSize,
                        TotalResults = model.Bugg.NumberOfCrashes.Value
                    };

                    return(View("Show", model));
                }
            }
        }
        /// <summary>
        /// The Show action.
        /// </summary>
        /// <param name="buggsForm">The form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the Bugg.</param>
        /// <returns>The view to display a Bugg on the client.</returns>
        public ActionResult Show(FormCollection buggsForm, int id)
        {
            using (var logTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(BuggId=" + id + ")", bCreateNewLog: true))
            {
                // Set the display properties based on the radio buttons
                var displayModuleNames   = buggsForm["DisplayModuleNames"] == "true";
                var displayFunctionNames = buggsForm["DisplayFunctionNames"] == "true";
                var displayFileNames     = buggsForm["DisplayFileNames"] == "true";
                var displayFilePathNames = false;
                if (buggsForm["DisplayFilePathNames"] == "true")
                {
                    displayFilePathNames = true;
                    displayFileNames     = false;
                }
                var displayUnformattedCallStack = buggsForm["DisplayUnformattedCallStack"] == "true";

                // Create a new view and populate with crashes
                List <Crash> crashes = null;
                var          model   = new BuggViewModel();
                var          newBugg = _unitOfWork.BuggRepository.GetById(id);
                if (newBugg == null)
                {
                    return(RedirectToAction("Index"));
                }
                crashes = newBugg.Crashes.OrderByDescending(data => data.TimeOfCrash).ToList();
                newBugg.CrashesInTimeFrameAll   = crashes.Count;
                newBugg.CrashesInTimeFrameGroup = crashes.Count;
                newBugg.NumberOfCrashes         = crashes.Count;

                // Handle 'CopyToJira' button
                var buggIdToBeAddedToJira = 0;
                foreach (var entry in buggsForm.Cast <object>().Where(entry => entry.ToString().Contains("CopyToJira-")))
                {
                    int.TryParse(entry.ToString().Substring("CopyToJira-".Length), out buggIdToBeAddedToJira);
                    break;
                }

                newBugg.PrepareBuggForJira(crashes);
                if (buggIdToBeAddedToJira != 0)
                {
                    newBugg.JiraProject = buggsForm["JiraProject"];
                    newBugg.CopyToJira();
                }

                var jc         = JiraConnection.Get();
                var bValidJira = false;

                // Verify valid JiraID, this may be still a TTP
                if (!string.IsNullOrEmpty(newBugg.TTPID))
                {
                    var jira = 0;
                    int.TryParse(newBugg.TTPID, out jira);

                    if (jira == 0)
                    {
                        bValidJira = true;
                    }
                }

                if (jc.CanBeUsed() && bValidJira)
                {
                    // Grab the data form JIRA.
                    var jiraSearchQuery = "key = " + newBugg.TTPID;
                    var jiraResults     = new Dictionary <string, Dictionary <string, object> >();

                    try
                    {
                        jiraResults = jc.SearchJiraTickets(
                            jiraSearchQuery,
                            new string[]
                        {
                            "key",                                          // string
                            "summary",                                      // string
                            "components",                                   // System.Collections.ArrayList, Dictionary<string,object>, name
                            "resolution",                                   // System.Collections.Generic.Dictionary`2[System.String,System.Object], name
                            "fixVersions",                                  // System.Collections.ArrayList, Dictionary<string,object>, name
                            "customfield_11200"                             // string
                        });
                    }
                    catch (System.Exception)
                    {
                        newBugg.JiraSummary         = "JIRA MISMATCH";
                        newBugg.JiraComponentsText  = "JIRA MISMATCH";
                        newBugg.JiraResolution      = "JIRA MISMATCH";
                        newBugg.JiraFixVersionsText = "JIRA MISMATCH";
                        newBugg.JiraFixCL           = "JIRA MISMATCH";
                    }

                    // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
                    if (jiraResults.Any())
                    {
                        var jira    = jiraResults.First();
                        var summary = (string)jira.Value["summary"];

                        var componentsText = "";
                        var components     = (System.Collections.ArrayList)jira.Value["components"];
                        foreach (Dictionary <string, object> component in components)
                        {
                            componentsText += (string)component["name"];
                            componentsText += " ";
                        }

                        var resolutionFields = (Dictionary <string, object>)jira.Value["resolution"];
                        var resolution       = resolutionFields != null ? (string)resolutionFields["name"] : "";

                        var fixVersionsText = "";
                        var fixVersions     = (System.Collections.ArrayList)jira.Value["fixVersions"];
                        foreach (Dictionary <string, object> fixVersion in fixVersions)
                        {
                            fixVersionsText += (string)fixVersion["name"];
                            fixVersionsText += " ";
                        }

                        var fixCl = jira.Value["customfield_11200"] != null ? (int)(decimal)jira.Value["customfield_11200"] : 0;

                        //Conversion to ado.net entity framework

                        newBugg.JiraSummary         = summary;
                        newBugg.JiraComponentsText  = componentsText;
                        newBugg.JiraResolution      = resolution;
                        newBugg.JiraFixVersionsText = fixVersionsText;
                        if (fixCl != 0)
                        {
                            newBugg.FixedChangeList = fixCl.ToString();
                        }
                    }
                }

                // Apply any user settings
                if (buggsForm.Count > 0)
                {
                    if (!string.IsNullOrEmpty(buggsForm["SetStatus"]))
                    {
                        newBugg.Status = buggsForm["SetStatus"];
                        newBugg.Crashes.ForEach(data => data.Status = buggsForm["SetStatus"]);
                    }

                    if (!string.IsNullOrEmpty(buggsForm["SetFixedIn"]))
                    {
                        newBugg.FixedChangeList = buggsForm["SetFixedIn"];
                        newBugg.Crashes.ForEach(data => data.FixedChangeList = buggsForm["SetFixedIn"]);
                    }

                    if (!string.IsNullOrEmpty(buggsForm["SetTTP"]))
                    {
                        newBugg.TTPID = buggsForm["SetTTP"];
                        newBugg.Crashes.ForEach(data => data.Jira = buggsForm["SetTTP"]);
                    }

                    _unitOfWork.BuggRepository.Update(newBugg);
                    _unitOfWork.Save();
                }

                // Set up the view model with the crash data
                model.Crashes = crashes;
                model.Bugg    = newBugg;

                var newCrash = model.Crashes.FirstOrDefault();
                if (newCrash != null)
                {
                    var callStack = new CallStackContainer(newCrash);

                    // Set callstack properties
                    callStack.bDisplayModuleNames          = displayModuleNames;
                    callStack.bDisplayFunctionNames        = displayFunctionNames;
                    callStack.bDisplayFileNames            = displayFileNames;
                    callStack.bDisplayFilePathNames        = displayFilePathNames;
                    callStack.bDisplayUnformattedCallStack = displayUnformattedCallStack;

                    model.CallStack = callStack;

                    // Shorten very long function names.
                    foreach (var entry in model.CallStack.CallStackEntries)
                    {
                        entry.FunctionName = entry.GetTrimmedFunctionName(128);
                    }

                    model.SourceContext = newCrash.SourceContext;

                    model.LatestCrashSummary = newCrash.Summary;
                }
                model.LatestCrashSummary      = newCrash.Summary;
                model.Bugg.LatestCrashSummary = newCrash.Summary;
                model.GenerationTime          = logTimer.GetElapsedSeconds().ToString("F2");
                return(View("Show", model));
            }
        }
Exemple #42
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="UserGroupId"></param>
        /// <returns></returns>
        public List<string> GetUsersForGroupId( int UserGroupId )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(UserGroupId=" + UserGroupId + ")" ) )
            {
                List<string> Users = new List<string>();
                try
                {
                    Users =
                    (
                        from UserDetail in Context.Users
                        where UserDetail.UserGroupId == UserGroupId
                        orderby UserDetail.UserName
                        select UserDetail.UserName
                    ).ToList();
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in GetUsersForGroup: " + Ex.ToString() );
                }

                return Users;
            }
        }
        /// <summary>
        /// Retrieve all Buggs matching the search criteria.
        /// </summary>
        /// <param name="FormData">The incoming form of search criteria from the client.</param>
        /// <param name="BuggIDToBeAddedToJira">ID of the bugg that will be added to JIRA</param>
        /// <returns>A view to display the filtered Buggs.</returns>
        public ReportsViewModel GetResults(FormHelper FormData, int BuggIDToBeAddedToJira)
        {
            // @TODO yrx 2015-02-17 BuggIDToBeAddedToJira replace with List<int> based on check box and Submit?
            // Enumerate JIRA projects if needed.
            // https://jira.ol.epicgames.net//rest/api/2/project
            var JC             = JiraConnection.Get();
            var JiraComponents = JC.GetNameToComponents();
            var JiraVersions   = JC.GetNameToVersions();

            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                string           AnonumousGroup        = "Anonymous";
                List <String>    Users                 = CrashRepository.GetUsersForGroup(AnonumousGroup);
                int              AnonymousGroupID      = BuggRepository.GetIdFromUserGroup(AnonumousGroup);
                HashSet <int>    AnonumousIDs          = BuggRepository.GetUserIdsFromUserGroup(AnonumousGroup);
                int              AnonymousID           = AnonumousIDs.First();
                HashSet <string> UserNamesForUserGroup = BuggRepository.GetUserNamesFromUserGroups(AnonumousGroup);

                //FormData.DateFrom = DateTime.Now.AddDays( -1 );

                var Crashes = CrashRepository
                              .FilterByDate(CrashRepository.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays(1))
                              // Only crashes and asserts
                              .Where(Crash => Crash.CrashType == 1 || Crash.CrashType == 2)
                              // Only anonymous user
                              .Where(Crash => Crash.UserNameId.Value == AnonymousID)
                              .Select(Crash => new
                {
                    ID          = Crash.Id,
                    TimeOfCrash = Crash.TimeOfCrash.Value,
                    //UserID = Crash.UserNameId.Value,
                    BuildVersion = Crash.BuildVersion,
                    JIRA         = Crash.TTPID,
                    Platform     = Crash.PlatformName,
                    FixCL        = Crash.FixedChangeList,
                    BuiltFromCL  = Crash.ChangeListVersion,
                    Pattern      = Crash.Pattern,
                    MachineID    = Crash.ComputerName,
                    Branch       = Crash.Branch,
                })
                              .ToList();
                int NumCrashes = Crashes.Count;

                /*
                 * // Build patterns for crashes where patters is null.
                 * var CrashesWithoutPattern = CrashRepository
                 *      .FilterByDate( CrashRepository.ListAll(), FormData.DateFrom, FormData.DateTo.AddDays( 1 ) )
                 *      // Only crashes and asserts
                 *      .Where( Crash => Crash.Pattern == null || Crash.Pattern == "" )
                 *      .Select( Crash => Crash )
                 *      .ToList();
                 *
                 * foreach( var Crash in CrashesWithoutPattern )
                 * {
                 *      ////BuildPattern( Crash );
                 * }
                 */

                // Total # of ALL (Anonymous) crashes in timeframe
                int TotalAnonymousCrashes = NumCrashes;

                // Total # of UNIQUE (Anonymous) crashes in timeframe
                HashSet <string>         UniquePatterns = new HashSet <string>();
                HashSet <string>         UniqueMachines = new HashSet <string>();
                Dictionary <string, int> PatternToCount = new Dictionary <string, int>();

                //List<int> CrashesWithoutPattern = new List<int>();
                //List<DateTime> CrashesWithoutPatternDT = new List<DateTime>();

                foreach (var Crash in Crashes)
                {
                    if (string.IsNullOrEmpty(Crash.Pattern))
                    {
                        //CrashesWithoutPattern.Add( Crash.ID );
                        //CrashesWithoutPatternDT.Add( Crash.TimeOfCrash );
                        continue;
                    }

                    UniquePatterns.Add(Crash.Pattern);
                    UniqueMachines.Add(Crash.MachineID);

                    bool bAdd = !PatternToCount.ContainsKey(Crash.Pattern);
                    if (bAdd)
                    {
                        PatternToCount.Add(Crash.Pattern, 1);
                    }
                    else
                    {
                        PatternToCount[Crash.Pattern]++;
                    }
                }
                var PatternToCountOrdered = PatternToCount.OrderByDescending(X => X.Value).ToList();
                // The 100 top.
                var PatternAndCount = PatternToCountOrdered.Take(100).ToDictionary(X => X.Key, Y => Y.Value);

                int TotalUniqueAnonymousCrashes = UniquePatterns.Count;

                // Total # of AFFECTED USERS (Anonymous) in timeframe
                int TotalAffectedUsers = UniqueMachines.Count;

                var RealBuggs = BuggRepository.GetDataContext().Buggs.Where(Bugg => PatternAndCount.Keys.Contains(Bugg.Pattern)).ToList();

                // Build search string.
                List <string> FoundJiras = new List <string>();
                Dictionary <string, List <Bugg> > JiraIDtoBugg = new Dictionary <string, List <Bugg> >();

                List <Bugg> Buggs = new List <Bugg>(100);
                foreach (var Top in PatternAndCount)
                {
                    Bugg NewBugg = new Bugg();

                    Bugg RealBugg = RealBuggs.Where(X => X.Pattern == Top.Key).FirstOrDefault();
                    if (RealBugg != null)
                    {
                        using (FAutoScopedLogTimer TopTimer = new FAutoScopedLogTimer(string.Format("{0}:{1}", Buggs.Count + 1, RealBugg.Id)))
                        {
                            // Index												// number
                            NewBugg.Id              = RealBugg.Id;                                                      // CrashGroup URL (a link to the Bugg)
                            NewBugg.TTPID           = RealBugg.TTPID;                                                   // JIRA
                            NewBugg.FixedChangeList = RealBugg.FixedChangeList;                                         // FixCL
                            NewBugg.NumberOfCrashes = Top.Value;                                                        // # Occurrences
                            NewBugg.Pattern         = RealBugg.Pattern;                                                 // # Occurrences

                            //NewBugg.BuildVersion =

                            var CrashesForBugg = Crashes.Where(Crash => Crash.Pattern == Top.Key).ToList();

                            NewBugg.AffectedVersions      = new SortedSet <string>();
                            NewBugg.AffectedMajorVersions = new SortedSet <string>();                            // 4.4, 4.5 and so
                            NewBugg.BranchesFoundIn       = new SortedSet <string>();
                            NewBugg.AffectedPlatforms     = new SortedSet <string>();

                            HashSet <string> MachineIds = new HashSet <string>();
                            int FirstCLAffected         = int.MaxValue;

                            foreach (var Crash in CrashesForBugg)
                            {
                                // Only add machine if the number has 32 characters
                                if (Crash.MachineID != null && Crash.MachineID.Length == 32)
                                {
                                    MachineIds.Add(Crash.MachineID);
                                }

                                // Ignore bad build versions.
                                // @TODO yrx 2015-02-17 What about launcher?
                                if (Crash.BuildVersion.StartsWith("4."))
                                {
                                    if (!string.IsNullOrEmpty(Crash.BuildVersion))
                                    {
                                        NewBugg.AffectedVersions.Add(Crash.BuildVersion);
                                    }
                                    if (!string.IsNullOrEmpty(Crash.Branch) && Crash.Branch.StartsWith("UE4"))
                                    {
                                        NewBugg.BranchesFoundIn.Add(Crash.Branch);
                                    }

                                    int CrashBuiltFromCL = 0;
                                    int.TryParse(Crash.BuiltFromCL, out CrashBuiltFromCL);
                                    if (CrashBuiltFromCL > 0)
                                    {
                                        FirstCLAffected = Math.Min(FirstCLAffected, CrashBuiltFromCL);
                                    }

                                    if (!string.IsNullOrEmpty(Crash.Platform))
                                    {
                                        // Platform = "Platform [Desc]";
                                        var PlatSubs = Crash.Platform.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                                        if (PlatSubs.Length >= 1)
                                        {
                                            NewBugg.AffectedPlatforms.Add(PlatSubs[0]);
                                        }
                                    }
                                }
                            }

                            // CopyToJira
                            NewBugg.ToJiraFirstCLAffected = FirstCLAffected;

                            if (NewBugg.AffectedVersions.Count > 0)
                            {
                                NewBugg.BuildVersion = NewBugg.AffectedVersions.Last();                                 // Latest Version Affected
                            }


                            foreach (var AffectedBuild in NewBugg.AffectedVersions)
                            {
                                var Subs = AffectedBuild.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                                if (Subs.Length >= 2)
                                {
                                    string MajorVersion = Subs[0] + "." + Subs[1];
                                    NewBugg.AffectedMajorVersions.Add(MajorVersion);
                                }
                            }

                            NewBugg.NumberOfUniqueMachines = MachineIds.Count;                                          // # Affected Users
                            string LatestCLAffected = CrashesForBugg.                                                   // CL of the latest build
                                                      Where(Crash => Crash.BuildVersion == NewBugg.BuildVersion).
                                                      Max(Crash => Crash.BuiltFromCL);

                            int ILatestCLAffected = -1;
                            int.TryParse(LatestCLAffected, out ILatestCLAffected);
                            NewBugg.LatestCLAffected = ILatestCLAffected;                                               // Latest CL Affected

                            string LatestOSAffected = CrashesForBugg.OrderByDescending(Crash => Crash.TimeOfCrash).First().Platform;
                            NewBugg.LatestOSAffected = LatestOSAffected;                                        // Latest Environment Affected

                            NewBugg.TimeOfFirstCrash = RealBugg.TimeOfFirstCrash;                               // First Crash Timestamp

                            // ToJiraSummary
                            var Callstack = RealBugg.GetFunctionCalls();
                            NewBugg.ToJiraSummary = Callstack.Count > 1 ? Callstack[0] : "No valid callstack found";

                            // ToJiraVersions
                            NewBugg.ToJiraVersions = new List <object>();
                            foreach (var Version in NewBugg.AffectedMajorVersions)
                            {
                                bool bValid = JC.GetNameToVersions().ContainsKey(Version);
                                if (bValid)
                                {
                                    NewBugg.ToJiraVersions.Add(JC.GetNameToVersions()[Version]);
                                }
                            }

                            // ToJiraBranches
                            NewBugg.ToJiraBranches = new List <object>();
                            foreach (var Platform in NewBugg.BranchesFoundIn)
                            {
                                string CleanedBranch = Platform.Contains("UE4-Releases") ? "UE4-Releases" : Platform;
                                Dictionary <string, object> JiraBranch = null;
                                JC.GetNameToBranchFoundIn().TryGetValue(CleanedBranch, out JiraBranch);
                                if (JiraBranch != null && !NewBugg.ToJiraBranches.Contains(JiraBranch))
                                {
                                    NewBugg.ToJiraBranches.Add(JiraBranch);
                                }
                            }

                            // ToJiraPlatforms
                            NewBugg.ToJiraPlatforms = new List <object>();
                            foreach (var Platform in NewBugg.AffectedPlatforms)
                            {
                                bool bValid = JC.GetNameToPlatform().ContainsKey(Platform);
                                if (bValid)
                                {
                                    NewBugg.ToJiraPlatforms.Add(JC.GetNameToPlatform()[Platform]);
                                }
                            }

                            // Verify valid JiraID, this may be still a TTP
                            if (!string.IsNullOrEmpty(NewBugg.TTPID))
                            {
                                int TTPID = 0;
                                int.TryParse(NewBugg.TTPID, out TTPID);

                                if (TTPID == 0)
                                {
                                    AddBuggJiraMapping(NewBugg, ref FoundJiras, ref JiraIDtoBugg);
                                }
                            }

                            Buggs.Add(NewBugg);
                        }
                    }
                    else
                    {
                        FLogger.WriteEvent("Bugg for pattern " + Top.Key + " not found");
                    }
                }

                if (BuggIDToBeAddedToJira > 0)
                {
                    var Bugg = Buggs.Where(X => X.Id == BuggIDToBeAddedToJira).FirstOrDefault();
                    if (Bugg != null)
                    {
                        Bugg.CopyToJira();
                        AddBuggJiraMapping(Bugg, ref FoundJiras, ref JiraIDtoBugg);
                    }
                }

                if (JC.CanBeUsed())
                {
                    // Grab the data form JIRA.
                    string JiraSearchQuery = string.Join(" OR ", FoundJiras);

                    using (FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer("JiraResults"))
                    {
                        var JiraResults = JC.SearchJiraTickets(
                            JiraSearchQuery,
                            new string[]
                        {
                            "key",                                          // string
                            "summary",                                      // string
                            "components",                                   // System.Collections.ArrayList, Dictionary<string,object>, name
                            "resolution",                                   // System.Collections.Generic.Dictionary`2[System.String,System.Object], name
                            "fixVersions",                                  // System.Collections.ArrayList, Dictionary<string,object>, name
                            "customfield_11200"                             // string
                        });


                        // Jira Key, Summary, Components, Resolution, Fix version, Fix changelist
                        foreach (var Jira in JiraResults)
                        {
                            string JiraID = Jira.Key;

                            string Summary = (string)Jira.Value["summary"];

                            string ComponentsText = "";
                            System.Collections.ArrayList Components = (System.Collections.ArrayList)Jira.Value["components"];
                            foreach (Dictionary <string, object> Component in Components)
                            {
                                ComponentsText += (string)Component["name"];
                                ComponentsText += " ";
                            }

                            Dictionary <string, object> ResolutionFields = (Dictionary <string, object>)Jira.Value["resolution"];
                            string Resolution = ResolutionFields != null ? (string)ResolutionFields["name"] : "";

                            string FixVersionsText = "";
                            System.Collections.ArrayList FixVersions = (System.Collections.ArrayList)Jira.Value["fixVersions"];
                            foreach (Dictionary <string, object> FixVersion in FixVersions)
                            {
                                FixVersionsText += (string)FixVersion["name"];
                                FixVersionsText += " ";
                            }

                            int FixCL = Jira.Value["customfield_11200"] != null ? (int)(decimal)Jira.Value["customfield_11200"] : 0;

                            var BuggsForJira = JiraIDtoBugg[JiraID];

                            foreach (Bugg Bugg in BuggsForJira)
                            {
                                Bugg.JiraSummary         = Summary;
                                Bugg.JiraComponentsText  = ComponentsText;
                                Bugg.JiraResolution      = Resolution;
                                Bugg.JiraFixVersionsText = FixVersionsText;
                                if (FixCL != 0)
                                {
                                    Bugg.JiraFixCL = FixCL.ToString();
                                }
                            }
                        }
                    }
                }

                return(new ReportsViewModel
                {
                    Buggs = Buggs,
                    /*Crashes = Crashes,*/
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    TotalAffectedUsers = TotalAffectedUsers,
                    TotalAnonymousCrashes = TotalAnonymousCrashes,
                    TotalUniqueAnonymousCrashes = TotalUniqueAnonymousCrashes
                });
            }
        }
Exemple #44
0
 /// <summary>Gets a set of user's names from the group name</summary>
 public HashSet<string> GetUserNamesFromGroupName( string GroupName )
 {
     using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(UserGroup=" + GroupName + ")" ) )
     {
         int UserGroupId = FindOrAddGroup( GroupName );
         var UserNames = Context.Users.Where( X => X.UserGroupId == UserGroupId ).Select( X => X.UserName );
         return new HashSet<string>( UserNames );
     }
 }
Exemple #45
0
        /// <summary>
        /// Gets a container of crash counts per user group for all crashes.
        /// </summary>
        /// <returns>A dictionary of user group names, and the count of crashes for each group.</returns>
        public Dictionary<string, int> GetCountsByGroup()
        {
            // @TODO yrx 2014-11-06 Optimize?
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + " SQL OPT" ) )
            {
                Dictionary<string, int> Results = new Dictionary<string, int>();

                try
                {
                    var GroupCounts =
                    (
                        from UserDetail in Context.Users
                        join UserGroupDetail in Context.UserGroups on UserDetail.UserGroupId equals UserGroupDetail.Id
                        group UserDetail by UserGroupDetail.Name into GroupCount
                        select new { Key = GroupCount.Key, Count = GroupCount.Count() }
                    );

                    foreach( var GroupCount in GroupCounts )
                    {
                        Results.Add( GroupCount.Key, GroupCount.Count );
                    }

                    // Add in all groups, even though there are no crashes associated
                    IEnumerable<string> UserGroups = ( from UserGroupDetail in Context.UserGroups select UserGroupDetail.Name );
                    foreach( string UserGroupName in UserGroups )
                    {
                        if( !Results.Keys.Contains( UserGroupName ) )
                        {
                            Results[UserGroupName] = 0;
                        }
                    }
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in GetCountsByGroup: " + Ex.ToString() );
                }

                return Results;
            }
        }
Exemple #46
0
        /// <summary>
        /// Find a user group, or add it if it doesn't exist. Return the id of the user group.
        /// </summary>
        /// <param name="UserGroupName">The user group name to find or add.</param>
        /// <returns>The id of the user group that was found or added.</returns>
        /// <remarks>All user group interaction is done this way to remove any dependencies on pre-populated tables.</remarks>
        public int FindOrAddGroup( string UserGroupName )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(GroupName=" + UserGroupName + ")" ) )
            {
                int UserGroupNameId = 0;
                try
                {
                    IQueryable<int> UserGroups = ( from UserGroupDetail in Context.UserGroups
                                                   where UserGroupDetail.Name.ToLower() == UserGroupName.ToLower()
                                                   select UserGroupDetail.Id );

                    // If there is no existing group, add a new one
                    if( UserGroups.Count() == 0 )
                    {
                        UserGroup NewUserGroup = new UserGroup();
                        NewUserGroup.Name = UserGroupName;
                        Context.UserGroups.InsertOnSubmit( NewUserGroup );

                        Context.SubmitChanges();
                        UserGroupNameId = NewUserGroup.Id;
                    }
                    else
                    {
                        UserGroupNameId = UserGroups.First();
                    }
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "FindOrAddUserGroup: " + Ex.ToString() );
                }

                return UserGroupNameId;
            }
        }
        /// <summary>
        /// Retrieves a list of function names from a list of function name ids.
        /// Primarily used to fill GetFunctionCalls in CachedDataService
        /// </summary>
        /// <param name="Ids">A list of unique function name ids.</param>
        /// <returns>A list of strings that make up a callstack.</returns>
        public List<string> GetFunctionCalls( List<int> Ids )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(Ids.Count=" + Ids.Count + ")" ) )
            {
                List<string> FunctionCalls = new List<string>();
                try
                {
                    List<FunctionCall> Funcs = BuggsDataContext.FunctionCalls.Where( FuncCall => Ids.Contains( FuncCall.Id ) ).ToList();
                    // Order by Ids
                    foreach( int Id in Ids )
                    {
                        var Found = Funcs.Find( FC => FC.Id == Id );
                        FunctionCalls.Add( Found.Call );
                    }
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in GetFunctionCalls: " + Ex.ToString() );
                }

                return FunctionCalls;
            }
        }
Exemple #48
0
		/// <summary>
		/// Return the top lines of a callstack.
		/// </summary>
		/// <returns>A list of callstack entries.</returns>
		public List<string> GetFunctionCalls()
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(Id=" + this.Id + ")" ) )
			{
				BuggRepository LocalBuggRepository = new BuggRepository();
				List<string> Results = LocalBuggRepository.GetFunctionCalls( Pattern );
				return Results;
			}
		}
        /// <summary>
        /// Retrieve all Buggs matching the search criteria.
        /// </summary>
        /// <param name="FormData">The incoming form of search criteria from the client.</param>
        /// <returns>A view to display the filtered Buggs.</returns>
        public BuggsViewModel GetResults( FormHelper FormData )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() ) )
            {
                // Right now we take a Result IQueryable starting with ListAll() Buggs then we widdle away the result set by tacking on
                // Linq queries. Essentially it's Results.ListAll().Where().Where().Where().Where().Where().Where()
                // Could possibly create more optimized queries when we know exactly what we're querying
                // The downside is that if we add more parameters each query may need to be updated.... Or we just add new case statements
                // The other downside is that there's less code reuse, but that may be worth it.

                IQueryable<Bugg> Results = null;
                int Skip = ( FormData.Page - 1 ) * FormData.PageSize;
                int Take = FormData.PageSize;

                // Get every Bugg.
                Results = ListAll();

                // Look at all Buggs that are still 'open' i.e. the last crash occurred in our date range.
                Results = FilterByDate( Results, FormData.DateFrom, FormData.DateTo );

                // Filter results by build version.
                Results = FilterByBuildVersion( Results, FormData.BuildVersion );

                // Run at the end
                if( !string.IsNullOrEmpty( FormData.SearchQuery ) )
                {
                    Results = Search( Results, FormData.SearchQuery );
                }

                // Filter by Crash Type
                if( FormData.CrashType != "All" )
                {
                    switch( FormData.CrashType )
                    {
                        case "Crashes":
                            Results = Results.Where( BuggInstance => BuggInstance.CrashType == 1 );
                            break;
                        case "Assert":
                            Results = Results.Where( BuggInstance => BuggInstance.CrashType == 2 );
                            break;
                        case "Ensure":
                            Results = Results.Where( BuggInstance => BuggInstance.CrashType == 3 );
                            break;
                        case "CrashesAsserts":
                            Results = Results.Where( BuggInstance => BuggInstance.CrashType == 1 || BuggInstance.CrashType == 2 );
                            break;
                    }
                }

                // Get UserGroup ResultCounts
                Dictionary<string, int> GroupCounts = GetCountsByGroup( Results );

                // Filter by user group if present
                Results = FilterByUserGroup( Results, FormData.UserGroup );

                // Pass in the results and return them sorted properly
                IEnumerable<Bugg> SortedResults = GetSortedResults( Results, FormData.SortTerm, ( FormData.SortOrder == "Descending" ), FormData.DateFrom, FormData.DateTo );

                // Grab just the results we want to display on this page
                SortedResults = SortedResults.Skip( Skip ).Take( Take ).ToList();

                return new BuggsViewModel
                {
                    Results = SortedResults,
                    PagingInfo = new PagingInfo { CurrentPage = FormData.Page, PageSize = FormData.PageSize, TotalResults = Results.Count() },
                    SortTerm = FormData.SortTerm,
                    SortOrder = FormData.SortOrder,
                    UserGroup = FormData.UserGroup,
                    CrashType = FormData.CrashType,
                    SearchQuery = FormData.SearchQuery,
                    DateFrom = (long)( FormData.DateFrom - CrashesViewModel.Epoch ).TotalMilliseconds,
                    DateTo = (long)( FormData.DateTo - CrashesViewModel.Epoch ).TotalMilliseconds,
                    BuildVersion = FormData.BuildVersion,
                    GroupCounts = GroupCounts,
                };
            }
        }
Exemple #50
0
		/// <summary>
		/// Return lines of processed callstack entries.
		/// </summary>
		/// <param name="StartIndex">The starting entry of the callstack.</param>
		/// <param name="Count">The number of lines to return.</param>
		/// <returns>Lines of processed callstack entries.</returns>
		public List<CallStackEntry> GetCallStackEntries( int StartIndex, int Count )
		{
			using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(Count=" + Count + ")" ) )
			{
				IEnumerable<CallStackEntry> Results = new List<CallStackEntry>() { new CallStackEntry() };

				if( CallStackContainer != null && CallStackContainer.CallStackEntries != null )
				{
					int MaxCount = Math.Min( Count, CallStackContainer.CallStackEntries.Count );
					Results = CallStackContainer.CallStackEntries.Take( MaxCount );
				}

				return Results.ToList();
			}
		}
        /// <summary>
        /// Filter the list of Buggs by a search query.
        /// </summary>
        /// <param name="Results">The unfiltered set of Buggs.</param>
        /// <param name="Query">The query to use as a filter.</param>
        /// <returns>A filtered set of Buggs.</returns>
        public IQueryable<Bugg> Search( IQueryable<Bugg> Results, string Query )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(Query=" + Query + ")" ) )
            {
                // Also may want to revisit how we search since this could get inefficient for a big search set.
                IQueryable<Bugg> Buggs;
                try
                {
                    string QueryString = HttpUtility.HtmlDecode( Query.ToString() );
                    if( QueryString == null )
                    {
                        QueryString = "";
                    }

                    // Take out terms starting with a -
                    string[] Terms = QueryString.Split( "-, ;+".ToCharArray(), StringSplitOptions.RemoveEmptyEntries );
                    string TermsToUse = "";
                    foreach( string Term in Terms )
                    {
                        string CallId = GetFunctionCallId( Term ).ToString();
                        if( !TermsToUse.Contains( CallId ) )
                        {
                            TermsToUse = TermsToUse + "+" + CallId;
                        }
                    }

                    Buggs = (IQueryable<Bugg>)Results.Search( new string[] { "Pattern" }, TermsToUse.Split( "+".ToCharArray() ) );
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in Search: " + Ex.ToString() );
                    Buggs = Results;
                }
                return Buggs;
            }
        }
        /// <summary>
        /// Show detailed information about a crash.
        /// </summary>
        /// <param name="CrashesForm">A form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the crash we wish to show the details of.</param>
        /// <returns>A view to show crash details.</returns>
        public ActionResult Show(FormCollection CrashesForm, int id)
        {
            using (var logTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + id + ")", bCreateNewLog: true))
            {
                CallStackContainer currentCallStack = null;

                // Update the selected crash based on the form contents
                var currentCrash = _unitOfWork.CrashRepository.GetById(id);

                if (currentCrash == null)
                {
                    return(RedirectToAction("Index"));
                }

                string FormValue;

                FormValue = CrashesForm["SetStatus"];
                if (!string.IsNullOrEmpty(FormValue))
                {
                    currentCrash.Status = FormValue;
                }

                FormValue = CrashesForm["SetFixedIn"];
                if (!string.IsNullOrEmpty(FormValue))
                {
                    currentCrash.FixedChangeList = FormValue;
                }

                FormValue = CrashesForm["SetTTP"];
                if (!string.IsNullOrEmpty(FormValue))
                {
                    currentCrash.Jira = FormValue;
                }

                // Valid to set description to an empty string
                FormValue = CrashesForm["Description"];
                if (FormValue != null)
                {
                    currentCrash.Description = FormValue;
                }

                currentCallStack    = new CallStackContainer(currentCrash);
                currentCrash.Module = currentCallStack.GetModuleName();

                //Set call stack properties
                currentCallStack.bDisplayModuleNames          = true;
                currentCallStack.bDisplayFunctionNames        = true;
                currentCallStack.bDisplayFileNames            = true;
                currentCallStack.bDisplayFilePathNames        = true;
                currentCallStack.bDisplayUnformattedCallStack = false;

                currentCrash.CallStackContainer = new CallStackContainer(currentCrash);

                // Populate the crash with the correct user data
                //_crashRepo.PopulateUserInfo( CurrentCrash );
                //_crashRepo.SubmitChanges();

                var Model = new CrashViewModel {
                    Crash = currentCrash, CallStack = currentCallStack
                };
                Model.GenerationTime = logTimer.GetElapsedSeconds().ToString("F2");
                return(View("Show", Model));
            }
        }
        /// <summary>
        /// Filter a set of Buggs by user group name.
        /// </summary>
        /// <param name="SetOfBuggs">The unfiltered set of Buggs.</param>
        /// <param name="UserGroup">The user group name to filter by.</param>
        /// <returns>The set of Buggs by users in the requested user group.</returns>
        public IQueryable<Bugg> FilterByUserGroup( IQueryable<Bugg> SetOfBuggs, string UserGroup )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(UserGroup=" + UserGroup + ")" ) )
            {
                IQueryable<Bugg> NewSetOfBuggs = null;

                try
                {
                    NewSetOfBuggs =
                    (
                        from BuggDetail in SetOfBuggs
                        join BuggsUserGroupDetail in BuggsDataContext.Buggs_UserGroups on BuggDetail.Id equals BuggsUserGroupDetail.BuggId
                        join UserGroupDetail in BuggsDataContext.UserGroups on BuggsUserGroupDetail.UserGroupId equals UserGroupDetail.Id
                        where UserGroupDetail.Name.Contains( UserGroup )
                        select BuggDetail
                    );

                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in FilterByUserGroup: " + Ex.ToString() );
                }

                return NewSetOfBuggs;
            }
        }
        //static readonly int MinNumberOfCrashes = 2;

        /// <summary>
        /// Retrieve all Buggs matching the search criteria.
        /// </summary>
        /// <param name="FormData">The incoming form of search criteria from the client.</param>
        /// <returns>A view to display the filtered Buggs.</returns>
        public CSV_ViewModel GetResults(FormHelper FormData)
        {
            BuggRepository  BuggsRepo = new BuggRepository();
            CrashRepository CrashRepo = new CrashRepository();

            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                string AnonymousGroup = "Anonymous";
                //List<String> Users = FRepository.Get().GetUserNamesFromGroupName( AnonumousGroup );
                int              AnonymousGroupID      = FRepository.Get(BuggsRepo).FindOrAddGroup(AnonymousGroup);
                HashSet <int>    AnonumousIDs          = FRepository.Get(BuggsRepo).GetUserIdsFromUserGroup(AnonymousGroup);
                int              AnonymousID           = AnonumousIDs.First();
                HashSet <string> UserNamesForUserGroup = FRepository.Get(BuggsRepo).GetUserNamesFromGroupName(AnonymousGroup);

                // Enable to narrow results and improve debugging performance.
                //FormData.DateFrom = FormData.DateTo.AddDays( -1 );
                FormData.DateTo = FormData.DateTo.AddDays(1);

                var FilteringQueryJoin = CrashRepo
                                         .ListAll()
                                         .Where(c => c.EpicAccountId != "")
                                         // Only crashes and asserts
                                         .Where(c => c.CrashType == 1 || c.CrashType == 2)
                                         // Only anonymous user
                                         .Where(c => c.UserNameId == AnonymousID)
                                         // Filter be date
                                         .Where(c => c.TimeOfCrash > FormData.DateFrom && c.TimeOfCrash < FormData.DateTo)
                                         .Join
                                         (
                    CrashRepo.Context.Buggs_Crashes,
                    c => c,
                    bc => bc.Crash,
                    (c, bc) => new
                {
                    GameName     = c.GameName,
                    TimeOfCrash  = c.TimeOfCrash.Value,
                    BuiltFromCL  = c.BuiltFromCL,
                    PlatformName = c.PlatformName,
                    EngineMode   = c.EngineMode,
                    MachineId    = c.MachineId,
                    Module       = c.Module,
                    BuildVersion = c.BuildVersion,
                    Jira         = c.Jira,
                    Branch       = c.Branch,
                    CrashType    = c.CrashType.Value,
                    EpicId       = c.EpicAccountId,
                    BuggId       = bc.BuggId,
                }
                                         );

                var FilteringQueryCrashes = CrashRepo
                                            .ListAll()
                                            .Where(c => c.EpicAccountId != "")
                                            // Only crashes and asserts
                                            .Where(c => c.CrashType == 1 || c.CrashType == 2)
                                            // Only anonymous user
                                            .Where(c => c.UserNameId == AnonymousID);

                int TotalCrashes = CrashRepo
                                   .ListAll()
                                   .Count();

                int TotalCrashesYearToDate = CrashRepo
                                             .ListAll()
                                             // Year to date
                                             .Where(c => c.TimeOfCrash > new DateTime(DateTime.UtcNow.Year, 1, 1))
                                             .Count();

                var CrashesFilteredWithDateQuery = FilteringQueryCrashes
                                                   // Filter be date
                                                   .Where(c => c.TimeOfCrash > FormData.DateFrom && c.TimeOfCrash < FormData.DateTo);

                int CrashesFilteredWithDate = CrashesFilteredWithDateQuery
                                              .Count();

                int CrashesYearToDateFiltered = FilteringQueryCrashes
                                                // Year to date
                                                .Where(c => c.TimeOfCrash > new DateTime(DateTime.UtcNow.Year, 1, 1))
                                                .Count();

                int AffectedUsersFiltered = FilteringQueryCrashes
                                            .Select(c => c.EpicAccountId)
                                            .Distinct()
                                            .Count();

                int UniqueCrashesFiltered = FilteringQueryCrashes
                                            .Select(c => c.Pattern)
                                            .Distinct()
                                            .Count();


                int NumCrashes = FilteringQueryJoin.Count();

                // Get all users
                // SLOW
                //var Users = FRepository.Get( BuggsRepo ).GetAnalyticsUsers().ToDictionary( X => X.EpicAccountId, Y => Y );

                // Export data to the file.
                string CSVPathname = Path.Combine(Settings.Default.CrashReporterCSV, DateTime.UtcNow.ToString("yyyy-MM-dd.HH-mm-ss"));
                CSVPathname += string
                               .Format("__[{0}---{1}]__{2}",
                                       FormData.DateFrom.ToString("yyyy-MM-dd"),
                                       FormData.DateTo.ToString("yyyy-MM-dd"),
                                       NumCrashes)
                               + ".csv";

                string ServerPath = Server.MapPath(CSVPathname);
                var    CSVFile    = new StreamWriter(ServerPath, true, Encoding.UTF8);

                using (FAutoScopedLogTimer ExportToCSVTimer = new FAutoScopedLogTimer("ExportToCSV"))
                {
                    var RowType = FilteringQueryJoin.FirstOrDefault().GetType();

                    string AllProperties = "";
                    foreach (var Property in RowType.GetProperties())
                    {
                        AllProperties += Property.Name;
                        AllProperties += "; ";
                    }

                    // Write header
                    CSVFile.WriteLine(AllProperties);

                    foreach (var Row in FilteringQueryJoin)
                    {
                        var BVParts = Row.BuildVersion.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                        if (BVParts.Length > 2 && BVParts[0] != "0")
                        {
                            string CleanEngineVersion = string.Format("{0}.{1}.{2}", BVParts[0], BVParts[1], BVParts[2]);

                            string[] RowProperties = new string[]
                            {
                                Row.GameName,
                                Row.TimeOfCrash.ToString(),
                                Row.BuiltFromCL,
                                Row.PlatformName,
                                Row.EngineMode,
                                Row.MachineId,
                                Row.Module,
                                CleanEngineVersion,
                                Row.Jira,
                                Row.Branch,
                                Row.CrashType == 1 ? "Crash" : "Assert",
                                Row.EpicId,
                                Row.BuggId.ToString()
                            };

                            string JoinedLine = string.Join("; ", RowProperties);
                            JoinedLine += "; ";

                            CSVFile.WriteLine(JoinedLine);
                        }
                    }

                    CSVFile.Flush();
                    CSVFile.Close();
                    CSVFile = null;
                }

                List <FCSVRow> CSVRows = FilteringQueryJoin
                                         .OrderByDescending(X => X.TimeOfCrash)
                                         .Take(32)
                                         .Select(c => new FCSVRow
                {
                    GameName     = c.GameName,
                    TimeOfCrash  = c.TimeOfCrash,
                    BuiltFromCL  = c.BuiltFromCL,
                    PlatformName = c.PlatformName,
                    EngineMode   = c.EngineMode,
                    MachineId    = c.MachineId,
                    Module       = c.Module,
                    BuildVersion = c.BuildVersion,
                    Jira         = c.Jira,
                    Branch       = c.Branch,
                    CrashType    = c.CrashType,
                    EpicId       = c.EpicId,
                    BuggId       = c.BuggId,
                })
                                         .ToList();

                return(new CSV_ViewModel
                {
                    CSVRows = CSVRows,
                    CSVPathname = CSVPathname,
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTimeFrom = FormData.DateFrom,
                    DateTimeTo = FormData.DateTo,
                    AffectedUsersFiltered = AffectedUsersFiltered,
                    UniqueCrashesFiltered = UniqueCrashesFiltered,
                    CrashesFilteredWithDate = CrashesFilteredWithDate,
                    TotalCrashes = TotalCrashes,
                    TotalCrashesYearToDate = TotalCrashesYearToDate,
                });
            }
        }
Exemple #55
0
        /// <summary>
        /// Retrieve all Buggs matching the search criteria.
        /// </summary>
        /// <param name="FormData">The incoming form of search criteria from the client.</param>
        /// <returns>A view to display the filtered Buggs.</returns>
        public CSV_ViewModel GetResults(FormHelper FormData)
        {
            using (var logTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                var anonymousGroup        = _unitOfWork.UserGroupRepository.First(data => data.Name == "Anonymous");
                var anonymousGroupId      = anonymousGroup.Id;
                var anonumousIDs          = new HashSet <int>(anonymousGroup.Users.Select(data => data.Id));
                var anonymousId           = anonumousIDs.First();
                var userNamesForUserGroup = new HashSet <string>(anonymousGroup.Users.Select(data => data.UserName));

                // Enable to narrow results and improve debugging performance.
                //FormData.DateFrom = FormData.DateTo.AddDays( -1 );
                //FormData.DateTo = FormData.DateTo.AddDays( 1 );

                var filteringQueryJoin = _unitOfWork.CrashRepository
                                         .ListAll()
                                         .Where(c => c.EpicAccountId != "")
                                         // Only Crashes, GPUCrashes and asserts
                                         .Where(c => c.CrashType == 1 || c.CrashType == 2 || c.CrashType == 4)
                                         // Only anonymous user
                                         .Where(c => c.UserId == anonymousId)
                                         // Filter be date
                                         .Where(c => c.TimeOfCrash > FormData.DateFrom && c.TimeOfCrash < FormData.DateTo)
                                         .Select
                                         (
                    c => new
                {
                    GameName     = c.GameName,
                    TimeOfCrash  = c.TimeOfCrash,
                    BuiltFromCL  = c.ChangelistVersion,
                    PlatformName = c.PlatformName,
                    EngineMode   = c.EngineMode,
                    MachineId    = c.ComputerName,
                    Module       = c.Module,
                    BuildVersion = c.BuildVersion,
                    Jira         = c.Jira,
                    Branch       = c.Branch,
                    CrashType    = c.CrashType,
                    EpicId       = c.EpicAccountId,
                    BuggId       = c.Bugg.Id
                }
                                         );

                var filteringQueryCrashes = _unitOfWork.CrashRepository
                                            .ListAll()
                                            .Where(c => c.EpicAccountId != null)
                                                                                  // Only Crashes and asserts
                                            .Where(c => c.CrashType == 1 || c.CrashType == 2 || c.CrashType == 4)
                                                                                  // Only anonymous user
                                            .Where(c => c.UserId == anonymousId); //44

                //Server timeout
                var totalCrashes = _unitOfWork.CrashRepository.ListAll().Count();

                var startOfYear            = new DateTime(DateTime.UtcNow.Year, 1, 1);
                var totalCrashesYearToDate = _unitOfWork.CrashRepository
                                             .ListAll().Count(c => c.TimeOfCrash > startOfYear);

                var CrashesFilteredWithDateQuery = filteringQueryCrashes
                                                   // Filter be date
                                                   .Where(c => c.TimeOfCrash > FormData.DateFrom && c.TimeOfCrash < FormData.DateTo);

                int CrashesFilteredWithDate = CrashesFilteredWithDateQuery
                                              .Count();

                int CrashesYearToDateFiltered = filteringQueryCrashes.Count(c => c.TimeOfCrash > startOfYear);

                //DB server timeout
                int AffectedUsersFiltered = filteringQueryCrashes.Select(c => c.EpicAccountId).Distinct().Count();

                //DB server time out
                int UniqueCrashesFiltered = filteringQueryCrashes.Select(c => c.Pattern).Count();

                int NumCrashes = filteringQueryJoin.Count();

                // Export data to the file.
                string CSVPathname = Path.Combine(Settings.Default.CrashReporterCSV, DateTime.UtcNow.ToString("yyyy-MM-dd.HH-mm-ss"));
                CSVPathname += string
                               .Format("__[{0}---{1}]__{2}",
                                       FormData.DateFrom.ToString("yyyy-MM-dd"),
                                       FormData.DateTo.ToString("yyyy-MM-dd"),
                                       NumCrashes)
                               + ".csv";

                var serverPath = Server.MapPath(CSVPathname);
                var csvFile    = new StreamWriter(serverPath, true, Encoding.UTF8);

                using (var exportToCsvTimer = new FAutoScopedLogTimer("ExportToCSV"))
                {
                    var rowType = filteringQueryJoin.FirstOrDefault().GetType();

                    string AllProperties = "";
                    foreach (var Property in rowType.GetProperties())
                    {
                        AllProperties += Property.Name;
                        AllProperties += "; ";
                    }

                    // Write header
                    csvFile.WriteLine(AllProperties);

                    foreach (var Row in filteringQueryJoin)
                    {
                        var BVParts = Row.BuildVersion.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                        if (BVParts.Length > 2 && BVParts[0] != "0")
                        {
                            var cleanEngineVersion = string.Format("{0}.{1}.{2}", BVParts[0], BVParts[1], BVParts[2]);

                            var rowProperties = new string[]
                            {
                                Row.GameName,
                                Row.TimeOfCrash.ToString(),
                                Row.BuiltFromCL,
                                Row.PlatformName,
                                Row.EngineMode,
                                Row.MachineId,
                                Row.Module,
                                cleanEngineVersion,
                                Row.Jira,
                                Row.Branch,
                                Row.CrashType == 1 ? "Crash" : "Assert",
                                Row.EpicId,
                                Row.BuggId.ToString()
                            };

                            var joinedLine = string.Join("; ", rowProperties);
                            joinedLine += "; ";

                            csvFile.WriteLine(joinedLine);
                        }
                    }

                    csvFile.Flush();
                    csvFile.Close();
                    csvFile = null;
                }

                List <FCSVRow> CSVRows = filteringQueryJoin
                                         .OrderByDescending(X => X.TimeOfCrash)
                                         .Take(32)
                                         .Select(c => new FCSVRow
                {
                    GameName     = c.GameName,
                    TimeOfCrash  = c.TimeOfCrash,
                    BuiltFromCL  = c.BuiltFromCL,
                    PlatformName = c.PlatformName,
                    EngineMode   = c.EngineMode,
                    MachineId    = c.MachineId,
                    Module       = c.Module,
                    BuildVersion = c.BuildVersion,
                    Jira         = c.Jira,
                    Branch       = c.Branch,
                    CrashType    = c.CrashType,
                    EpicId       = c.EpicId,
                    BuggId       = c.BuggId,
                })
                                         .ToList();

                return(new CSV_ViewModel()
                {
                    CSVRows = CSVRows,
                    CSVPathname = CSVPathname,
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTimeFrom = FormData.DateFrom,
                    DateTimeTo = FormData.DateTo,
                    AffectedUsersFiltered = AffectedUsersFiltered,
                    UniqueCrashesFiltered = UniqueCrashesFiltered,
                    CrashesFilteredWithDate = CrashesFilteredWithDate,
                    TotalCrashes = totalCrashes,
                    TotalCrashesYearToDate = totalCrashesYearToDate,
                });
            }
        }
        /// <summary>
        /// Get a Bugg from an id
        /// </summary>
        /// <param name="Id">The id of a Bugg.</param>
        /// <returns>A Bugg representing a group of crashes.</returns>
        public Bugg GetBugg( int Id )
        {
            using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString() + "(" + Id + ")" ) )
            {
                Bugg Result = null;

                try
                {
                    Result =
                    (
                        from BuggDetail in BuggsDataContext.Buggs
                        where BuggDetail.Id == Id
                        select BuggDetail
                    ).FirstOrDefault();
                }
                catch( Exception Ex )
                {
                    Debug.WriteLine( "Exception in GetBugg: " + Ex.ToString() );
                }

                return Result;
            }
        }
        /// <summary>
        /// Return a view model containing a sorted list of crashes based on the user input.
        /// </summary>
        /// <param name="FormData">The user input from the client.</param>
        /// <returns>A view model to use to display a list of crashes.</returns>
        /// <remarks>The filtering mechanism works by generating a fluent query to describe the set of crashes we wish to view. Basically, 'Select.Where().Where().Where().Where()' etc.
        /// The filtering is applied in the following order:
        /// 1. Get all crashes.
        /// 2. Filter between the start and end dates.
        /// 3. Apply the search query.
        /// 4. Filter by the branch.
        /// 5. Filter by the game name.
        /// 6. Filter by the type of reports to view.
        /// 7. Filter by the user group.
        /// 8. Sort the results by the sort term.
        /// 9. Take one page of results.</remarks>
        public CrashesViewModel GetResults(FormHelper FormData)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString()))
            {
                UsersMapping UniqueUser = null;

                IEnumerable <Crash> Results = null;
                int Skip = (FormData.Page - 1) * FormData.PageSize;
                int Take = FormData.PageSize;

                var ResultsAll = ConstructQueryForFiltering(FormData);

                // Filter by data and get as enumerable.
                Results = FilterByDate(ResultsAll, FormData.DateFrom, FormData.DateTo);

                // Filter by BuggId
                if (!string.IsNullOrEmpty(FormData.BuggId))
                {
                    int  BuggId = 0;
                    bool bValid = int.TryParse(FormData.BuggId, out BuggId);

                    if (bValid)
                    {
                        BuggRepository Buggs   = new BuggRepository();
                        Bugg           NewBugg = Buggs.GetBugg(BuggId);

                        if (NewBugg != null)
                        {
                            List <Crash> Crashes   = NewBugg.GetCrashes();
                            var          NewResult = Results.Intersect(Crashes, new CrashComparer());
                            Results = NewResult;
                        }
                    }
                }

                // Get UserGroup ResultCounts
                Dictionary <string, int> GroupCounts = GetCountsByGroupFromCrashes(Results);

                // Filter by user group if present
                int UserGroupId;
                if (!string.IsNullOrEmpty(FormData.UserGroup))
                {
                    UserGroupId = FRepository.Get(this).FindOrAddGroup(FormData.UserGroup);
                }
                else
                {
                    UserGroupId = 1;
                }

                HashSet <int> UserIdsForGroup = FRepository.Get(this).GetUserIdsFromUserGroupId(UserGroupId);

                using (FScopedLogTimer LogTimer3 = new FScopedLogTimer("CrashRepository.Results.Users"))
                {
                    List <Crash> NewResults = new List <Crash>();
                    foreach (Crash Crash in Results)
                    {
                        if (UserIdsForGroup.Contains(Crash.UserNameId.Value))
                        {
                            NewResults.Add(Crash);
                        }
                    }

                    Results = NewResults;
                }

                // Pass in the results and return them sorted properly
                Results = GetSortedResults(Results, FormData.SortTerm, (FormData.SortOrder == "Descending"));

                // Get the Count for pagination
                int ResultCount = 0;
                using (FScopedLogTimer LogTimer3 = new FScopedLogTimer("CrashRepository.Results.Users"))
                {
                    ResultCount = Results.Count();
                }


                // Grab just the results we want to display on this page
                Results = Results.Skip(Skip).Take(Take);

                using (FScopedLogTimer LogTimer3 = new FScopedLogTimer("CrashRepository.GetResults.GetCallstacks"))
                {
                    // Process call stack for display
                    foreach (Crash CrashInstance in Results)
                    {
                        // Put callstacks into an list so we can access them line by line in the view
                        CrashInstance.CallStackContainer = GetCallStack(CrashInstance);
                    }
                }

                return(new CrashesViewModel
                {
                    Results = Results,
                    PagingInfo = new PagingInfo {
                        CurrentPage = FormData.Page, PageSize = FormData.PageSize, TotalResults = ResultCount
                    },
                    SortOrder = FormData.SortOrder,
                    SortTerm = FormData.SortTerm,
                    UserGroup = FormData.UserGroup,
                    CrashType = FormData.CrashType,
                    SearchQuery = FormData.SearchQuery,
                    UsernameQuery = FormData.UsernameQuery,
                    EpicIdOrMachineQuery = FormData.EpicIdOrMachineQuery,
                    MessageQuery = FormData.MessageQuery,
                    BuiltFromCL = FormData.BuiltFromCL,
                    BuggId = FormData.BuggId,
                    JiraQuery = FormData.JiraQuery,
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    BranchName = FormData.BranchName,
                    VersionName = FormData.VersionName,
                    PlatformName = FormData.PlatformName,
                    GameName = FormData.GameName,
                    GroupCounts = GroupCounts,
                    RealUserName = UniqueUser != null?UniqueUser.ToString() : null,
                });
            }
        }
        /// <summary>
        /// The main view of the dash board.
        /// </summary>
        /// <returns>A view showing two charts of Crashes over time.</returns>
        public ActionResult Index()
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString(), bCreateNewLog: true))
            {
                DateTime Today         = DateTime.UtcNow;
                DateTime AfewMonthsAgo = Today.AddMonths(-6);

                FAutoScopedLogTimer LogTimerSQL = new FAutoScopedLogTimer("CrashesFilterByDate", "", "");

                // Get engine versions from the last 6 months.
                var           TempVersions      = _Crashes.GetVersions();
                List <string> EngineUE4Versions = new List <string>();
                foreach (var Version in TempVersions)
                {
                    if (Version.StartsWith("4."))
                    {
                        EngineUE4Versions.Add(Version);
                    }
                }

                // Only 4 latest version.
                EngineUE4Versions = EngineUE4Versions.OrderByDescending(item => item).Take(5).ToList();

                var endDate = Today.AddDays(1);

                IQueryable <Crash> CrashesInTimeFrame = _Crashes.ListAll()
                                                        .Where(MyCrash => MyCrash.TimeOfCrash >= AfewMonthsAgo && MyCrash.TimeOfCrash <= endDate);
                //IEnumerable<Crash> Crashes = FRepository.Get().Crashes.FilterByDate( FRepository.Get().Crashes.ListAll(), AfewMonthsAgo, Today );
                var VMinimalCrashes = CrashesInTimeFrame.Select(Crash => new
                {
                    TimeOfCrash   = Crash.TimeOfCrash,
                    UserID        = Crash.UserId,
                    EngineVersion = Crash.BuildVersion,
                })
                                      .ToList();

                List <FCrashMinimal> MinimalCrashes = new List <FCrashMinimal>(VMinimalCrashes.Count);
                foreach (var Anotype in VMinimalCrashes)
                {
                    MinimalCrashes.Add(new FCrashMinimal(Anotype.TimeOfCrash, Anotype.UserID, Anotype.EngineVersion));
                }
                LogTimerSQL.Dispose();

                HashSet <int> AnonumousIDs = new HashSet <int>(_entities.UserGroups.First(data => data.Name == "Anonymous").Users.Select(data => data.Id));
                int           AnonymousID  = AnonumousIDs.First();

                int GeneralUserGroupId  = 1;         //FRepository.Get( _Crashes ).FindOrAddGroup( "General" );
                int CoderUserGroupId    = 3;         //FRepository.Get( _Crashes ).FindOrAddGroup( "Coder" );
                int EngineQAUserGroupId = 22;        //FRepository.Get( _Crashes ).FindOrAddGroup( "EngineQA" );
                int GameQAUserGroupId   = 21;        //FRepository.Get( _Crashes ).FindOrAddGroup( "GameQA" );

                // Weekly
                Dictionary <DateTime, int> WeeklyGeneralResults  = GetWeeklyCountsByGroup(MinimalCrashes, GeneralUserGroupId);
                Dictionary <DateTime, int> WeeklyCoderResults    = GetWeeklyCountsByGroup(MinimalCrashes, CoderUserGroupId);
                Dictionary <DateTime, int> WeeklyEngineQAResults = GetWeeklyCountsByGroup(MinimalCrashes, EngineQAUserGroupId);
                Dictionary <DateTime, int> WeeklyGameQAResults   = GetWeeklyCountsByGroup(MinimalCrashes, GameQAUserGroupId);

                Dictionary <string, Dictionary <DateTime, int> > WeeklyEngineVersionResults = new Dictionary <string, Dictionary <DateTime, int> >();
                foreach (string UE4Version in EngineUE4Versions)
                {
                    Dictionary <DateTime, int> Results = GetWeeklyCountsByVersion(MinimalCrashes, UE4Version, AnonymousID);
                    WeeklyEngineVersionResults.Add(UE4Version, Results);
                }

                Dictionary <DateTime, int> WeeklyAllResults = GetWeeklyCountsByGroup(MinimalCrashes, AllUserGroupId);

                // Daily
                Dictionary <DateTime, int> DailyGeneralResults  = GetDailyCountsByGroup(MinimalCrashes, GeneralUserGroupId);
                Dictionary <DateTime, int> DailyCoderResults    = GetDailyCountsByGroup(MinimalCrashes, CoderUserGroupId);
                Dictionary <DateTime, int> DailyEngineQAResults = GetDailyCountsByGroup(MinimalCrashes, EngineQAUserGroupId);
                Dictionary <DateTime, int> DailyGameQAResults   = GetDailyCountsByGroup(MinimalCrashes, GameQAUserGroupId);


                Dictionary <string, Dictionary <DateTime, int> > DailyEngineVersionResults = new Dictionary <string, Dictionary <DateTime, int> >();
                foreach (string UE4Version in EngineUE4Versions)
                {
                    Dictionary <DateTime, int> Results = GetDailyCountsByVersion(MinimalCrashes, UE4Version, AnonymousID);
                    DailyEngineVersionResults.Add(UE4Version, Results);
                }

                Dictionary <DateTime, int> DailyAllResults = GetDailyCountsByGroup(MinimalCrashes, AllUserGroupId);

                // Get daily buggs stats.
                List <Bugg> Buggs = _Buggs.ListAll().Where(Bugg => Bugg.TimeOfFirstCrash >= AfewMonthsAgo).ToList();

                Dictionary <DateTime, int> BuggDailyAllResults =
                    (
                        from Bugg in Buggs
                        group Bugg by Bugg.TimeOfFirstCrash.Value.Date into GroupCount
                        orderby GroupCount.Key
                        select new { Count = GroupCount.Count(), Date = GroupCount.Key }
                    ).ToDictionary(x => x.Date, y => y.Count);


                string CrashesByWeek = "";

                foreach (KeyValuePair <DateTime, int> WeeklyResult in WeeklyAllResults)
                {
                    int GeneralCrashes = 0;
                    WeeklyGeneralResults.TryGetValue(WeeklyResult.Key, out GeneralCrashes);

                    int CoderCrashes = 0;
                    WeeklyCoderResults.TryGetValue(WeeklyResult.Key, out CoderCrashes);

                    int EngineQACrashes = 0;
                    WeeklyEngineQAResults.TryGetValue(WeeklyResult.Key, out EngineQACrashes);

                    int GameQACrashes = 0;
                    WeeklyGameQAResults.TryGetValue(WeeklyResult.Key, out GameQACrashes);

                    string AnonymousLine = "";
                    foreach (var VersionCrashes in WeeklyEngineVersionResults)
                    {
                        int EngineVersionCrashes = 0;
                        VersionCrashes.Value.TryGetValue(WeeklyResult.Key, out EngineVersionCrashes);

                        AnonymousLine += EngineVersionCrashes;
                        AnonymousLine += ", ";
                    }

                    int Year  = WeeklyResult.Key.Year;
                    int Month = WeeklyResult.Key.AddMonths(-1).Month;
                    if (WeeklyResult.Key.Month == 13 || WeeklyResult.Key.Month == 1)
                    {
                        Month = 0;
                    }

                    int Day = WeeklyResult.Key.Day + 6;

                    string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AnonymousLine + WeeklyResult.Value + "], ";
                    CrashesByWeek += Line;
                }

                CrashesByWeek = CrashesByWeek.TrimEnd(", ".ToCharArray());

                string CrashesByDay = "";
                foreach (KeyValuePair <DateTime, int> DailyResult in DailyAllResults)
                {
                    int GeneralCrashes = 0;
                    DailyGeneralResults.TryGetValue(DailyResult.Key, out GeneralCrashes);

                    int CoderCrashes = 0;
                    DailyCoderResults.TryGetValue(DailyResult.Key, out CoderCrashes);

                    int EngineQACrashes = 0;
                    DailyEngineQAResults.TryGetValue(DailyResult.Key, out EngineQACrashes);

                    int GameQACrashes = 0;
                    DailyGameQAResults.TryGetValue(DailyResult.Key, out GameQACrashes);

                    string AnonymousLine = "";
                    foreach (var VersionCrashes in DailyEngineVersionResults)
                    {
                        int EngineVersionCrashes = 0;
                        VersionCrashes.Value.TryGetValue(DailyResult.Key, out EngineVersionCrashes);

                        AnonymousLine += EngineVersionCrashes;
                        AnonymousLine += ", ";
                    }

                    int Year  = DailyResult.Key.Year;
                    int Month = DailyResult.Key.AddMonths(-1).Month;
                    if (DailyResult.Key.Month == 13 || DailyResult.Key.Month == 1)
                    {
                        Month = 0;
                    }

                    int Day = DailyResult.Key.Day;

                    string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + GeneralCrashes + ", " + CoderCrashes + ", " + EngineQACrashes + ", " + GameQACrashes + ", " + AnonymousLine + DailyResult.Value + "], ";
                    CrashesByDay += Line;
                }

                CrashesByDay = CrashesByDay.TrimEnd(", ".ToCharArray());

                string BuggsByDay = "";
                foreach (KeyValuePair <DateTime, int> DailyResult in BuggDailyAllResults)
                {
                    int Year  = DailyResult.Key.Year;
                    int Month = DailyResult.Key.AddMonths(-1).Month;
                    if (DailyResult.Key.Month == 13 || DailyResult.Key.Month == 1)
                    {
                        Month = 0;
                    }

                    int Day = DailyResult.Key.Day;

                    string Line = "[new Date(" + Year + ", " + Month + ", " + Day + "), " + DailyResult.Value + "], ";
                    BuggsByDay += Line;
                }

                BuggsByDay = BuggsByDay.TrimEnd(", ".ToCharArray());

                var ResultDashboard = new DashboardViewModel
                {
                    CrashesByWeek  = CrashesByWeek,
                    CrashesByDay   = CrashesByDay,
                    BuggsByDay     = BuggsByDay,
                    EngineVersions = EngineUE4Versions,
                };
                ResultDashboard.GenerationTime = LogTimer.GetElapsedSeconds().ToString("F2");
                return(View("Index", ResultDashboard));
            }
        }
        /// <summary>
        /// Apply the sort term to a set of crashes.
        /// </summary>
        /// <param name="Results">The unsorted set of crashes.</param>
        /// <param name="SortTerm">The term to sort by. e.g. UserName</param>
        /// <param name="bSortByDescending">Whether to sort ascending or descending.</param>
        /// <returns>A sorted set of crashes.</returns>
        public IEnumerable <Crash> GetSortedResults(IEnumerable <Crash> Results, string SortTerm, bool bSortByDescending)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(SortTerm=" + SortTerm + ")"))
            {
                switch (SortTerm)
                {
                case "Id":
                    //Results = bSortByDescending ? Results.OrderByDescending( CrashInstance => CrashInstance.Id ) : Results.OrderBy( CrashInstance => CrashInstance.Id );
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.Id, bSortByDescending);
                    break;

                case "TimeOfCrash":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.TimeOfCrash, bSortByDescending);
                    break;

                case "UserName":
                    // Note: only works where user is stored by Id
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.UserName, bSortByDescending);

                    //OrderBy( IntermediateQueryable.Join( Context.Users, CrashInstance => CrashInstance.UserNameId, UserInstance => UserInstance.Id,
                    //							( CrashInstance, UserInstance ) => new { CrashInstance, UserInstance.UserName } ),
                    //							Joined => Joined.UserName, bSortByDescending ).Select( Joined => Joined.CrashInstance ).AsEnumerable();
                    break;

                case "RawCallStack":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.RawCallStack, bSortByDescending);
                    break;

                case "GameName":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.GameName, bSortByDescending);
                    break;

                case "EngineMode":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.EngineMode, bSortByDescending);
                    break;

                case "FixedChangeList":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.FixedChangeList, bSortByDescending);
                    break;

                case "TTPID":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.Jira, bSortByDescending);
                    break;

                case "Branch":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.Branch, bSortByDescending);
                    break;

                case "ChangeListVersion":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.BuiltFromCL, bSortByDescending);
                    break;

                case "ComputerName":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.MachineId, bSortByDescending);
                    break;

                case "PlatformName":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.PlatformName, bSortByDescending);
                    break;

                case "Status":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.Status, bSortByDescending);
                    break;

                case "Module":
                    Results = EnumerableOrderBy(Results, CrashInstance => CrashInstance.Module, bSortByDescending);
                    break;
                }

                return(Results);
            }
        }
        /// <summary>
        /// Show detailed information about a crash.
        /// </summary>
        /// <param name="CrashesForm">A form of user data passed up from the client.</param>
        /// <param name="id">The unique id of the crash we wish to show the details of.</param>
        /// <returns>A view to show crash details.</returns>
        public ActionResult Show(FormCollection CrashesForm, int id)
        {
            using (FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer(this.GetType().ToString() + "(CrashId=" + id + ")"))
            {
                CallStackContainer CurrentCallStack = null;

                // Update the selected crash based on the form contents
                Crash CurrentCrash = LocalCrashRepository.GetCrash(id);

                if (CurrentCrash == null)
                {
                    return(RedirectToAction(""));
                }

                string FormValue;

                FormValue = CrashesForm["SetStatus"];
                if (!string.IsNullOrEmpty(FormValue))
                {
                    CurrentCrash.Status = FormValue;
                }

                FormValue = CrashesForm["SetFixedIn"];
                if (!string.IsNullOrEmpty(FormValue))
                {
                    CurrentCrash.FixedChangeList = FormValue;
                }

                FormValue = CrashesForm["SetTTP"];
                if (!string.IsNullOrEmpty(FormValue))
                {
                    CurrentCrash.TTPID = FormValue;
                }

                // Valid to set description to an empty string
                FormValue = CrashesForm["Description"];
                if (FormValue != null)
                {
                    CurrentCrash.Description = FormValue;
                }

                CurrentCallStack = new CallStackContainer(CurrentCrash);

                // Set callstack properties
                CurrentCallStack.bDisplayModuleNames          = true;
                CurrentCallStack.bDisplayFunctionNames        = true;
                CurrentCallStack.bDisplayFileNames            = true;
                CurrentCallStack.bDisplayFilePathNames        = true;
                CurrentCallStack.bDisplayUnformattedCallStack = false;

                CurrentCrash.CallStackContainer = LocalCrashRepository.GetCallStack(CurrentCrash);

                // Populate the crash with the correct user data
                LocalCrashRepository.PopulateUserInfo(CurrentCrash);
                LocalCrashRepository.SubmitChanges();

                return(View("Show", new CrashViewModel {
                    Crash = CurrentCrash, CallStack = CurrentCallStack
                }));
            }
        }