Exemple #1
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 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>
		/// 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() ) )
			{
				// 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 = LocalCrashRepository.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.TTPID = CrashesForm["SetTTP"];
							}
						}
					}

					LocalCrashRepository.SubmitChanges();
				}

				// <STATUS>

				// Parse the contents of the query string, and populate the form
				FormHelper FormData = new FormHelper( Request, CrashesForm, "TimeOfCrash" );
				CrashesViewModel Result = LocalCrashRepository.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;

				return View( "Index", Result );
			}
		}
        /// <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,
                };
            }
        }
        //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,
                };
            }
        }
 /// <summary>
 /// 
 /// </summary>
 /// <returns></returns>
 public ActionResult Index( FormCollection Form )
 {
     using( FAutoScopedLogTimer LogTimer = new FAutoScopedLogTimer( this.GetType().ToString(), bCreateNewLog: true ) )
     {
         FormHelper FormData = new FormHelper( Request, Form, "JustReport" );
         CSV_ViewModel Results = GetResults( FormData );
         Results.GenerationTime = LogTimer.GetElapsedSeconds().ToString( "F2" );
         return View( "Index", Results );
     }
 }
		/// <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?
			// It would be great to have a CSV export of this as well with buggs ID being the key I can then use to join them :)
			// 
			// 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();

				var Crashes = CrashRepo
					.FilterByDate( CrashRepo.ListAll(), FormData.DateFrom, FormData.DateTo )
					// 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.Jira,
						Platform = Crash.PlatformName,
						FixCL = Crash.FixedChangeList,
						BuiltFromCL = Crash.BuiltFromCL,
						Pattern = Crash.Pattern,
						MachineID = Crash.MachineId,
						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();
				const int NumTopRecords = 200;
				var PatternAndCount = PatternToCountOrdered.Take( NumTopRecords ).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>( NumTopRecords );
				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.Jira ) )
							{
								int TTPID = 0;
								int.TryParse( NewBugg.Jira, 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 );

					HashSet<string> InvalidJiras = new HashSet<string>();

					// Simple verification of JIRA
					foreach (var Value in FoundJiras)
					{
						if( Value.Length < 3 || !Value.Contains('-') )
						{
							InvalidJiras.Add(Value);
						}
					}

					foreach (var InvalidJira in InvalidJiras)
					{
						FoundJiras.Remove( InvalidJira );
					}

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

					using( FAutoScopedLogTimer JiraResultsTimer = new FAutoScopedLogTimer( "JiraResults" ) )
					{
						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)
						{

						}


						// 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.Jira ) ) )
					{
						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.CrashesInTimeFrameGroup ).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
				};
			}
		}
		/// <summary>
		/// 
		/// </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( Bugg.JiraSubmitName ) )
					{
						int.TryParse( Entry.ToString().Substring( Bugg.JiraSubmitName.Length ), out BuggIDToBeAddedToJira );
						break;
					}
				}

				ReportsViewModel Results = GetResults( FormData, BuggIDToBeAddedToJira );
				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 )
 {
     FormHelper FormData = new FormHelper( Request, BuggsForm, "CrashesInTimeFrame" );
     BuggsViewModel Results = LocalBuggRepository.GetResults( FormData );
     return View( "Index", Results );
 }
Exemple #10
0
        /// <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;
                IQueryable <Crash> Results    = null;
                int Skip = (FormData.Page - 1) * FormData.PageSize;
                int Take = FormData.PageSize;

                Results = ListAll();
                Results = FilterByDate(Results, FormData.DateFrom, FormData.DateTo);

                // Grab Results
                if (!string.IsNullOrEmpty(FormData.SearchQuery))
                {
                    string DecodedQuery = HttpUtility.HtmlDecode(FormData.SearchQuery).ToLower();
                    using (FScopedLogTimer LogTimer2 = new FScopedLogTimer("CrashRepository.GetResults.FindUserFromQuery" + "(Query=" + DecodedQuery + ")"))
                    {
                        if (!string.IsNullOrEmpty(DecodedQuery))
                        {
                            // Check if we are looking for user name.
                            string[] Params = DecodedQuery.Split(new string[] { "user:"******"SELECT * FROM [analyticsdb-01.dmz.epicgames.net].[CrashReport].[dbo].[UsersMapping] WHERE lower(UserName) = {0} OR lower(UserEmail) = {0}", Params[1]);

                                foreach (UsersMapping TheUser in FoundUsers)
                                {
                                    UniqueUser = TheUser;
                                    break;
                                }
                                if (UniqueUser != null)
                                {
                                    Results = Results.Where(CrashInstance => CrashInstance.EpicAccountId == UniqueUser.EpicAccountId);
                                }
                                else
                                {
                                    Results = Results.Where(CrashInstance => CrashInstance.EpicAccountId == "SomeValueThatIsNotPresentInTheDatabase");
                                }
                            }
                            else
                            {
                                Results = Search(Results, DecodedQuery);
                            }
                        }
                    }
                }

                // Start Filtering the results

                // Filter by BranchName
                if (!string.IsNullOrEmpty(FormData.BranchName))
                {
                    if (FormData.BranchName.StartsWith("-"))
                    {
                        Results =
                            (
                                from CrashDetail in Results
                                where !CrashDetail.Branch.Contains(FormData.BranchName.Substring(1))
                                select CrashDetail
                            );
                    }
                    else
                    {
                        Results =
                            (
                                from CrashDetail in Results
                                where CrashDetail.Branch.Contains(FormData.BranchName)
                                select CrashDetail
                            );
                    }
                }

                // Filter by GameName
                if (!string.IsNullOrEmpty(FormData.GameName))
                {
                    if (FormData.GameName.StartsWith("-"))
                    {
                        Results =
                            (
                                from CrashDetail in Results
                                where !CrashDetail.GameName.Contains(FormData.GameName.Substring(1))
                                select CrashDetail
                            );
                    }
                    else
                    {
                        Results =
                            (
                                from CrashDetail in Results
                                where CrashDetail.GameName.Contains(FormData.GameName)
                                select CrashDetail
                            );
                    }
                }

                // Filter by Crash Type
                if (FormData.CrashType != "All")
                {
                    switch (FormData.CrashType)
                    {
                    case "Crashes":
                        Results = Results.Where(CrashInstance => CrashInstance.CrashType == 1);
                        break;

                    case "Assert":
                        Results = Results.Where(CrashInstance => CrashInstance.CrashType == 2);
                        break;

                    case "Ensure":
                        Results = Results.Where(CrashInstance => CrashInstance.CrashType == 3);
                        break;

                    case "CrashesAsserts":
                        Results = Results.Where(CrashInstance => CrashInstance.CrashType == 1 || CrashInstance.CrashType == 2);
                        break;
                    }
                }

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

                // Filter by user group if present
                int UserGroupId;
                if (!string.IsNullOrEmpty(FormData.UserGroup))
                {
                    UserGroupId = FindOrAddUserGroup(FormData.UserGroup);
                }
                else
                {
                    UserGroupId = 1;
                }
                Results =
                    (
                        from CrashDetail in Results
                        from UserDetail in Context.Users
                        where UserDetail.UserGroupId == UserGroupId &&
                        (CrashDetail.UserNameId == UserDetail.Id || CrashDetail.UserName == UserDetail.UserName)
                        select CrashDetail
                    );

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

                // Get the Count for pagination
                int 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,
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    BranchName = FormData.BranchName,
                    GameName = FormData.GameName,
                    GroupCounts = GroupCounts,
                    RealUserName = UniqueUser != null?UniqueUser.ToString() : null,
                });
            }
        }
Exemple #11
0
        private IQueryable <Crash> ConstructQuery(FormHelper FormData)
        {
            var results = ListAll();

            // Grab Results
            if (!string.IsNullOrEmpty(FormData.SearchQuery))
            {
                if (!string.IsNullOrEmpty(FormData.UsernameQuery))
                {
                    //We only use SearchQuery now for CallStack searching - if there's a searchquery value and a Username value, we need to get rid of the
                    //Username so that we can create a broader search range
                    FormData.UsernameQuery = "";
                }
                string DecodedQuery = HttpUtility.HtmlDecode(FormData.SearchQuery).ToLower();
                using (FScopedLogTimer LogTimer2 = new FScopedLogTimer("CrashRepository.GetResults.FindUserFromQuery" + "(Query=" + DecodedQuery + ")"))
                {
                    results = results.Where(item => item.RawCallStack.Contains(FormData.SearchQuery));
                }
            }

            // Filter by Crash Type
            if (FormData.CrashType != "All")
            {
                switch (FormData.CrashType)
                {
                case "Crashes":
                    results = results.Where(CrashInstance => CrashInstance.CrashType == 1);
                    break;

                case "Assert":
                    results = results.Where(CrashInstance => CrashInstance.CrashType == 2);
                    break;

                case "Ensure":
                    results = results.Where(CrashInstance => CrashInstance.CrashType == 3);
                    break;

                case "CrashesAsserts":
                    results = results.Where(CrashInstance => CrashInstance.CrashType == 1 || CrashInstance.CrashType == 2);
                    break;
                }
            }

            if (!string.IsNullOrEmpty(FormData.UsernameQuery))
            {
                results =
                    (
                        from CrashDetail in results
                        where CrashDetail.UserName.Equals(FormData.UsernameQuery)
                        select CrashDetail
                    );
            }

            // Start Filtering the results
            if (!string.IsNullOrEmpty(FormData.EpicIdQuery))
            {
                var DecodedQuery = HttpUtility.HtmlDecode(FormData.EpicIdQuery).ToLower();
                results =
                    (
                        from CrashDetail in results
                        where CrashDetail.EpicAccountId.Equals(FormData.EpicIdQuery)
                        select CrashDetail
                    );
            }

            if (!string.IsNullOrEmpty(FormData.MachineIdQuery))
            {
                var DecodedQuery = HttpUtility.HtmlDecode(FormData.MachineIdQuery).ToLower();
                results =
                    (
                        from CrashDetail in results
                        where CrashDetail.ComputerName.Equals(FormData.MachineIdQuery)
                        select CrashDetail
                    );
            }

            if (!string.IsNullOrEmpty(FormData.JiraQuery))
            {
                var DecodedQuery = HttpUtility.HtmlDecode(FormData.JiraQuery).ToLower();
                results =
                    (
                        from CrashDetail in results
                        where CrashDetail.TTPID.Equals(FormData.JiraQuery)
                        select CrashDetail
                    );
            }
            // Filter by BranchName
            if (!string.IsNullOrEmpty(FormData.BranchName))
            {
                if (FormData.BranchName.StartsWith("-"))
                {
                    results =
                        (
                            from CrashDetail in results
                            where !CrashDetail.Branch.Contains(FormData.BranchName.Substring(1))
                            select CrashDetail
                        );
                }
                else
                {
                    results =
                        (
                            from CrashDetail in results
                            where CrashDetail.Branch.Equals(FormData.BranchName)
                            select CrashDetail
                        );
                }
            }
            else
            {
                results =
                    (
                        from CrashDetail in results
                        where !CrashDetail.Branch.Equals("UE4-UT-Releases") && !CrashDetail.Branch.Equals("UE4-UT")
                        select CrashDetail
                    );
            }

            // Filter by GameName
            if (!string.IsNullOrEmpty(FormData.GameName))
            {
                if (FormData.GameName.StartsWith("-"))
                {
                    results =
                        (
                            from CrashDetail in results
                            where !CrashDetail.GameName.Contains(FormData.GameName.Substring(1))
                            select CrashDetail
                        );
                }
                else
                {
                    results =
                        (
                            from CrashDetail in results
                            where CrashDetail.GameName.Contains(FormData.GameName)
                            select CrashDetail
                        );
                }
            }

            if (!string.IsNullOrEmpty(FormData.MessageQuery))
            {
                results =
                    (
                        from CrashDetail in results
                        where SqlMethods.Like(CrashDetail.Summary, "%" + FormData.MessageQuery + "%")
                        select CrashDetail
                    );
            }

            if (!string.IsNullOrEmpty(FormData.DescriptionQuery))
            {
                results =
                    (
                        from CrashDetail in results
                        where SqlMethods.Like(CrashDetail.Description, "%" + FormData.DescriptionQuery + "%")
                        select CrashDetail
                    );
            }

            if (!string.IsNullOrEmpty(FormData.SearchQuery))
            {
                results =
                    (
                        from CrashDetail in results
                        where SqlMethods.Like(CrashDetail.RawCallStack, "%" + FormData.SearchQuery + "%")
                        select CrashDetail
                    );
            }

            return(results);
        }
Exemple #12
0
        /// <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 = ConstructQuery(FormData);

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

                // 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,
                    EpicIdQuery = FormData.EpicIdQuery,
                    MachineIdQuery = FormData.MachineIdQuery,
                    DescriptionQuery = FormData.DescriptionQuery,
                    MessageQuery = FormData.MessageQuery,
                    JiraQuery = FormData.JiraQuery,
                    DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                    DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                    BranchName = FormData.BranchName,
                    GameName = FormData.GameName,
                    GroupCounts = GroupCounts,
                    RealUserName = UniqueUser != null?UniqueUser.ToString() : null,
                });
            }
        }
Exemple #13
0
        /// <summary>Constructs query for filtering.</summary>
        private IQueryable <Crash> ConstructQueryForFiltering(FormHelper FormData)
        {
            var Results = ListAll();

            // Grab Results
            string QueryString = HttpUtility.HtmlDecode(FormData.SearchQuery);

            if (!string.IsNullOrEmpty(QueryString))
            {
                if (!string.IsNullOrEmpty(QueryString))
                {
                    //We only use SearchQuery now for CallStack searching - if there's a SearchQuery value and a Username value, we need to get rid of the
                    //Username so that we can create a broader search range
                    FormData.UsernameQuery = "";
                }

                Results =
                    (
                        from CrashDetail in Results
                        where SqlMethods.Like(CrashDetail.RawCallStack, "%" + FormData.SearchQuery + "%")
                        select CrashDetail
                    );
            }

            // Filter by Crash Type
            if (FormData.CrashType != "All")
            {
                switch (FormData.CrashType)
                {
                case "Crashes":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 1);
                    break;

                case "Assert":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 2);
                    break;

                case "Ensure":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 3);
                    break;

                case "CrashesAsserts":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 1 || CrashInstance.CrashType == 2);
                    break;
                }
            }

            // JRX Restore EpicID/UserName searching
            if (!string.IsNullOrEmpty(FormData.UsernameQuery))
            {
                var DecodedUsername = HttpUtility.HtmlDecode(FormData.UsernameQuery).ToLower();
                Results =
                    (
                        from CrashDetail in Results
                        where CrashDetail.UserName.Equals(DecodedUsername)
                        select CrashDetail
                    );
            }

            // Start Filtering the results
            if (!string.IsNullOrEmpty(FormData.EpicIdOrMachineQuery))
            {
                var DecodedEpicOrMachineID = HttpUtility.HtmlDecode(FormData.EpicIdOrMachineQuery).ToLower();
                Results =
                    (
                        from CrashDetail in Results
                        where CrashDetail.EpicAccountId.Equals(DecodedEpicOrMachineID) || CrashDetail.MachineId.Equals(DecodedEpicOrMachineID)
                        select CrashDetail
                    );
            }

            if (!string.IsNullOrEmpty(FormData.JiraQuery))
            {
                var DecodedJIRA = HttpUtility.HtmlDecode(FormData.JiraQuery).ToLower();
                Results =
                    (
                        from CrashDetail in Results
                        where CrashDetail.Jira.Contains(DecodedJIRA)
                        select CrashDetail
                    );
            }

            // Filter by BranchName
            if (!string.IsNullOrEmpty(FormData.BranchName))
            {
                Results =
                    (
                        from CrashDetail in Results
                        where CrashDetail.Branch.Equals(FormData.BranchName)
                        select CrashDetail
                    );
            }
            else
            {
                Results =
                    (
                        from CrashDetail in Results
                        where !CrashDetail.Branch.Contains("UE4-UT")
                        select CrashDetail
                    );
            }

            // Filter by VersionName
            if (!string.IsNullOrEmpty(FormData.VersionName))
            {
                Results =
                    (
                        from CrashDetail in Results
                        where CrashDetail.BuildVersion.Equals(FormData.VersionName)
                        select CrashDetail
                    );
            }

            // Filter by GameName
            if (!string.IsNullOrEmpty(FormData.GameName))
            {
                var DecodedGameName = HttpUtility.HtmlDecode(FormData.GameName).ToLower();

                if (DecodedGameName.StartsWith("-"))
                {
                    Results =
                        (
                            from CrashDetail in Results
                            where !CrashDetail.GameName.Contains(DecodedGameName.Substring(1))
                            select CrashDetail
                        );
                }
                else
                {
                    Results =
                        (
                            from CrashDetail in Results
                            where CrashDetail.GameName.Contains(DecodedGameName)
                            select CrashDetail
                        );
                }
            }

            if (!string.IsNullOrEmpty(FormData.MessageQuery))
            {
                Results =
                    (
                        from CrashDetail in Results
                        where SqlMethods.Like(CrashDetail.Summary, "%" + FormData.MessageQuery + "%") || SqlMethods.Like(CrashDetail.Description, "%" + FormData.MessageQuery + "%")
                        select CrashDetail
                    );
            }

            return(Results);
        }
		/// <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 #15
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 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.

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

                // Get every Bugg.
                var ResultsAll = ListAll();

                // Look at all Buggs that are still 'open' i.e. the last crash occurred in our date range.
                Results = FilterByDate(ResultsAll, 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
                SortedDictionary <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, FormData.UserGroup);

                // Grab just the results we want to display on this page

                var SortedResultsList   = SortedResults.ToList();
                var TotalCountedRecords = SortedResultsList.Count();

                SortedResultsList = SortedResultsList.GetRange(Skip, TotalCountedRecords >= Skip + Take ? Take : TotalCountedRecords);

                return(new BuggsViewModel
                {
                    Results = SortedResultsList,
                    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 #16
0
        /// <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)
        {
            IQueryable <Crash> Results = null;
            int Skip = (FormData.Page - 1) * FormData.PageSize;
            int Take = FormData.PageSize;

            Results = ListAll();
            Results = FilterByDate(Results, FormData.DateFrom, FormData.DateTo);

            // Grab Results
            if (!string.IsNullOrEmpty(FormData.SearchQuery))
            {
                Results = Search(Results, FormData.SearchQuery);
            }

            // Start Filtering the results

            // Filter by BranchName
            if (!string.IsNullOrEmpty(FormData.BranchName))
            {
                if (FormData.BranchName.StartsWith("-"))
                {
                    Results =
                        (
                            from CrashDetail in Results
                            where !CrashDetail.Branch.Contains(FormData.BranchName.Substring(1))
                            select CrashDetail
                        );
                }
                else
                {
                    Results =
                        (
                            from CrashDetail in Results
                            where CrashDetail.Branch.Contains(FormData.BranchName)
                            select CrashDetail
                        );
                }
            }

            // Filter by GameName
            if (!string.IsNullOrEmpty(FormData.GameName))
            {
                if (FormData.GameName.StartsWith("-"))
                {
                    Results =
                        (
                            from CrashDetail in Results
                            where !CrashDetail.GameName.Contains(FormData.GameName.Substring(1))
                            select CrashDetail
                        );
                }
                else
                {
                    Results =
                        (
                            from CrashDetail in Results
                            where CrashDetail.GameName.Contains(FormData.GameName)
                            select CrashDetail
                        );
                }
            }

            // Filter by Crash Type
            if (FormData.CrashType != "All")
            {
                switch (FormData.CrashType)
                {
                case "Crashes":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 1);
                    break;

                case "Assert":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 2);
                    break;

                case "Ensure":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 3);
                    break;

                case "CrashesAsserts":
                    Results = Results.Where(CrashInstance => CrashInstance.CrashType == 1 || CrashInstance.CrashType == 2);
                    break;
                }
            }

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

            // Filter by user group if present
            int UserGroupId;

            if (!string.IsNullOrEmpty(FormData.UserGroup))
            {
                UserGroupId = FindOrAddUserGroup(FormData.UserGroup);
            }
            else
            {
                UserGroupId = 1;
            }
            Results =
                (
                    from CrashDetail in Results
                    from UserDetail in CrashRepositoryDataContext.Users
                    where UserDetail.UserGroupId == UserGroupId &&
                    (CrashDetail.UserNameId == UserDetail.Id || CrashDetail.UserName == UserDetail.UserName)
                    select CrashDetail
                );

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

            // Get the Count for pagination
            int ResultCount = Results.Count();

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

            // 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,
                DateFrom = (long)(FormData.DateFrom - CrashesViewModel.Epoch).TotalMilliseconds,
                DateTo = (long)(FormData.DateTo - CrashesViewModel.Epoch).TotalMilliseconds,
                BranchName = FormData.BranchName,
                GameName = FormData.GameName,
                GroupCounts = GroupCounts,
            });
        }