/// <summary> /// Returns infrastructure history for requested component. /// </summary> /// <param name="componentId">Component identifier.</param> /// <param name="date">The date to get details for.</param> /// <returns>Component details.</returns> public async Task <InfrastructureComponentSummaryWithHistory> GetDetails(string componentId, DateTime date) { // 1. get audit which represents the "date". var audit = await this.db.Set <AuditEntity>() .Include(i => i.InfrastructureComponent) .AsNoTracking() .Where(i => i.Date.Date == date.Date && i.ComponentId == componentId) .OrderByDescending(i => i.Date) .FirstOrDefaultAsync(); // 1.1. try to get InfrastructureComponent if no audit fo a requested date string componentName; if (audit == null) { var component = await this.db.Set <InfrastructureComponentEntity>() .AsNoTracking() .FirstOrDefaultAsync(i => i.ComponentId == componentId); if (component == null) { throw new JosekiException($"Unknown componentId: {componentId}"); } componentName = component.ComponentName; } else { componentName = audit.InfrastructureComponent.ComponentName; } // 2. prepare history for the last month var today = DateTime.UtcNow.Date; var componentHistory = new List <ScoreHistoryItem>(); foreach (var summaryDate in Enumerable.Range(-30, 31).Select(i => today.AddDays(i))) { var historyItem = await this.cache.GetCountersSummary(componentId, summaryDate); componentHistory.Add(new ScoreHistoryItem(summaryDate, historyItem.Score)); } // 3. when the history is ready, calculate summary for the requested date. var currentSummary = await this.cache.GetCountersSummary(componentId, date.Date); var componentDetails = new InfrastructureComponentSummaryWithHistory { Date = date, Component = new InfrastructureComponent(componentId) { Category = InfraScoreExtensions.GetCategory(componentId), Name = componentName, }, Current = currentSummary, ScoreHistory = componentHistory.OrderBy(i => i.RecordedAt).ToArray(), }; // if no audit for a given date - return result if (audit == null) { componentDetails.Checks = new Check[0]; componentDetails.CategorySummaries = new CheckCategorySummary[0]; return(componentDetails); } // 4. Get all the check details var checkResults = await this.db.Set <CheckResultEntity>() .AsNoTracking() .Include(i => i.Check) .Where(i => i.AuditId == audit.Id) .Select(i => new { i.ComponentId, i.Check.CheckId, i.Check.Severity, i.Check.Category, i.Check.Description, i.Value, i.Message, }) .ToArrayAsync(); var checks = new List <Check>(); foreach (var entity in checkResults) { CheckResult checkResult; switch (entity.Value) { case CheckValue.Failed: if (entity.Severity == CheckSeverity.Critical || entity.Severity == CheckSeverity.High) { checkResult = CheckResult.Failed; } else { checkResult = CheckResult.Warning; } break; case CheckValue.Succeeded: checkResult = CheckResult.Success; break; default: checkResult = CheckResult.NoData; break; } var message = entity.Message ?? entity.Description; var(collection, resource, tags) = ParseCollectionAndResource(entity.ComponentId); resource.Owner = await this.ownershipCache.GetOwner(entity.ComponentId); var check = new Check( date, collection, resource, entity.Category, new CheckControl(entity.CheckId, message), checkResult) { Tags = tags, }; checks.Add(check); } componentDetails.Checks = checks.ToArray(); // 5. enrich with category descriptions var scannerType = audit.InfrastructureComponent.ScannerId.Split('/').First(); var categories = checks .Select(i => i.Category) .Distinct() .Select(i => new { Id = $"{scannerType}.{i.Replace(" ", string.Empty)}".ToLowerInvariant(), Category = i }) .ToDictionary(i => i.Id, j => j.Category); var ids = categories.Keys.ToArray(); var docs = await this.docsHandler.GetItemsByIds(ids); componentDetails.CategorySummaries = docs .Select(i => new CheckCategorySummary { Description = i.Content, Category = categories[i.Id] }) .ToArray(); return(componentDetails); }
/// <summary> /// Returns autocomplete data for selected field. /// </summary> /// <param name="date">The date to get details for.</param> /// <returns>string array.</returns> public async Task <List <OverviewCheck> > GetChecks(DateTime date) { var theDay = date.Date; var theNextDay = theDay.AddDays(1); var oneDayAudits = await this.db.Set <AuditEntity>() .Include(i => i.InfrastructureComponent) .AsNoTracking() .Where(i => i.Date >= theDay && i.Date < theNextDay) .ToArrayAsync(); var audits = oneDayAudits .GroupBy(i => i.ComponentId) .Select(i => i.OrderByDescending(a => a.Date).First()) .ToArray(); // 4. Get all the check details var checkResults = await this.db.Set <CheckResultEntity>() .Include(i => i.Check) .Include(i => i.Audit) .AsNoTracking() .Where(i => audits.Contains(i.Audit)) .Select(i => new { component = new InfrastructureComponent(i.Audit.InfrastructureComponent.ComponentId) { Category = InfraScoreExtensions.GetCategory(i.Audit.InfrastructureComponent.ComponentId), Name = i.Audit.InfrastructureComponent.ComponentName, }, i.ComponentId, i.Check.CheckId, i.Check.Severity, i.Check.Category, i.Check.Description, i.Value, i.Message, }) .ToArrayAsync(); var checks = new List <OverviewCheck>(); foreach (var entity in checkResults) { CheckResult checkResult; switch (entity.Value) { case CheckValue.Failed: if (entity.Severity == CheckSeverity.Critical || entity.Severity == CheckSeverity.High) { checkResult = CheckResult.Failed; } else { checkResult = CheckResult.Warning; } break; case CheckValue.Succeeded: checkResult = CheckResult.Success; break; default: checkResult = CheckResult.NoData; break; } var message = entity.Message ?? entity.Description; var(collection, resource, tags) = ParseCollectionAndResource(entity.ComponentId); resource.Owner = await this.ownershipCache.GetOwner(entity.ComponentId); var check = new OverviewCheck( date, collection, resource, entity.Category, new CheckControl(entity.CheckId, message), checkResult, entity.component) { Tags = tags, }; checks.Add(check); } return(checks); }