From 40875a26c9d0f4e7a74e1d2dfbe204a11da1167d Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Thu, 6 Mar 2025 15:40:18 +0000 Subject: [PATCH 01/10] TD-5307 Begins to implement controller, viewmodel and view (WIP) --- .../CompetencyAssessmentDataService.cs | 12 +++++++ .../CompetencyAssessments.cs | 20 +++++++++++ .../Services/CompetencyAssessmentService.cs | 6 ++++ .../SelectFrameworkSourcesViewModel.cs | 33 +++++++++++++++++++ .../SelectFrameworkSources.cshtml | 26 +++++++++++++++ 5 files changed, 97 insertions(+) create mode 100644 DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs create mode 100644 DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index 983bdba073..782f87375c 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -28,6 +28,8 @@ public interface ICompetencyAssessmentDataService CompetencyAssessmentTaskStatus GetOrInsertAndReturnAssessmentTaskStatus(int assessmentId, bool frameworkBased); + int[] GetLinkedFrameworkIds (int assessmentId); + //UPDATE DATA bool UpdateCompetencyAssessmentName(int competencyAssessmentId, int adminId, string competencyAssessmentName); @@ -459,5 +461,15 @@ public bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus) } return true; } + + public int[] GetLinkedFrameworkIds(int assessmentId) + { + return [.. connection.Query( + @"SELECT FrameworkId + FROM SelfAssessmentFrameworks + WHERE (SelfAssessmentId = @assessmentId) AND (RemovedDate IS NULL)", + new { assessmentId } + )]; + } } } diff --git a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs index aee8442d14..a89089d8d5 100644 --- a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs +++ b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs @@ -389,5 +389,25 @@ public IActionResult SaveVocabulary(EditVocabularyViewModel model) competencyAssessmentService.UpdateVocabularyTaskStatus(model.ID, model.TaskStatus ?? false); return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId = model.ID }); } + [Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/")] + public IActionResult SelectFrameworkSources(int competencyAssessmentId) + { + var adminId = GetAdminID(); + var frameworks = frameworkService.GetAllFrameworks(adminId); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + if (competencyAssessmentBase == null) + { + logger.LogWarning($"Failed to load Vocabulary page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); + } + if (competencyAssessmentBase.UserRole < 2) + { + return StatusCode(403); + } + var selectedFrameworks = competencyAssessmentService.GetLinkedFrameworkIds(competencyAssessmentId); + var competencyAssessmentTaskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null); + var model = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, selectedFrameworks, competencyAssessmentTaskStatus.FrameworkLinksTaskStatus); + return View(model); + } } } diff --git a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs index 7e8cf37fdb..2574da1547 100644 --- a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs @@ -37,6 +37,7 @@ public interface ICompetencyAssessmentService //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName, int? frameworkId); + int[] GetLinkedFrameworkIds(int assessmentId); } public class CompetencyAssessmentService : ICompetencyAssessmentService { @@ -149,5 +150,10 @@ public bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus) { return competencyAssessmentDataService.UpdateRoleProfileLinksTaskStatus(assessmentId, taskStatus); } + + public int[] GetLinkedFrameworkIds(int assessmentId) + { + return competencyAssessmentDataService.GetLinkedFrameworkIds(assessmentId); + } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs new file mode 100644 index 0000000000..fcfe0d0bd9 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs @@ -0,0 +1,33 @@ +using AngleSharp.Css; +using DigitalLearningSolutions.Data.Models.CompetencyAssessments; +using DigitalLearningSolutions.Data.Models.Frameworks; +using DocumentFormat.OpenXml.Office2010.Excel; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + public class SelectFrameworkSourcesViewModel + { + public SelectFrameworkSourcesViewModel() { } + public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable frameworks, int[] selectedFrameworks, bool? taskStatus) + { + ID = competencyAssessmentBase.ID; + CompetencyAssessmentName = competencyAssessmentBase.CompetencyAssessmentName; + UserRole = competencyAssessmentBase.UserRole; + TaskStatus = taskStatus; + Frameworks = frameworks; + SelectedFrameworks = selectedFrameworks; + } + public IEnumerable Frameworks { get; set; } + public int[] SelectedFrameworks { get; set; } + public IEnumerable Roles { get; set; } + public int ID { get; set; } + public string CompetencyAssessmentName { get; set; } + public int UserRole { get; set; } + public bool? TaskStatus { get; set; } + public string? GroupName { get; set; } + public string? SubGroupName { get; set; } + public string? RoleName { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml new file mode 100644 index 0000000000..11bc5bb465 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml @@ -0,0 +1,26 @@ +@using DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +@model SelectFrameworkSourcesViewModel; +@{ + ViewData["Title"] = "Select Framework Sources"; + ViewData["Application"] = "Framework Service"; +} + + +@section NavMenuItems { + +} + +@section NavBreadcrumbs { + +} + +

Select framework sources for @Model.CompetencyAssessmentName

From 6eb251c17924ce6fb58285152dc3099a5205913e Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Fri, 21 Mar 2025 16:50:58 +0000 Subject: [PATCH 02/10] TD-5307 Sets up post action and services for assessment frameworks --- .../CompetencyAssessmentDataService.cs | 10 ++++ .../CompetencyAssessments.cs | 28 +++++++++ .../Services/CompetencyAssessmentService.cs | 6 ++ .../SelectFrameworkSourcesFormData.cs | 10 ++++ .../SelectFrameworkSourcesViewModel.cs | 16 +++-- .../SelectFrameworkSources.cshtml | 60 ++++++++++++++++++- 6 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index 782f87375c..f6c20a0597 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -334,6 +334,16 @@ WHERE NOT EXISTS (SELECT 1 FROM SelfAssessmentFrameworks WHERE SelfAssessmentId new { adminId, selfAssessmentId, frameworkId } ); if (numberOfAffectedRows < 1) + { + numberOfAffectedRows = connection.Execute( + @"UPDATE SelfAssessmentFrameworks + SET @selfAssessmentId, @frameworkId, @adminId + WHERE SelfAssessmentId = @selfAssessmentId AND FrameworkId = @frameworkId" + , + new { adminId, selfAssessmentId, frameworkId } + ); + } + if (numberOfAffectedRows < 1) { logger.LogWarning( "Not inserting SelfAssessmentFrameworks record as db insert failed. " + diff --git a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs index a89089d8d5..50fb6f252e 100644 --- a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs +++ b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs @@ -409,5 +409,33 @@ public IActionResult SelectFrameworkSources(int competencyAssessmentId) var model = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, selectedFrameworks, competencyAssessmentTaskStatus.FrameworkLinksTaskStatus); return View(model); } + [HttpPost] + [Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/")] + public IActionResult SelectFrameworkSources(SelectFrameworkSourcesFormData model) + { + var adminId = GetAdminID(); + var competencyAssessmentId = model.CompetencyAssessmentId; + if (!ModelState.IsValid) + { + + var frameworks = frameworkService.GetAllFrameworks(adminId); + var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId); + if (competencyAssessmentBase == null) + { + logger.LogWarning($"Failed to load Vocabulary page for competencyAssessmentId: {competencyAssessmentId} adminId: {adminId}"); + return StatusCode(500); + } + if (competencyAssessmentBase.UserRole < 2) + { + return StatusCode(403); + } + var selectedFrameworks = competencyAssessmentService.GetLinkedFrameworkIds(competencyAssessmentId); + var competencyAssessmentTaskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null); + var viewModel = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, selectedFrameworks, competencyAssessmentTaskStatus.FrameworkLinksTaskStatus); + return View("SelectFrameworkSources", viewModel); + } + competencyAssessmentService.InsertSelfAssessmentFramework(adminId, competencyAssessmentId, model.FrameworkId); + return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId }); + } } } diff --git a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs index 2574da1547..2f2ef98c07 100644 --- a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs @@ -37,6 +37,7 @@ public interface ICompetencyAssessmentService //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName, int? frameworkId); + bool InsertSelfAssessmentFramework(int adminId, int assessmentId, int frameworkId); int[] GetLinkedFrameworkIds(int assessmentId); } public class CompetencyAssessmentService : ICompetencyAssessmentService @@ -155,5 +156,10 @@ public int[] GetLinkedFrameworkIds(int assessmentId) { return competencyAssessmentDataService.GetLinkedFrameworkIds(assessmentId); } + + public bool InsertSelfAssessmentFramework(int adminId, int assessmentId, int frameworkId) + { + return competencyAssessmentDataService.InsertSelfAssessmentFramework(adminId, assessmentId, frameworkId); + } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs new file mode 100644 index 0000000000..b7a56295f8 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs @@ -0,0 +1,10 @@ +namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments +{ + using System.ComponentModel.DataAnnotations; + public class SelectFrameworkSourcesFormData + { + [Required] + public int[] SelectedFrameworkIds { get; set; } + public int CompetencyAssessmentId { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs index fcfe0d0bd9..c9a0f49ed2 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs @@ -1,26 +1,24 @@ -using AngleSharp.Css; -using DigitalLearningSolutions.Data.Models.CompetencyAssessments; +using DigitalLearningSolutions.Data.Models.CompetencyAssessments; using DigitalLearningSolutions.Data.Models.Frameworks; -using DocumentFormat.OpenXml.Office2010.Excel; using System.Collections.Generic; -using System.Threading.Tasks; +using System.Linq; namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments { - public class SelectFrameworkSourcesViewModel + public class SelectFrameworkSourcesViewModel : SelectFrameworkSourcesFormData { public SelectFrameworkSourcesViewModel() { } - public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable frameworks, int[] selectedFrameworks, bool? taskStatus) + public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable frameworks, int[] selectedFrameworksIds, bool? taskStatus) { ID = competencyAssessmentBase.ID; CompetencyAssessmentName = competencyAssessmentBase.CompetencyAssessmentName; UserRole = competencyAssessmentBase.UserRole; TaskStatus = taskStatus; - Frameworks = frameworks; - SelectedFrameworks = selectedFrameworks; + Frameworks = frameworks.OrderBy(f => f.FrameworkName); + SelectedFrameworks = [.. frameworks.Where(f => selectedFrameworksIds.Contains(f.ID))]; } public IEnumerable Frameworks { get; set; } - public int[] SelectedFrameworks { get; set; } + public IEnumerable SelectedFrameworks { get; set; } public IEnumerable Roles { get; set; } public int ID { get; set; } public string CompetencyAssessmentName { get; set; } diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml index 11bc5bb465..77f0c731ec 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml @@ -7,7 +7,7 @@ @section NavMenuItems { - + } @section NavBreadcrumbs { @@ -24,3 +24,61 @@ }

Select framework sources for @Model.CompetencyAssessmentName

+@if (Model.SelectedFrameworks.Count() > 0) +{ +
+
+
+ Primary framework +
+
+ @Model.SelectedFrameworks.First().FrameworkName +
+
+ + Remove @Model.SelectedFrameworks.First().FrameworkName + +
+
+ @if (Model.SelectedFrameworks.Count() > 1) + { + for (int i = 1; i < Model.SelectedFrameworks.Count(); i++) + { +
+
+ Additional framework @i +
+
+ @Model.SelectedFrameworks.ElementAt(i).FrameworkName +
+
+ + Remove @Model.SelectedFrameworks.ElementAt(i).FrameworkName + +
+
+ } + } +
+} +
+
+
+ +

Add a framework source

+
+
+ @foreach(var framework in Model.Frameworks) + { +
+ + +
+ } +
+
+
+ +
From 8888836c092622b73a607624de4780d292fe3d4c Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Tue, 15 Apr 2025 16:10:42 +0100 Subject: [PATCH 03/10] Updates post to take framework ID param --- .../CompetencyAssessments/SelectFrameworkSourcesFormData.cs | 2 +- .../Views/CompetencyAssessments/SelectFrameworkSources.cshtml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs index b7a56295f8..f113a1b9ab 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs @@ -4,7 +4,7 @@ public class SelectFrameworkSourcesFormData { [Required] - public int[] SelectedFrameworkIds { get; set; } + public int FrameworkId { get; set; } public int CompetencyAssessmentId { get; set; } } } diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml index 77f0c731ec..1aeb7dd7fc 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml @@ -71,7 +71,7 @@ @foreach(var framework in Model.Frameworks) {
- + From 3e92629cf383d2bf5fa41acd151a2d52bb4f32bd Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Mon, 28 Apr 2025 17:09:34 +0100 Subject: [PATCH 04/10] TD-5307 Implements adding of linked frameworks and updating of task status --- ...sPrimaryToSelfAssessmentFrameworksTable.cs | 12 +++ .../CompetencyAssessmentDataService.cs | 32 +++++++- .../CompetencyAssessments.cs | 25 ++++--- .../Services/CompetencyAssessmentService.cs | 9 ++- .../SelectFrameworkSourcesFormData.cs | 2 + .../SelectFrameworkSourcesViewModel.cs | 6 +- .../EditRoleProfileLinks.cshtml | 3 + .../ManageCompetencyAssessment.cshtml | 2 +- .../SelectFrameworkSources.cshtml | 74 +++++++++++++------ 9 files changed, 125 insertions(+), 40 deletions(-) create mode 100644 DigitalLearningSolutions.Data.Migrations/202504241517_AddFieldIsPrimaryToSelfAssessmentFrameworksTable.cs diff --git a/DigitalLearningSolutions.Data.Migrations/202504241517_AddFieldIsPrimaryToSelfAssessmentFrameworksTable.cs b/DigitalLearningSolutions.Data.Migrations/202504241517_AddFieldIsPrimaryToSelfAssessmentFrameworksTable.cs new file mode 100644 index 0000000000..fe1e096135 --- /dev/null +++ b/DigitalLearningSolutions.Data.Migrations/202504241517_AddFieldIsPrimaryToSelfAssessmentFrameworksTable.cs @@ -0,0 +1,12 @@ +namespace DigitalLearningSolutions.Data.Migrations +{ + using FluentMigrator; + [Migration(202504241517)] + public class AddFieldIsPrimaryToSelfAssessmentFrameworksTable : AutoReversingMigration + { + public override void Up() + { + Alter.Table("SelfAssessmentFrameworks").AddColumn("IsPrimary").AsBoolean().NotNullable().WithDefaultValue(1); + } + } +} diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index f6c20a0597..a8b24f4100 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -46,6 +46,7 @@ int categoryId bool UpdateBrandingTaskStatus(int assessmentId, bool taskStatus); bool UpdateVocabularyTaskStatus(int assessmentId, bool taskStatus); bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus); + bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus); //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName); bool InsertSelfAssessmentFramework(int adminId, int selfAssessmentId, int frameworkId); @@ -326,12 +327,16 @@ public bool UpdateCompetencyAssessmentVocabulary(int competencyAssessmentId, int public bool InsertSelfAssessmentFramework(int adminId, int selfAssessmentId, int frameworkId) { + bool isPrimary = Convert.ToInt32(connection.ExecuteScalar( + @"SELECT Count(1) FROM SelfAssessmentFrameworks + WHERE SelfAssessmentId = @selfAssessmentId AND IsPrimary = 1", new { selfAssessmentId })) == 0; + var numberOfAffectedRows = connection.Execute( - @"INSERT INTO SelfAssessmentFrameworks (SelfAssessmentId, FrameworkId, CreatedByAdminId) - SELECT @selfAssessmentId, @frameworkId, @adminId + @"INSERT INTO SelfAssessmentFrameworks (SelfAssessmentId, FrameworkId, CreatedByAdminId, IsPrimary) + SELECT @selfAssessmentId, @frameworkId, @adminId, @isPrimary WHERE NOT EXISTS (SELECT 1 FROM SelfAssessmentFrameworks WHERE SelfAssessmentId = @selfAssessmentId AND FrameworkId = @frameworkId)" , - new { adminId, selfAssessmentId, frameworkId } + new { adminId, selfAssessmentId, frameworkId, isPrimary } ); if (numberOfAffectedRows < 1) { @@ -477,9 +482,28 @@ public int[] GetLinkedFrameworkIds(int assessmentId) return [.. connection.Query( @"SELECT FrameworkId FROM SelfAssessmentFrameworks - WHERE (SelfAssessmentId = @assessmentId) AND (RemovedDate IS NULL)", + WHERE (SelfAssessmentId = @assessmentId) AND (RemovedDate IS NULL) + ORDER BY CAST(IsPrimary AS Int) DESC, ID", new { assessmentId } )]; } + + public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus) + { + var numberOfAffectedRows = connection.Execute( + @"UPDATE SelfAssessmentTaskStatus SET FrameworkLinksTaskStatus = @taskStatus + WHERE SelfAssessmentId = @assessmentId", + new { assessmentId, taskStatus } + ); + if (numberOfAffectedRows < 1) + { + logger.LogWarning( + "Not updating FrameworkLinksTaskStatus as db update failed. " + + $"assessmentId: {assessmentId}, taskStatus: {taskStatus}" + ); + return false; + } + return true; + } } } diff --git a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs index 50fb6f252e..c7d938b17e 100644 --- a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs +++ b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs @@ -389,8 +389,8 @@ public IActionResult SaveVocabulary(EditVocabularyViewModel model) competencyAssessmentService.UpdateVocabularyTaskStatus(model.ID, model.TaskStatus ?? false); return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId = model.ID }); } - [Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/")] - public IActionResult SelectFrameworkSources(int competencyAssessmentId) + [Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/{actionName}")] + public IActionResult SelectFrameworkSources(int competencyAssessmentId, string actionName) { var adminId = GetAdminID(); var frameworks = frameworkService.GetAllFrameworks(adminId); @@ -406,12 +406,12 @@ public IActionResult SelectFrameworkSources(int competencyAssessmentId) } var selectedFrameworks = competencyAssessmentService.GetLinkedFrameworkIds(competencyAssessmentId); var competencyAssessmentTaskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null); - var model = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, selectedFrameworks, competencyAssessmentTaskStatus.FrameworkLinksTaskStatus); + var model = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, selectedFrameworks, competencyAssessmentTaskStatus.FrameworkLinksTaskStatus, actionName); return View(model); } [HttpPost] - [Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/")] - public IActionResult SelectFrameworkSources(SelectFrameworkSourcesFormData model) + [Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/{actionName}")] + public IActionResult SelectFrameworkSources(SelectFrameworkSourcesFormData model, string actionName) { var adminId = GetAdminID(); var competencyAssessmentId = model.CompetencyAssessmentId; @@ -430,12 +430,19 @@ public IActionResult SelectFrameworkSources(SelectFrameworkSourcesFormData model return StatusCode(403); } var selectedFrameworks = competencyAssessmentService.GetLinkedFrameworkIds(competencyAssessmentId); - var competencyAssessmentTaskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null); - var viewModel = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, selectedFrameworks, competencyAssessmentTaskStatus.FrameworkLinksTaskStatus); + var viewModel = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, selectedFrameworks, model.TaskStatus, model.ActionName); return View("SelectFrameworkSources", viewModel); } - competencyAssessmentService.InsertSelfAssessmentFramework(adminId, competencyAssessmentId, model.FrameworkId); - return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId }); + if(actionName == "AddFramework") + { + competencyAssessmentService.InsertSelfAssessmentFramework(adminId, competencyAssessmentId, model.FrameworkId); + return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId, actionName = "Summary" }); + } + else + { + competencyAssessmentService.UpdateFrameworkLinksTaskStatus(model.CompetencyAssessmentId, model.TaskStatus ?? false); + return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId = model.CompetencyAssessmentId }); + } } } } diff --git a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs index 2f2ef98c07..ed8de2219f 100644 --- a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs @@ -34,11 +34,13 @@ public interface ICompetencyAssessmentService bool UpdateCompetencyAssessmentVocabulary(int assessmentId, int adminId, string vocabulary); bool UpdateVocabularyTaskStatus(int assessmentId, bool taskStatus); bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus); + bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus); //INSERT DATA int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName, int? frameworkId); bool InsertSelfAssessmentFramework(int adminId, int assessmentId, int frameworkId); int[] GetLinkedFrameworkIds(int assessmentId); + } public class CompetencyAssessmentService : ICompetencyAssessmentService { @@ -83,7 +85,7 @@ public int InsertCompetencyAssessment(int adminId, int centreId, string competen { competencyAssessmentDataService.InsertSelfAssessmentFramework(adminId, assessmentId, framework.ID); competencyAssessmentDataService.UpdateCompetencyAssessmentDescription(adminId, assessmentId, framework.Description); - competencyAssessmentDataService.UpdateCompetencyAssessmentBranding(assessmentId, (int)framework.BrandID, (int)framework.CategoryID, adminId); + competencyAssessmentDataService.UpdateCompetencyAssessmentBranding(assessmentId, adminId, (int)framework.BrandID, (int)framework.CategoryID); competencyAssessmentDataService.UpdateCompetencyAssessmentVocabulary(assessmentId, adminId, framework.Vocabulary); } } @@ -161,5 +163,10 @@ public bool InsertSelfAssessmentFramework(int adminId, int assessmentId, int fra { return competencyAssessmentDataService.InsertSelfAssessmentFramework(adminId, assessmentId, frameworkId); } + + public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus) + { + return competencyAssessmentDataService.UpdateFrameworkLinksTaskStatus(assessmentId, taskStatus); + } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs index f113a1b9ab..846a0fb2dd 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesFormData.cs @@ -6,5 +6,7 @@ public class SelectFrameworkSourcesFormData [Required] public int FrameworkId { get; set; } public int CompetencyAssessmentId { get; set; } + public bool? TaskStatus { get; set; } + public string? ActionName { get; set; } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs index c9a0f49ed2..f4c9d28738 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs @@ -8,14 +8,15 @@ namespace DigitalLearningSolutions.Web.ViewModels.CompetencyAssessments public class SelectFrameworkSourcesViewModel : SelectFrameworkSourcesFormData { public SelectFrameworkSourcesViewModel() { } - public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable frameworks, int[] selectedFrameworksIds, bool? taskStatus) + public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssessmentBase, IEnumerable frameworks, int[] selectedFrameworksIds, bool? taskStatus, string actionName) { ID = competencyAssessmentBase.ID; CompetencyAssessmentName = competencyAssessmentBase.CompetencyAssessmentName; UserRole = competencyAssessmentBase.UserRole; TaskStatus = taskStatus; Frameworks = frameworks.OrderBy(f => f.FrameworkName); - SelectedFrameworks = [.. frameworks.Where(f => selectedFrameworksIds.Contains(f.ID))]; + SelectedFrameworks = [.. selectedFrameworksIds.Select(id => frameworks.First(f => f.ID == id))]; + ActionName = actionName; } public IEnumerable Frameworks { get; set; } public IEnumerable SelectedFrameworks { get; set; } @@ -23,7 +24,6 @@ public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssess public int ID { get; set; } public string CompetencyAssessmentName { get; set; } public int UserRole { get; set; } - public bool? TaskStatus { get; set; } public string? GroupName { get; set; } public string? SubGroupName { get; set; } public string? RoleName { get; set; } diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/EditRoleProfileLinks.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/EditRoleProfileLinks.cshtml index b5faad6214..96e78ce8d9 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/EditRoleProfileLinks.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/EditRoleProfileLinks.cshtml @@ -119,6 +119,7 @@ + @@ -170,6 +171,7 @@ else if (Model.ActionName == "EditSubGroup" && Model.ProfessionalGroupId != null + @@ -220,6 +222,7 @@ else if (Model.ActionName == "EditRole" && Model.SubGroupId != null) + diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml index 3e4f9f34be..70b5bbdc71 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/ManageCompetencyAssessment.cshtml @@ -57,7 +57,7 @@
- +
- - - - - - + + + + + + +

- This group has @Model.DelegateCount delegate@(DisplayStringHelper.GetPluralitySuffix(Model.DelegateCount)) - and @Model.CourseCount course@(DisplayStringHelper.GetPluralitySuffix(Model.CourseCount)). Deleting this - group will permanently remove all the delegates and courses from this group. + This competency assessment has @Model.CompetencyCount @DisplayStringHelper.PluraliseStringIfRequired(@Model.Vocabulary.ToLower(), Model.CompetencyCount) + associated with it from the framework @Model.FrameworkName. Removing this + framework source will remove the @DisplayStringHelper.PluraliseStringIfRequired(@Model.Vocabulary.ToLower(), Model.CompetencyCount) from the assessment.

- - - + - - +
From 8cd667ecccdab415c3cd41cc30962e267d12c7e8 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Tue, 6 May 2025 11:20:46 +0100 Subject: [PATCH 07/10] TD-5307 Removes frameworks that are already linked from the list of frameworks available to link --- .../SelectFrameworkSourcesViewModel.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs index c50aee9008..8d1adea226 100644 --- a/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/CompetencyAssessments/SelectFrameworkSourcesViewModel.cs @@ -15,7 +15,14 @@ public SelectFrameworkSourcesViewModel(CompetencyAssessmentBase competencyAssess UserRole = competencyAssessmentBase.UserRole; TaskStatus = taskStatus; PrimaryFramework = frameworks.FirstOrDefault(f => f.ID == primaryFramework); - Frameworks = frameworks.OrderBy(f => f.FrameworkName); + var excludedIds = new HashSet(additionalFrameworksIds); + if (primaryFramework.HasValue) + { + excludedIds.Add(primaryFramework.Value); + } + Frameworks = [.. frameworks + .Where(f => !excludedIds.Contains(f.ID)) + .OrderBy(f => f.FrameworkName)]; AdditionalFrameworks = [.. additionalFrameworksIds.Select(id => frameworks.First(f => f.ID == id))]; ActionName = actionName; } From 9b86b6f3f794b43267e9486694b823cfb9d6eff8 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Tue, 6 May 2025 11:21:19 +0100 Subject: [PATCH 08/10] TD-5307 Fixes logic for showing primary and additional framework sections of interface --- .../SelectFrameworkSources.cshtml | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml index ff1d998fa3..35496950f2 100644 --- a/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml +++ b/DigitalLearningSolutions.Web/Views/CompetencyAssessments/SelectFrameworkSources.cshtml @@ -25,8 +25,8 @@

Select framework sources for @Model.CompetencyAssessmentName

-@if (Model.PrimaryFramework != null) -{ + @if (Model.PrimaryFramework != null) + {
Primary framework @@ -40,27 +40,26 @@
- - @if (Model.AdditionalFrameworks.Count() > 0) + } + @if (Model.AdditionalFrameworks.Count() > 0) + { + for (int i = 0; i < Model.AdditionalFrameworks.Count(); i++) { - for (int i = 0; i < Model.AdditionalFrameworks.Count(); i++) - { -
-
- Additional framework @i -
-
- @Model.AdditionalFrameworks.ElementAt(i).FrameworkName -
-
- - Remove @Model.AdditionalFrameworks.ElementAt(i).FrameworkName - -
-
- } +
+
+ Additional framework @i +
+
+ @Model.AdditionalFrameworks.ElementAt(i).FrameworkName +
+
+ + Remove @Model.AdditionalFrameworks.ElementAt(i).FrameworkName + +
+
} -} + }
@if (Model.ActionName == "AddFramework") { From 2cde4fc083f4759c34dfbaa703c60c8edb790acc Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Tue, 6 May 2025 11:48:37 +0100 Subject: [PATCH 09/10] Resets complete status of select frameworks task if a framework is removed --- .../DataServices/CompetencyAssessmentDataService.cs | 8 ++++---- .../CompetencyAssessments.cs | 2 +- .../Services/CompetencyAssessmentService.cs | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index 3d3145e44f..df295c0f72 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -50,7 +50,7 @@ int categoryId bool UpdateBrandingTaskStatus(int assessmentId, bool taskStatus); bool UpdateVocabularyTaskStatus(int assessmentId, bool taskStatus); bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus); - bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus); + bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); bool RemoveSelfAssessmentFramework(int assessmentId, int frameworkId, int adminId); bool UpdateSelectCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); bool UpdateOptionalCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); @@ -529,12 +529,12 @@ FROM SelfAssessmentFrameworks ); } - public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus) + public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus) { var numberOfAffectedRows = connection.Execute( @"UPDATE SelfAssessmentTaskStatus SET FrameworkLinksTaskStatus = @taskStatus - WHERE SelfAssessmentId = @assessmentId", - new { assessmentId, taskStatus } + WHERE SelfAssessmentId = @assessmentId AND (@previousStatus IS NULL OR FrameworkLinksTaskStatus = @previousStatus)", + new { assessmentId, taskStatus, previousStatus } ); if (numberOfAffectedRows < 1) { diff --git a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs index c899639c1e..0d8d3ec490 100644 --- a/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs +++ b/DigitalLearningSolutions.Web/Controllers/CompetencyAssessmentsController/CompetencyAssessments.cs @@ -445,7 +445,7 @@ public IActionResult SelectFrameworkSources(SelectFrameworkSourcesFormData model } else { - competencyAssessmentService.UpdateFrameworkLinksTaskStatus(model.CompetencyAssessmentId, model.TaskStatus ?? false); + competencyAssessmentService.UpdateFrameworkLinksTaskStatus(model.CompetencyAssessmentId, model.TaskStatus ?? false, null); return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId = model.CompetencyAssessmentId }); } } diff --git a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs index 308f1dd63c..80bb557030 100644 --- a/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/CompetencyAssessmentService.cs @@ -39,7 +39,7 @@ public interface ICompetencyAssessmentService bool UpdateCompetencyAssessmentVocabulary(int assessmentId, int adminId, string vocabulary); bool UpdateVocabularyTaskStatus(int assessmentId, bool taskStatus); bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus); - bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus); + bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); bool UpdateSelectCompetenciesTaskStatus(int competencyAssessmentId, bool taskStatus, bool? previousStatus); bool UpdateOptionalCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus); @@ -175,9 +175,9 @@ public bool InsertSelfAssessmentFramework(int adminId, int assessmentId, int fra return competencyAssessmentDataService.InsertSelfAssessmentFramework(adminId, assessmentId, frameworkId); } - public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus) + public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus) { - return competencyAssessmentDataService.UpdateFrameworkLinksTaskStatus(assessmentId, taskStatus); + return competencyAssessmentDataService.UpdateFrameworkLinksTaskStatus(assessmentId, taskStatus, previousStatus); } public int? GetPrimaryLinkedFrameworkId(int assessmentId) @@ -187,6 +187,7 @@ public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus) public bool RemoveSelfAssessmentFramework(int assessmentId, int frameworkId, int adminId) { + UpdateFrameworkLinksTaskStatus(assessmentId, false, true); return competencyAssessmentDataService.RemoveSelfAssessmentFramework(assessmentId, frameworkId, adminId); } From 5c6015c5c130d8b3f915a453b550f80b0ddbc552 Mon Sep 17 00:00:00 2001 From: kevwhitt-hee Date: Tue, 6 May 2025 12:15:07 +0100 Subject: [PATCH 10/10] TD-5307 Fixes csv list of linked frameworks on dashboard --- .../CompetencyAssessmentDataService.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs index df295c0f72..2f597dc696 100644 --- a/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CompetencyAssessmentDataService.cs @@ -92,13 +92,15 @@ FROM AdminUsers sa.Archived, sa.LastEdit, STUFF(( - SELECT - ', ' + f.FrameworkName - FROM - Frameworks f - WHERE - f.ID = saf.FrameworkId - FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS LinkedFrameworks, + SELECT + ', ' + f.FrameworkName + FROM + SelfAssessmentFrameworks saf2 + INNER JOIN Frameworks f ON f.ID = saf2.FrameworkId + WHERE + saf2.SelfAssessmentId = sa.ID + FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '' + ) AS LinkedFrameworks, (SELECT ProfessionalGroup FROM NRPProfessionalGroups WHERE (ID = sa.NRPProfessionalGroupID)) AS NRPProfessionalGroup, @@ -115,8 +117,7 @@ FROM NRPRoles private const string SelfAssessmentTables = @" LEFT OUTER JOIN - SelfAssessmentReviews AS sar ON sac.ID = sar.SelfAssessmentCollaboratorID AND sar.Archived IS NULL AND sar.ReviewComplete IS NULL - LEFT OUTER JOIN SelfAssessmentFrameworks AS saf ON sa.ID = saf.SelfAssessmentId"; + SelfAssessmentReviews AS sar ON sac.ID = sar.SelfAssessmentCollaboratorID AND sar.Archived IS NULL AND sar.ReviewComplete IS NULL"; private readonly IDbConnection connection; private readonly ILogger logger;