Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First iteration of a CMMC Scoring chart page #4273

Merged
merged 1 commit into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Maturity/CmmcBusiness.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
ο»Ώ////////////////////////////////
//
// Copyright 2024 Battelle Energy Alliance, LLC
//
//
////////////////////////////////
using CSETWebCore.DataLayer.Model;
using CSETWebCore.Helpers;
using CSETWebCore.Interfaces.AdminTab;
using CSETWebCore.Interfaces.Helpers;
using CSETWebCore.Model.Maturity;
using System.Collections.Generic;
using System.Linq;

namespace CSETWebCore.Business.Maturity
{
/// <summary>
///
/// </summary>
public class CmmcBusiness
{
private CSETContext _context;
private readonly IAssessmentUtil _assessmentUtil;
private readonly IAdminTabBusiness _adminTabBusiness;

private int _maturityModelId;

Check warning on line 26 in CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Maturity/CmmcBusiness.cs

View workflow job for this annotation

GitHub Actions / .NET Analysis

The field 'CmmcBusiness._maturityModelId' is never used

Check warning on line 26 in CSETWebApi/CSETWeb_Api/CSETWebCore.Business/Maturity/CmmcBusiness.cs

View workflow job for this annotation

GitHub Actions / .NET Analysis

The field 'CmmcBusiness._maturityModelId' is never used

private static object myLock = new object();

private TranslationOverlay _overlay;

private AdditionalSupplemental _addlSuppl;


private readonly int modelIdCmmc2 = 19;

private int _level1Max = 15;
private int _level2Max = 110;


/// <summary>
/// CTOR
/// </summary>
public CmmcBusiness(CSETContext context, IAssessmentUtil assessmentUtil, IAdminTabBusiness adminTabBusiness)
{
_context = context;
_assessmentUtil = assessmentUtil;
_adminTabBusiness = adminTabBusiness;

_addlSuppl = new AdditionalSupplemental(context);

_overlay = new TranslationOverlay();
}


/// <summary>
///
/// </summary>
public CmmcScores GetCmmcScores(int assessmentId)
{
var response = new CmmcScores();


// Level 1
response.Level1Score = GetScoreForLevel(assessmentId, 1);



// Level 2
var sprs = GetSPRSScore(assessmentId);
response.Level2Score = sprs.SprsScore;
response.Level2Active = (response.Level1Score == _level1Max);



// Level 3
response.Level3Score = GetScoreForLevel(assessmentId, 3);
response.Level3Active = (response.Level2Score == _level2Max);


return response;
}


/// <summary>
/// Sums up the number of "Y" and "NA" answers for CMMC2F questions
/// at a given maturity level.
/// </summary>
public int GetScoreForLevel(int assessmentId, int level)
{
var goodAnswers = new List<string>() { "Y", "NA" };

var levelId = _context.MATURITY_LEVELS
.Where(x => x.Level == level && x.Maturity_Model_Id == modelIdCmmc2)
.Select(x => x.Maturity_Level_Id)
.FirstOrDefault();

var query = from a in _context.ANSWER
join q in _context.MATURITY_QUESTIONS on a.Question_Or_Requirement_Id equals q.Mat_Question_Id
where q.Maturity_Level_Id == levelId && a.Assessment_Id == assessmentId
select a;

var answerList = query.ToList().Select(x => x.Answer_Text).ToList();

var score = answerList.Where(x => goodAnswers.Contains(x)).Count();

return score;
}


/// <summary>
/// Calculates a SPRS score based on the question scoring values in MATURITY_EXTRA.
/// </summary>
/// <param name="assessmentId"></param>
/// <returns></returns>
public SprsScoreModel GetSPRSScore(int assessmentId)
{
var response = new SprsScoreModel();

IList<SPRSScore> scores = _context.usp_GetSPRSScore(assessmentId);


var maturityExtra = _context.MATURITY_EXTRA.ToList();

var biz = new MaturityBusiness(_context, _assessmentUtil, _adminTabBusiness);
var x = biz.GetMaturityStructureAsXml(assessmentId, true);


int calculatedScore = 110;

foreach (var goal in x.Descendants("Goal"))
{
var d = new SprsDomain();
d.DomainName = goal.Attribute("title").Value;
response.Domains.Add(d);

foreach (var question in goal.Descendants("Question"))
{
var q = new SprsQuestion();
q.Id = question.Attribute("displaynumber").Value;
q.QuestionText = question.Attribute("questiontext").Value;
q.AnswerText = question.Attribute("answer").Value;

int questionID = int.Parse(question.Attribute("questionid").Value);
var mx = maturityExtra.Where(x => x.Maturity_Question_Id == questionID).FirstOrDefault();

switch (q.AnswerText)
{
case "Y":
case "NA":
break;
case "N":
case "U":
if (mx != null)
{
q.Score = mx.SPRSValue ?? 0;
}
break;
}

calculatedScore -= q.Score;

d.Questions.Add(q);
}
}

response.SprsScore = calculatedScore;

// TODO: With the release of CMMC 2.0 Final the gauge is built in the UI and this
// code will not be needed.
var sprsGauge = new Helpers.ReportWidgets.SprsScoreGauge(calculatedScore, 500, 100);
response.GaugeSvg = sprsGauge.ToString();

return response;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
using CSETWebCore.Model.Mvra;



namespace CSETWebCore.Business.Maturity
{
public class MaturityBusiness : IMaturityBusiness
Expand Down Expand Up @@ -277,71 +276,6 @@ public int GetTargetLevel(int assessmentId)
}


/// <summary>
///
/// </summary>
/// <param name="assessmentId"></param>
/// <returns></returns>
public SprsScoreModel GetSPRSScore(int assessmentId)
{
var response = new SprsScoreModel();

IList<SPRSScore> scores = _context.usp_GetSPRSScore(assessmentId);


var maturityExtra = _context.MATURITY_EXTRA.ToList();

var biz = new MaturityBusiness(_context, _assessmentUtil, _adminTabBusiness);
var x = biz.GetMaturityStructureAsXml(assessmentId, true);


int calculatedScore = 110;

foreach (var goal in x.Descendants("Goal"))
{
var d = new SprsDomain();
d.DomainName = goal.Attribute("title").Value;
response.Domains.Add(d);

foreach (var question in goal.Descendants("Question"))
{
var q = new SprsQuestion();
q.Id = question.Attribute("displaynumber").Value;
q.QuestionText = question.Attribute("questiontext").Value;
q.AnswerText = question.Attribute("answer").Value;

int questionID = int.Parse(question.Attribute("questionid").Value);
var mx = maturityExtra.Where(x => x.Maturity_Question_Id == questionID).FirstOrDefault();

switch (q.AnswerText)
{
case "Y":
case "NA":
break;
case "N":
case "U":
if (mx != null)
{
q.Score = (int)mx.SPRSValue;
}
break;
}

calculatedScore -= q.Score;

d.Questions.Add(q);
}
}

response.SprsScore = calculatedScore;

var sprsGauge = new Helpers.ReportWidgets.SprsScoreGauge(calculatedScore, 500, 100);
response.GaugeSvg = sprsGauge.ToString();

return response;
}


/// <summary>
///
/// </summary>
Expand Down
32 changes: 32 additions & 0 deletions CSETWebApi/CSETWeb_Api/CSETWebCore.Model/Maturity/CmmcScores.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
ο»Ώusing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CSETWebCore.Model.Maturity
{
public class CmmcScores
{
public int Level1Score { get; set; }



public int Level2Score { get; set; }

/// <summary>
/// Level 3 is only active if Level 1 is 100% compliant
/// </summary>
public bool Level2Active { get; set; } = false;



public int Level3Score { get; set; }

/// <summary>
/// Level 3 is only active if Level 2 is 100% compliant
/// </summary>
public bool Level3Active { get; set; } = false;

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using CSETWebCore.Business.Authorization;
using CSETWebCore.Business.Document;
using CSETWebCore.Business.Maturity;
using CSETWebCore.DataLayer.Model;
using CSETWebCore.Interfaces.AdminTab;
using CSETWebCore.Interfaces.Document;
using CSETWebCore.Interfaces.Helpers;
using CSETWebCore.Interfaces.Reports;
using CSETWebCore.Model.Document;
using CSETWebCore.Model.Question;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.CodeAnalysis.Elfie.Model.Map;
using System.Collections.Generic;

namespace CSETWebCore.Api.Controllers
{
[CsetAuthorize]
[ApiController]
public class CmmcController : ControllerBase
{
private readonly ITokenManager _tokenManager;
private readonly CSETContext _context;
private readonly IAssessmentUtil _assessmentUtil;
private readonly IAdminTabBusiness _adminTabBusiness;
private readonly IReportsDataBusiness _reports;


/// <summary>
///
/// </summary>
public CmmcController(ITokenManager tokenManager, CSETContext context, IAssessmentUtil assessmentUtil,
IAdminTabBusiness adminTabBusiness, IReportsDataBusiness reports)
{
_tokenManager = tokenManager;
_context = context;
_assessmentUtil = assessmentUtil;
_adminTabBusiness = adminTabBusiness;
_reports = reports;
}


/// <summary>
/// </summary>
[HttpGet]
[Route("api/cmmcscores")]
public IActionResult GetCmmcScores()
{
int assessmentId = _tokenManager.AssessmentForUser();

return Ok(new CmmcBusiness(_context, _assessmentUtil, _adminTabBusiness).GetCmmcScores(assessmentId));
}


/// <summary>
/// TODO: This should be deprecated with CMMC2 final
/// </summary>
[HttpGet]
[Route("api/SPRSScore")]
public IActionResult GetSPRSScore()
{
int assessmentId = _tokenManager.AssessmentForUser();

return Ok(new CmmcBusiness(_context, _assessmentUtil, _adminTabBusiness).GetSPRSScore(assessmentId));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -181,18 +181,6 @@ public IActionResult GetLevelScoresByGroup(int mat_model_id)
}


/// <summary>
/// </summary>
[HttpGet]
[Route("api/SPRSScore")]
public IActionResult GetSPRSScore()
{
int assessmentId = _tokenManager.AssessmentForUser();

return Ok(new MaturityBusiness(_context, _assessmentUtil, _adminTabBusiness).GetSPRSScore(assessmentId));
}


[HttpGet]
[Route("api/results/compliancebylevel")]
public IActionResult GetComplianceByLevel()
Expand Down
4 changes: 4 additions & 0 deletions CSETWebNg/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ import { AllCommentsmarkedComponent } from './reports/all-commentsmarked/all-com
import { AllReviewedComponent } from './reports/all-reviewed/all-reviewed.component';
import { AnalyticsResultsComponent } from './assessment/results/analytics-results/analytics-results.component';
import { Cmmc2LevelsComponent } from './assessment/prepare/maturity/cmmc2-levels/cmmc2-levels.component';
import { Cmmc2ScoresComponent } from './assessment/results/mat-cmmc2/cmmc2-scores/cmmc2-scores.component';
import { Cmmc2ScorecardComponent } from './assessment/results/mat-cmmc2/cmmc2-scorecard/cmmc2-scorecard.component';

const appRoutes: Routes = [

Expand Down Expand Up @@ -462,6 +464,8 @@ const appRoutes: Routes = [
{ path: 'cmmc-compliance', component: CmmcComplianceComponent },
{ path: 'cmmc-gaps', component: CmmcGapsComponent },
{ path: 'sprs-score', component: SprsScoreComponent },
{ path: 'cmmc2-scores', component: Cmmc2ScoresComponent },
{ path: 'cmmc2-scorecard', component: Cmmc2ScorecardComponent },
{ path: 'cmmc2-level-results', component: Cmmc2LevelResultsComponent },
{ path: 'cmmc2-domain-results', component: Cmmc2DomainResultsComponent },
{ path: 'rra-summary-all', component: RraSummaryAllComponent },
Expand Down
Loading
Loading