diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index b6ff269935..cc10791b12 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -1426,11 +1426,34 @@ public int InsertAssessmentQuestionRoleRequirementForSelfAssessment(int assessme { var numberOfAffectedRows = connection.Execute( @"INSERT INTO CompetencyAssessmentQuestionRoleRequirements - (SelfAssessmentID, CompetencyID, AssessmentQuestionID, LevelValue, LevelRAG) - SELECT sas.SelfAssessmentID, sas.CompetencyID, caq.AssessmentQuestionID, @levelValue AS LevelValue, @levelRAG AS LevelRAG - FROM SelfAssessmentStructure AS sas INNER JOIN - CompetencyAssessmentQuestions AS caq ON sas.CompetencyID = caq.CompetencyID - WHERE (sas.SelfAssessmentID = @assessmentId) AND (caq.AssessmentQuestionID = @assessmentQuestionId);" + ( + SelfAssessmentID, + CompetencyID, + AssessmentQuestionID, + LevelValue, + LevelRAG + ) + SELECT DISTINCT + sas.SelfAssessmentID, + sas.CompetencyID, + caq.AssessmentQuestionID, + @levelValue, + @levelRAG + FROM SelfAssessmentStructure AS sas + INNER JOIN CompetencyAssessmentQuestions AS caq + ON sas.CompetencyID = caq.CompetencyID + WHERE + sas.SelfAssessmentID = @assessmentId + AND caq.AssessmentQuestionID = @assessmentQuestionId + AND NOT EXISTS + ( + SELECT 1 + FROM CompetencyAssessmentQuestionRoleRequirements existing + WHERE existing.SelfAssessmentID = sas.SelfAssessmentID + AND existing.CompetencyID = sas.CompetencyID + AND existing.AssessmentQuestionID = caq.AssessmentQuestionID + AND existing.LevelValue = @levelValue + );" , new { assessmentId, assessmentQuestionId, levelValue, levelRAG } ); diff --git a/DigitalLearningSolutions.Data/Extensions/ConfigurationExtensions.cs b/DigitalLearningSolutions.Data/Extensions/ConfigurationExtensions.cs index 61dc157340..3ff77ba9bb 100644 --- a/DigitalLearningSolutions.Data/Extensions/ConfigurationExtensions.cs +++ b/DigitalLearningSolutions.Data/Extensions/ConfigurationExtensions.cs @@ -11,7 +11,8 @@ public static class ConfigurationExtensions private const string LearningHubOpenApiKey = "LearningHubOpenAPIKey"; private const string LearningHubOpenApiBaseUrl = "LearningHubOpenAPIBaseUrl"; private const string PricingPageEnabled = "FeatureManagement:PricingPage"; - + private const string ShowDlsLoginButton = "FeatureManagement:ShowDlsLoginButton"; + private const string LearningHubAuthBaseUrl = "BaseUrl"; private const string LearningHubAuthLoginEndpoint = "LoginEndpoint"; private const string LearningHubAuthLinkingEndpoint = "LinkingEndpoint"; @@ -118,7 +119,11 @@ public static bool IsPricingPageEnabled(this IConfiguration config) bool.TryParse(config[PricingPageEnabled], out bool isEnabled); return isEnabled; } - + public static bool IsDlsLoginButtonShown(this IConfiguration config) + { + bool.TryParse(config[ShowDlsLoginButton], out bool isEnabled); + return isEnabled; + } public static int GetLearningHubSsoHashTolerance(this IConfiguration config) { int.TryParse(config[$"{LearningHubSsoSectionKey}:{LearningHubSsoToleranceKey}"], out int ssoHashTolerance); diff --git a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs index b353490b19..326d71895b 100644 --- a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs +++ b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs @@ -438,6 +438,11 @@ public IActionResult SelectFrameworkSources(SelectFrameworkSourcesFormData model competencyAssessmentService.InsertSelfAssessmentFramework(adminId, competencyAssessmentId, model.FrameworkId.Value); return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId, actionName = "Summary" }); } + else if (actionName == "ViewSelected") + { + competencyAssessmentService.InsertSelfAssessmentFramework(adminId, competencyAssessmentId, model.FrameworkId.Value); + return RedirectToAction("ViewSelectedCompetencies", new { competencyAssessmentId }); + } else { competencyAssessmentService.UpdateFrameworkLinksTaskStatus(model.CompetencyAssessmentId, model.TaskStatus ?? false, null); @@ -484,7 +489,7 @@ public IActionResult ViewSelectedCompetencies(int competencyAssessmentId) var linkedFrameworks = competencyAssessmentService.GetLinkedFrameworksForCompetencyAssessment(competencyAssessmentId); if (!linkedFrameworks.Any()) { - return RedirectToAction("AddCompetenciesSelectFramework", new { competencyAssessmentId }); + return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId, actionName = "ViewSelected" }); } var adminId = GetAdminID(); var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); @@ -496,7 +501,8 @@ public IActionResult ViewSelectedCompetencies(int competencyAssessmentId) return View(model); } [Route("/Self-Assessment/{competencyAssessmentId}/Competencies/Add/SelectFramework")] - public IActionResult AddCompetenciesSelectFramework(int competencyAssessmentId) + [Route("/Self-Assessment/{competencyAssessmentId}/{actionName}/Competencies/Add/SelectFramework")] + public IActionResult AddCompetenciesSelectFramework(int competencyAssessmentId, string? actionName) { var linkedFrameworks = competencyAssessmentService.GetLinkedFrameworksForCompetencyAssessment(competencyAssessmentId); if (!linkedFrameworks.Any()) @@ -513,6 +519,7 @@ public IActionResult AddCompetenciesSelectFramework(int competencyAssessmentId) } [HttpPost] [Route("/Self-Assessment/{competencyAssessmentId}/Competencies/Add/SelectFramework")] + [Route("/Self-Assessment/{competencyAssessmentId}/{actionName}/Competencies/Add/SelectFramework")] public IActionResult AddCompetenciesSelectFramework(AddCompetenciesSelectFrameworkFormData formdata) { if (!ModelState.IsValid) @@ -579,6 +586,9 @@ public IActionResult AddComptencies(AddCompetenciesFormData model, int competenc competency.CompetencyFlags = competencyFlags.Where(f => f.CompetencyId == competency.CompetencyID); } var models = new AddCompetenciesViewModel(competencyAssessmentBase, groupedCompetencies, ungroupedCompetencies, frameworkId, framework.FrameworkName, model.SelectedCompetencyIds); + ModelState.Clear(); + ModelState.AddModelError("SelectedCompetencyIds", $"You must select at least one {models.VocabularySingular}"); + ViewBag.RequiredCheckboxMessage = "You must select at least one "+ models.VocabularySingular; return View("AddCompetencies", models); } if (model.SelectedCompetencyIds != null) diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewFormData.cs index 07516407bf..0e6d2ed887 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewFormData.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewFormData.cs @@ -1,11 +1,8 @@ -using System.ComponentModel.DataAnnotations; - -namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments { public class AddCompetenciesFormData { public int ID { get; set; } - [Required(ErrorMessage = "Select at least one competency")] public int[] SelectedCompetencyIds { get; set; } public int FrameworkId { get; set; } } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewModel.cs index 24433fe494..c1699ef52a 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/AddCompetenciesViewModel.cs @@ -28,7 +28,7 @@ public AddCompetenciesViewModel(CompetencyAssessmentBase competencyAssessmentBas public string VocabularyPlural { get; set; } public IEnumerable GroupedCompetencies { get; set; } public IEnumerable UngroupedCompetencies { get; set; } - [Required(ErrorMessage = "Select at least one competency")] + [Required] public int[] SelectedCompetencyIds { get; set; } public int FrameworkId { get; set; } public string? FrameworkName { get; set; } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs index 8d1adea226..45ab4395e2 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs @@ -23,7 +23,7 @@ public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssess Frameworks = [.. frameworks .Where(f => !excludedIds.Contains(f.ID)) .OrderBy(f => f.FrameworkName)]; - AdditionalFrameworks = [.. additionalFrameworksIds.Select(id => frameworks.First(f => f.ID == id))]; + AdditionalFrameworks = [.. additionalFrameworksIds.Select(id => frameworks.FirstOrDefault(f => f.ID == id))]; ActionName = actionName; } public IEnumerable Frameworks { get; set; } diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetencies.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetencies.cshtml index 30a10c2ef8..89cea71d72 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetencies.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/AddCompetencies.cshtml @@ -4,6 +4,8 @@ ViewData["Title"] = $"Add {@Model.VocabularyPlural.ToLower()} to self-assessment"; ViewData["Application"] = "Framework service"; var errorHasOccurred = !ViewData.ModelState.IsValid; + var noSelection = Model.SelectedCompetencyIds == null || !Model.SelectedCompetencyIds.Any(); + var isFirst = true; } @section NavMenuItems { @@ -40,6 +42,11 @@ Add @Model.VocabularyPlural.ToLower() to assessment +
+ + @ViewBag.RequiredCheckboxMessage + +
@if (Model.GroupedCompetencies.Count() > 0) { @foreach (var competencyGroup in Model.GroupedCompetencies) @@ -62,8 +69,18 @@
@foreach (var competency in competencyGroup.FrameworkCompetencies) { + var shouldAutofocus = noSelection && isFirst; + isFirst = false;
- +
} - @if (Model.AdditionalFrameworks.Count() > 0) + @if (Model?.AdditionalFrameworks != null && Model.AdditionalFrameworks.Any()) { - for (int i = 0; i < Model.AdditionalFrameworks.Count(); i++) + int i = 0; + foreach (var framework in Model.AdditionalFrameworks) { + if (framework == null) continue; +
Additional framework @(i + 1)
- @Model.AdditionalFrameworks.ElementAt(i).FrameworkName + @framework.FrameworkName
@if (Model.UserRole > 1) { @@ -90,28 +93,28 @@ }
+ i++; } } } -@if (Model.ActionName == "AddFramework") +@if (Model.ActionName == "AddFramework" || Model.ActionName == "ViewSelected") {