Skip to content

Commit 85a6d91

Browse files
committed
TD-5402-New feature competency assessment options and labels has been added.
1 parent f4b766c commit 85a6d91

File tree

6 files changed

+826
-5
lines changed

6 files changed

+826
-5
lines changed

DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ int categoryId
5959
bool UpdateOptionalCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus);
6060
bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus);
6161
bool UpdateWorkingGroupTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus);
62+
bool UpdateCompetencyAssessmentOptions(
63+
bool includeLearnerDeclarationPrompt,
64+
bool includesSignposting,
65+
bool linearNavigation,
66+
bool useDescriptionExpanders,
67+
string? questionLabelText,
68+
string? reviewerCommentsLabelText,
69+
int competencyAssessmentId, int adminId);
70+
bool UpdateCompetencyAssessmentOptionsTaskStatus(int assessmentId, bool taskStatus);
6271
void MoveCompetencyInSelfAssessment(int competencyAssessmentId,
6372
int competencyId,
6473
string direction
@@ -84,6 +93,7 @@ public bool UpdateCompetencyAssessmentFeaturesTaskStatus(int id, bool descriptio
8493
int AddCollaboratorToCompetencyAssessment(int competencyAssessmentId, string? userEmail, bool canModify, int? centreID);
8594
void RemoveCollaboratorFromCompetencyAssessment(int competencyAssessmentId, int id);
8695
CompetencyAssessmentCollaboratorNotification? GetCollaboratorNotification(int id, int invitedByAdminId);
96+
bool HasCompetencyWithSignpostedLearning(int competencyAssessmentId);
8797
}
8898

8999
public class CompetencyAssessmentDataService : ICompetencyAssessmentDataService
@@ -92,9 +102,11 @@ public class CompetencyAssessmentDataService : ICompetencyAssessmentDataService
92102
sa.ParentSelfAssessmentID,
93103
sa.[National], sa.[Public], sa.CreatedByAdminID AS OwnerAdminID,
94104
sa.NRPProfessionalGroupID,
95-
sa.NRPSubGroupID,
96-
sa.NRPRoleID,
97-
sa.PublishStatusID, sa.Vocabulary, CASE WHEN sa.CreatedByAdminID = @adminId THEN 3 WHEN sac.CanModify = 1 THEN 2 WHEN sac.CanModify = 0 THEN 1 ELSE 0 END AS UserRole";
105+
sa.NRPSubGroupID,
106+
sa.NRPRoleID,
107+
sa.PublishStatusID, sa.Vocabulary, CASE WHEN sa.CreatedByAdminID = @adminId THEN 3 WHEN sac.CanModify = 1 THEN 2 WHEN sac.CanModify = 0 THEN 1 ELSE 0 END AS UserRole,
108+
sa.IncludeLearnerDeclarationPrompt, sa.IncludesSignposting, sa.LinearNavigation, sa.UseDescriptionExpanders, sa.QuestionLabel, sa.ReviewerCommentsLabel,
109+
sa.SupervisorSelfAssessmentReview, sa.SupervisorResultsReview ";
98110

99111
private const string SelfAssessmentFields =
100112
@", sa.CategoryID, sa.CreatedDate,
@@ -1057,5 +1069,84 @@ FROM SelfAssessmentCollaborators AS sc
10571069
new { invitedByAdminId, id }
10581070
).FirstOrDefault();
10591071
}
1072+
1073+
public bool HasCompetencyWithSignpostedLearning(int competencyAssessmentId)
1074+
{
1075+
int hasSignpostedLearning = connection.QueryFirstOrDefault<int>(
1076+
@"SELECT count(*) FROM SelfAssessmentStructure sas INNER JOIN
1077+
CompetencyLearningResources clr ON sas.CompetencyID = clr.CompetencyID AND
1078+
clr.RemovedDate IS NULL
1079+
WHERE sas.SelfAssessmentID = @competencyAssessmentId",
1080+
new { competencyAssessmentId });
1081+
1082+
return hasSignpostedLearning > 0;
1083+
}
1084+
public bool UpdateCompetencyAssessmentOptions(
1085+
bool includeLearnerDeclarationPrompt,
1086+
bool includesSignposting,
1087+
bool linearNavigation,
1088+
bool useDescriptionExpanders,
1089+
string? questionLabelText,
1090+
string? reviewerCommentsLabelText,
1091+
int competencyAssessmentId, int adminId)
1092+
{
1093+
if ((adminId < 1) | (competencyAssessmentId < 1))
1094+
{
1095+
logger.LogWarning(
1096+
$"Not updating role profile name as it failed server side validation. AdminId: {adminId}, competencyAssessmentId: {competencyAssessmentId}"
1097+
);
1098+
return false;
1099+
}
1100+
1101+
var numberOfAffectedRows = connection.Execute(
1102+
@"UPDATE SelfAssessments SET IncludeLearnerDeclarationPrompt = @includeLearnerDeclarationPrompt,
1103+
IncludesSignposting = @includesSignposting,
1104+
LinearNavigation = @linearNavigation,
1105+
UseDescriptionExpanders = @useDescriptionExpanders,
1106+
QuestionLabel = @questionLabelText,
1107+
ReviewerCommentsLabel = @reviewerCommentsLabelText,
1108+
UpdatedByAdminID = @adminId
1109+
WHERE ID = @competencyAssessmentId ",
1110+
new
1111+
{
1112+
includeLearnerDeclarationPrompt,
1113+
includesSignposting,
1114+
linearNavigation,
1115+
useDescriptionExpanders,
1116+
questionLabelText,
1117+
reviewerCommentsLabelText,
1118+
adminId,
1119+
competencyAssessmentId
1120+
}
1121+
);
1122+
if (numberOfAffectedRows < 1)
1123+
{
1124+
logger.LogWarning(
1125+
"Not updating options/labels as db update failed. " +
1126+
$"admin id: {adminId}, competencyAssessmentId: {competencyAssessmentId}"
1127+
);
1128+
return false;
1129+
}
1130+
1131+
return true;
1132+
}
1133+
1134+
public bool UpdateCompetencyAssessmentOptionsTaskStatus(int assessmentId, bool taskStatus)
1135+
{
1136+
var numberOfAffectedRows = connection.Execute(
1137+
@"UPDATE SelfAssessmentTaskStatus SET SelfAssessmentOptionsTaskStatus = @taskStatus
1138+
WHERE SelfAssessmentId = @assessmentId",
1139+
new { assessmentId, taskStatus }
1140+
);
1141+
if (numberOfAffectedRows < 1)
1142+
{
1143+
logger.LogWarning(
1144+
"Not updating SelfAssessmentOptionsTaskStatus as db update failed. " +
1145+
$"assessmentId: {assessmentId}, taskStatus: {taskStatus}"
1146+
);
1147+
return false;
1148+
}
1149+
return true;
1150+
}
10601151
}
10611152
}

DigitalLearningSolutions.Data/Models/CompetencyAssessments/CompetencyAssessmentBase.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,14 @@ public class CompetencyAssessmentBase
2020
public int PublishStatusID { get; set; }
2121
public int UserRole { get; set; }
2222
public string? Vocabulary { get; set; }
23-
23+
public bool IncludeLearnerDeclarationPrompt { get; set; }
24+
public bool IncludesSignposting { get; set; }
25+
public bool LinearNavigation { get; set; }
26+
public bool UseDescriptionExpanders { get; set; }
27+
public string? QuestionLabel { get; set; }
28+
public string? ReviewerCommentsLabel { get; set; }
29+
public bool SupervisorSelfAssessmentReview { get; set; }
30+
public bool SupervisorResultsReview { get; set; }
2431
}
2532
}
2633

DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -809,6 +809,168 @@ public IActionResult AssessmentWorkingGroup(WorkingGroupCollaboratorsViewModel m
809809
}
810810
}
811811

812+
[Route("/CompetencyAssessments/{competencyAssessmentId}/ConfigureOptions")]
813+
public IActionResult ConfigureOptions(int competencyAssessmentId)
814+
{
815+
var data = new OptionsLabelsViewModel();
816+
var adminId = GetAdminID();
817+
var result = ValidateCompetencyAssessmentAndRole(competencyAssessmentId, adminId, "competency assessment options");
818+
if (result.StatusCode != 200)
819+
return result;
820+
var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId);
821+
822+
data.CompetencyAssessmentID = competencyAssessmentId;
823+
data.Vocabulary = competencyAssessmentBase.Vocabulary;
824+
data.IncludeLearnerDeclarationPrompt = competencyAssessmentBase.IncludeLearnerDeclarationPrompt;
825+
data.IncludesSignposting = competencyAssessmentBase.IncludesSignposting;
826+
data.LinearNavigation = competencyAssessmentBase.LinearNavigation;
827+
data.UseDescriptionExpanders = competencyAssessmentBase.UseDescriptionExpanders;
828+
data.QuestionLabel = string.IsNullOrWhiteSpace(competencyAssessmentBase.QuestionLabel) ? false : true;
829+
data.QuestionLabelText = competencyAssessmentBase.QuestionLabel?.Trim();
830+
data.ReviewerCommentsLabel = string.IsNullOrWhiteSpace(competencyAssessmentBase.ReviewerCommentsLabel) ? false : true;
831+
data.ReviewerCommentsLabelText = competencyAssessmentBase.ReviewerCommentsLabel?.Trim();
832+
data.IsSupervisionSwitchedOn = competencyAssessmentBase.SupervisorSelfAssessmentReview && competencyAssessmentBase.SupervisorResultsReview;
833+
data.IsSignpostedLearning = competencyAssessmentService.HasCompetencyWithSignpostedLearning(competencyAssessmentId);
834+
835+
data.IsSupervisionSwitchedOn = true; // Remove
836+
data.IsSignpostedLearning = true; //remove
837+
838+
var taskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null);
839+
data.SelfAssessmentOptionsTaskStatus = taskStatus.SelfAssessmentOptionsTaskStatus;
840+
841+
SetOptionsLabelsData(data);
842+
843+
var step = (int)OptionLabel.Declaration;
844+
if (taskStatus.SelfAssessmentOptionsTaskStatus != null)
845+
step = (int)OptionLabel.Summary;
846+
847+
ValidateStep(data, ref step);
848+
return RedirectToAction("OptionsLabels", "CompetencyAssessments", new { competencyAssessmentId, step });
849+
}
850+
851+
[Route("/CompetencyAssessments/{competencyAssessmentId}/OptionsLabels/{step}")]
852+
public IActionResult OptionsLabels(int competencyAssessmentId, int step)
853+
{
854+
if (step < (int)OptionLabel.Declaration || step > (int)OptionLabel.Summary)
855+
return StatusCode(500);
856+
857+
var adminId = GetAdminID();
858+
var result = ValidateCompetencyAssessmentAndRole(competencyAssessmentId, adminId, "competency assessment options");
859+
if (result.StatusCode != 200)
860+
return result;
861+
862+
var data = GetOptionsLabelslData();
863+
864+
if (ValidateStep(data, ref step))
865+
{
866+
return RedirectToAction("OptionsLabels", "CompetencyAssessments", new { competencyAssessmentId, step });
867+
}
868+
869+
data.CurrentStep = step;
870+
var model = new OptionsLabelsViewModel(data);
871+
872+
return View("CompetencyAssessmentOptions", model);
873+
}
874+
875+
[HttpPost]
876+
[Route("/CompetencyAssessments/{competencyAssessmentId}/OptionsLabels/{step}")]
877+
public IActionResult OptionsLabels(OptionsLabelsViewModel model)
878+
{
879+
var adminId = GetAdminID();
880+
var data = GetOptionsLabelslData();
881+
data.CurrentStep = model.CurrentStep;
882+
ModelState.Remove("VocabularySingular");
883+
ModelState.Remove("VocabularyPlural");
884+
885+
if (model.CurrentStep == (int)OptionLabel.Declaration)
886+
{
887+
data.IncludeLearnerDeclarationPrompt = model.IncludeLearnerDeclarationPrompt;
888+
}
889+
else if (model.CurrentStep == (int)OptionLabel.Signposting)
890+
{
891+
data.IncludesSignposting = model.IncludesSignposting;
892+
}
893+
else if (model.CurrentStep == (int)OptionLabel.LinearNavigation)
894+
{
895+
data.LinearNavigation = model.LinearNavigation;
896+
}
897+
else if (model.CurrentStep == (int)OptionLabel.DescriptionExpanders)
898+
{
899+
data.UseDescriptionExpanders = model.UseDescriptionExpanders;
900+
}
901+
else if (model.CurrentStep == (int)OptionLabel.QuestionLabels)
902+
{
903+
data.QuestionLabel = model.QuestionLabel;
904+
if (model.QuestionLabel)
905+
{
906+
var label = model.QuestionLabelText?.Trim();
907+
if (string.IsNullOrEmpty(label))
908+
ModelState.AddModelError(nameof(model.QuestionLabelText), "Please enter a question label");
909+
else if (label.Length > 50)
910+
ModelState.AddModelError(nameof(model.QuestionLabelText), "Question label must be 50 characters or fewer");
911+
912+
if (!ModelState.IsValid)
913+
{
914+
SetOptionsLabelsData(data);
915+
model = new OptionsLabelsViewModel(data);
916+
model.Error = true;
917+
return View("CompetencyAssessmentOptions", model);
918+
}
919+
}
920+
data.QuestionLabelText = model.QuestionLabel ? model.QuestionLabelText.Trim() : null;
921+
}
922+
else if (model.CurrentStep == (int)OptionLabel.CommentsLabel)
923+
{
924+
data.ReviewerCommentsLabel = model.ReviewerCommentsLabel;
925+
if (model.ReviewerCommentsLabel)
926+
{
927+
var label = model.ReviewerCommentsLabelText?.Trim();
928+
if (string.IsNullOrEmpty(label))
929+
ModelState.AddModelError(nameof(model.ReviewerCommentsLabelText), "Please enter a reviewer comment");
930+
else if (label.Length > 50)
931+
ModelState.AddModelError(nameof(model.ReviewerCommentsLabelText), "Reviewer comment must be 50 characters or fewer");
932+
933+
if (!ModelState.IsValid)
934+
{
935+
SetOptionsLabelsData(data);
936+
model = new OptionsLabelsViewModel(data);
937+
model.Error = true;
938+
return View("CompetencyAssessmentOptions", model);
939+
}
940+
}
941+
data.ReviewerCommentsLabelText = model.ReviewerCommentsLabel ? model.ReviewerCommentsLabelText.Trim() : null;
942+
}
943+
else if (model.CurrentStep == (int)OptionLabel.Summary)
944+
{
945+
var isUpdate = competencyAssessmentService.UpdateCompetencyAssessmentOptions(
946+
data.IncludeLearnerDeclarationPrompt,
947+
data.IncludesSignposting,
948+
data.LinearNavigation,
949+
data.UseDescriptionExpanders,
950+
data.QuestionLabel ? data.QuestionLabelText?.Trim() : null,
951+
data.ReviewerCommentsLabel ? data.ReviewerCommentsLabelText?.Trim() : null,
952+
data.CompetencyAssessmentID,
953+
adminId);
954+
if (!isUpdate)
955+
{
956+
ModelState.AddModelError("", "Update failed. Please try again.");
957+
return View("CompetencyAssessmentOptions", model);
958+
}
959+
competencyAssessmentService.UpdateCompetencyAssessmentOptionsTaskStatus(model.CompetencyAssessmentID, model.SelfAssessmentOptionsTaskStatus ?? false);
960+
return RedirectToAction("ManageCompetencyAssessment", "CompetencyAssessments", new { model.CompetencyAssessmentID });
961+
}
962+
963+
if (data.SelfAssessmentOptionsTaskStatus != null)
964+
data.CurrentStep = (int)OptionLabel.Summary;
965+
else
966+
data.CurrentStep = model.CurrentStep + 1;
967+
968+
SetOptionsLabelsData(data);
969+
970+
var newModel = new OptionsLabelsViewModel(data);
971+
return RedirectToAction("OptionsLabels", "CompetencyAssessments", new { model.CompetencyAssessmentID, step = newModel.CurrentStep });
972+
}
973+
812974
public IActionResult RemoveCollaborator(int competencyAssessmentId, int id, string actionName)
813975
{
814976
competencyAssessmentService.RemoveCollaboratorFromCompetencyAssessment(competencyAssessmentId, id);
@@ -832,5 +994,54 @@ private CompetencyAssessmentFeaturesViewModel GetcompetencyAssessmentFeaturesDat
832994
).GetAwaiter().GetResult();
833995
return data;
834996
}
997+
998+
private void SetOptionsLabelsData(OptionsLabelsViewModel data)
999+
{
1000+
multiPageFormService.SetMultiPageFormData(
1001+
data,
1002+
MultiPageFormDataFeature.AddCustomWebForm("OptionsLabelsCWF"),
1003+
TempData
1004+
);
1005+
}
1006+
1007+
private OptionsLabelsViewModel GetOptionsLabelslData()
1008+
{
1009+
var data = multiPageFormService.GetMultiPageFormData<OptionsLabelsViewModel>(
1010+
MultiPageFormDataFeature.AddCustomWebForm("OptionsLabelsCWF"),
1011+
TempData
1012+
).GetAwaiter().GetResult();
1013+
return data;
1014+
}
1015+
private bool ValidateStep(OptionsLabelsViewModel data, ref int step)
1016+
{
1017+
int original = step;
1018+
if (step == (int)OptionLabel.Declaration && !data.IsSupervisionSwitchedOn) step = (int)OptionLabel.Signposting;
1019+
if (step == (int)OptionLabel.Signposting && !data.IsSignpostedLearning) step = (int)OptionLabel.LinearNavigation;
1020+
if (step == (int)OptionLabel.CommentsLabel && !data.IsSupervisionSwitchedOn) step = (int)OptionLabel.Summary;
1021+
1022+
return step != original;
1023+
}
1024+
1025+
private StatusCodeResult ValidateCompetencyAssessmentAndRole(int competencyAssessmentId, int adminId, string pageName)
1026+
{
1027+
if (competencyAssessmentId > 0)
1028+
{
1029+
var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId);
1030+
if (competencyAssessmentBase == null)
1031+
{
1032+
logger.LogWarning($"Failed to load {pageName} page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}");
1033+
return StatusCode(500);
1034+
}
1035+
if (competencyAssessmentBase.UserRole < 2)
1036+
{
1037+
return StatusCode(403);
1038+
}
1039+
}
1040+
else
1041+
{
1042+
return StatusCode(500);
1043+
}
1044+
return StatusCode(200);
1045+
}
8351046
}
8361047
}

0 commit comments

Comments
 (0)