Skip to content

Commit

Permalink
Merge pull request #4280 from cisagov/cmmc-fix
Browse files Browse the repository at this point in the history
Fixed SPRS score calculation.
  • Loading branch information
LaddieZeigler authored Dec 5, 2024
2 parents 7aa644c + 09b6ecc commit 03d4662
Show file tree
Hide file tree
Showing 11 changed files with 44 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ public class CmmcBusiness

private List<MATURITY_EXTRA> _maturityExtra;

private List<string> _goodAnswerOptions = new List<string>() {"Y", "NA"};

private readonly List<string> _goodAnswerOptions = new List<string>() {"Y", "NA"};

// CMMC 2.0 FINAL model ID
private readonly int modelIdCmmc2 = 19;

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


/// <summary>
Expand Down Expand Up @@ -77,7 +77,7 @@ public CmmcScores GetCmmcScores(int assessmentId)

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


Expand Down Expand Up @@ -121,13 +121,9 @@ join q in _context.MATURITY_QUESTIONS on a.Question_Or_Requirement_Id equals q.M
/// Returns a list of scorecards, one for each active level.
/// </summary>
/// <returns></returns>
public List<SprsScoreModel> GetLevelScorecards(int assessmentId)
public List<CmmcScoreModel> GetLevelScorecards(int assessmentId)
{
var response = new List<SprsScoreModel>();


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

var response = new List<CmmcScoreModel>();

var biz = new MaturityBusiness(_context, _assessmentUtil, _adminTabBusiness);

Expand Down Expand Up @@ -167,15 +163,15 @@ public List<SprsScoreModel> GetLevelScorecards(int assessmentId)
///
/// Questions are also assigned their score/deduction.
/// </summary>
private SprsScoreModel FilterByLevel(XDocument x, int level)
private CmmcScoreModel FilterByLevel(XDocument x, int level)
{
var response = new SprsScoreModel();
var response = new CmmcScoreModel();
response.Level = level;


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


Expand All @@ -186,13 +182,12 @@ private SprsScoreModel FilterByLevel(XDocument x, int level)
continue;
}

var q = new SprsQuestion();
var q = new CmmcQuestion();
q.QuestionId = int.Parse(question.Attribute("questionid").Value);
q.Title = question.Attribute("displaynumber").Value;
q.QuestionText = question.Attribute("questiontext")?.Value;
q.AnswerText = question.Attribute("answer").Value;

// default the question score to 1
q.Score = DeductionForAnswer(q);

d.Questions.Add(q);
Expand All @@ -209,22 +204,11 @@ private SprsScoreModel FilterByLevel(XDocument x, int level)


/// <summary>
///
/// DEPRECATE OR REFACTOR THIS
///
///
/// 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)
public CmmcScoreModel GetSPRSScore(int assessmentId)
{
var response = new SprsScoreModel();

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


//var maturityExtra = _context.MATURITY_EXTRA.ToList();
var response = new CmmcScoreModel();

var biz = new MaturityBusiness(_context, _assessmentUtil, _adminTabBusiness);
var options = new StructureOptions() { IncludeQuestionText = true, IncludeSupplemental = false };
Expand All @@ -235,27 +219,29 @@ public SprsScoreModel GetSPRSScore(int assessmentId)

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

foreach (var question in goal.Descendants("Question"))
{
var q = new SprsQuestion();
var q = new CmmcQuestion();
q.QuestionId = int.Parse(question.Attribute("questionid").Value);
q.Title = question.Attribute("displaynumber").Value;
q.QuestionText = question.Attribute("questiontext").Value;
q.AnswerText = question.Attribute("answer").Value;
q.Score = DeductionForAnswer(q);

int questionID = int.Parse(question.Attribute("questionid").Value);


calculatedScore -= DeductionForAnswer(q);
// Adjust the SPRS score
calculatedScore -= q.Score;

d.Questions.Add(q);
}
}

response.SprsScore = calculatedScore;
response.LevelScore = calculatedScore;

// TODO: With the release of CMMC 2.0 Final the gauge is built in the UI and this
// code will not be needed.
Expand All @@ -267,9 +253,12 @@ public SprsScoreModel GetSPRSScore(int assessmentId)


/// <summary>
///
/// Returns the number of points deducted based on the question's answer.
/// Successful answers (Y, NA) deduct no points.
/// Questions not defined with a point value in MATURITY_EXTRA (e.g., Level 1 and Level 3)
/// default to a 1-point deduction.
/// </summary>
private int DeductionForAnswer(SprsQuestion q)
private int DeductionForAnswer(CmmcQuestion q)
{
if (_goodAnswerOptions.Contains(q.AnswerText))
{
Expand Down
18 changes: 0 additions & 18 deletions CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Manual/CSETContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,24 +148,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
}


public virtual IList<SPRSScore> usp_GetSPRSScore(Nullable<int> assessment_id)
{

if (!assessment_id.HasValue)
throw new ApplicationException("parameters may not be null");

IList<SPRSScore> myrval = null;
this.LoadStoredProc("usp_GenerateSPRSScore")
.WithSqlParam("assessment_id", assessment_id)

.ExecuteStoredProc((handler) =>
{
myrval = handler.ReadToList<SPRSScore>();
});
return myrval;

}


public string ConnectionString { get { return this._connectionString; } }

Expand Down
13 changes: 0 additions & 13 deletions CSETWebApi/CSETWeb_Api/CSETWebCore.DataLayer/Manual/SPRSScore.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -1915,31 +1915,6 @@ public virtual async Task<List<usp_financial_attributesResult>> usp_financial_at
return _;
}

public virtual async Task<List<usp_GenerateSPRSScoreResult>> usp_GenerateSPRSScoreAsync(int? assessment_id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default)
{
var parameterreturnValue = new SqlParameter
{
ParameterName = "returnValue",
Direction = System.Data.ParameterDirection.Output,
SqlDbType = System.Data.SqlDbType.Int,
};

var sqlParameters = new []
{
new SqlParameter
{
ParameterName = "assessment_id",
Value = assessment_id ?? Convert.DBNull,
SqlDbType = System.Data.SqlDbType.Int,
},
parameterreturnValue,
};
var _ = await _context.SqlQueryAsync<usp_GenerateSPRSScoreResult>("EXEC @returnValue = [dbo].[usp_GenerateSPRSScore] @assessment_id = @assessment_id", sqlParameters, cancellationToken);

returnValue?.SetValue(parameterreturnValue.Value);

return _;
}

public virtual async Task<List<usp_getAnswerComponentOverridesResult>> usp_getAnswerComponentOverridesAsync(int? assessment_id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ public partial interface ICsetwebContextProcedures
Task<int> usp_CopyIntoSet_DeleteAsync(string DestinationSetName, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default);
Task<List<usp_countsForLevelsByGroupMaturityModelResult>> usp_countsForLevelsByGroupMaturityModelAsync(int? assessment_id, int? mat_model_id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default);
Task<List<usp_financial_attributesResult>> usp_financial_attributesAsync(int? Assessment_Id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default);
Task<List<usp_GenerateSPRSScoreResult>> usp_GenerateSPRSScoreAsync(int? assessment_id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default);
Task<List<usp_getAnswerComponentOverridesResult>> usp_getAnswerComponentOverridesAsync(int? assessment_id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default);
Task<List<usp_GetAssessmentPieResult>> usp_GetAssessmentPieAsync(int? Assessment_Id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default);
Task<List<usp_getComponentsRankedCategoriesResult>> usp_getComponentsRankedCategoriesAsync(int? assessment_id, OutputParameter<int> returnValue = null, CancellationToken cancellationToken = default);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,35 @@

namespace CSETWebCore.Model.Maturity
{
public class SprsScoreModel
public class CmmcScoreModel
{
public int Level { get; set; }

public int SprsScore { get; set; }
public int LevelScore { get; set; }

public List<SprsDomain> Domains { get; set; }
public List<CmmcDomain> Domains { get; set; }

public string GaugeSvg { get; set; }

public SprsScoreModel()
public CmmcScoreModel()
{
this.Domains = new List<SprsDomain>();
this.Domains = new List<CmmcDomain>();
}
}

public class SprsDomain
public class CmmcDomain
{
public string DomainName { get; set; }

public List<SprsQuestion> Questions { get; set; }
public List<CmmcQuestion> Questions { get; set; }

public SprsDomain()
public CmmcDomain()
{
this.Questions = new List<SprsQuestion>();
this.Questions = new List<CmmcQuestion>();
}
}

public class SprsQuestion
public class CmmcQuestion
{
public int QuestionId { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ <h5>{{t('level.level 2')}}</h5>

<!-- Draw bar -->
<g class="bars" transform="translate(30, 30)">
<rect x="0" y="40" [attr.width]="width" height="20" fill="url(#barGradient)" [matTooltip]="'SPRS: ' + score">
<rect x="0" y="40" [attr.width]="width" height="20" fill="url(#barGradient)" [matTooltip]="'SPRS: ' + score" *ngIf="active">
</rect>
<rect x="0" y="40" [attr.width]="width" height="20" fill="white" stroke="#aaa" [matTooltip]="'SPRS: ' + score" *ngIf="!active">
</rect>
</g>

<!-- Axis line for current score -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<h5>{{t('level.level 3')}}</h5>

<p *ngIf="!active">
{{t('cmmc.scoring.scorecard description')}}
{{t('cmmc.scoring.level2 inactive description')}}
</p>

<svg viewBox="0 0 800 130" [attr.width]="width" height="130" xmlns="http://www.w3.org/2000/svg"
Expand All @@ -39,7 +39,8 @@ <h5>{{t('level.level 3')}}</h5>

<!-- Draw bar -->
<g class="bars" transform="translate(30, 30)">
<rect x="0" y="50" [attr.width]="n(score)" height="20" fill="#034b61" [matTooltip]="score"></rect>
<rect x="0" y="50" [attr.width]="n(score)" height="20" fill="#034b61" [matTooltip]="score" *ngIf="active"></rect>
<rect x="0" y="50" [attr.width]="n(score)" height="20" fill="white" stroke="#aaa" [matTooltip]="score" *ngIf="!active"></rect>
</g>

<!-- Axis line for current score -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<td class="align-top" [class.fw-bold]="q.score != 0" [innerHTML]="q.questionText"></td>
<td class="align-top" [class.fw-bold]="q.score != 0">{{t('answer-options.labels.' + q.answerText.toLowerCase() +
'-cmmc')}}</td>
<td class="align-top" [class.fw-bold]="q.score != 0">{{q.score == 0 ? '' : q.score}}</td>
<td class="align-top align-end" [class.fw-bold]="q.score != 0">{{q.score == 0 ? '' : q.score}}</td>
</tr>
</ng-template>
</ng-template>
Expand Down
3 changes: 2 additions & 1 deletion CSETWebNg/src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,8 @@
"y-cmmc": "Met",
"no-cmmc": "Not Met",
"n-cmmc": "Not Met",
"na-cmmc": "N/A"
"na-cmmc": "N/A",
"u-cmmc": "Unanswered"
},
"placeholders": {
"alt acet": "Description, explanation and/or justification for compensating control",
Expand Down

0 comments on commit 03d4662

Please sign in to comment.