Skip to content
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
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ public interface ICompetencyAssessmentDataService

CompetencyAssessmentTaskStatus GetOrInsertAndReturnAssessmentTaskStatus(int assessmentId, bool frameworkBased);

int[] GetLinkedFrameworkIds (int assessmentId);

int? GetPrimaryLinkedFrameworkId(int assessmentId);

int GetCompetencyCountByFrameworkId(int assessmentId, int frameworkId);

//UPDATE DATA
bool UpdateCompetencyAssessmentName(int competencyAssessmentId, int adminId, string competencyAssessmentName);

Expand All @@ -44,10 +50,19 @@ 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? 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);
bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus);

//INSERT DATA
int InsertCompetencyAssessment(int adminId, int centreId, string competencyAssessmentName);
bool InsertSelfAssessmentFramework(int adminId, int selfAssessmentId, int frameworkId);

//DELETE DATA
bool RemoveFrameworkCompetenciesFromAssessment(int competencyAssessmentId, int frameworkId);

}

public class CompetencyAssessmentDataService : ICompetencyAssessmentDataService
Expand Down Expand Up @@ -77,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,
Expand All @@ -100,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<CompetencyAssessmentDataService> logger;
Expand Down Expand Up @@ -324,14 +340,28 @@ 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)
{
numberOfAffectedRows = connection.Execute(
@"UPDATE SelfAssessmentFrameworks
SET RemovedDate = NULL, RemovedByAdminId = NULL, AmendedByAdminId = @adminId
WHERE SelfAssessmentId = @selfAssessmentId AND FrameworkId = @frameworkId"
,
new { adminId, selfAssessmentId, frameworkId }
);
}
if (numberOfAffectedRows < 1)
{
logger.LogWarning(
"Not inserting SelfAssessmentFrameworks record as db insert failed. " +
Expand Down Expand Up @@ -459,5 +489,148 @@ public bool UpdateRoleProfileLinksTaskStatus(int assessmentId, bool taskStatus)
}
return true;
}

public int[] GetLinkedFrameworkIds(int assessmentId)
{
return [.. connection.Query<int>(
@"SELECT FrameworkId
FROM SelfAssessmentFrameworks
WHERE (SelfAssessmentId = @assessmentId) AND (RemovedDate IS NULL) AND (IsPrimary = 0)
ORDER BY ID",
new { assessmentId }
)];
}

public bool RemoveSelfAssessmentFramework(int assessmentId, int frameworkId, int adminId)
{
var numberOfAffectedRows = connection.Execute(
@"UPDATE SelfAssessmentFrameworks SET RemovedDate = @removedDate, RemovedByAdminId = @adminId
WHERE SelfAssessmentId = @assessmentId AND FrameworkId = @frameworkId",
new { removedDate = DateTime.Now, assessmentId, frameworkId, adminId }
);
if (numberOfAffectedRows < 1)
{
logger.LogWarning(
"Not updating SelfAssessmentFrameworks as db update failed. " +
$"assessmentId: {assessmentId}, frameworkId: {frameworkId}, adminId: {adminId}"
);
return false;
}
return true;
}

public int? GetPrimaryLinkedFrameworkId(int assessmentId)
{
return connection.QuerySingleOrDefault<int?>(
@"SELECT TOP(1) FrameworkId
FROM SelfAssessmentFrameworks
WHERE (SelfAssessmentId = @assessmentId) AND (RemovedDate IS NULL) AND (IsPrimary = 1)
ORDER BY ID DESC",
new { assessmentId }
);
}

public bool UpdateFrameworkLinksTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus)
{
var numberOfAffectedRows = connection.Execute(
@"UPDATE SelfAssessmentTaskStatus SET FrameworkLinksTaskStatus = @taskStatus
WHERE SelfAssessmentId = @assessmentId AND (@previousStatus IS NULL OR FrameworkLinksTaskStatus = @previousStatus)",
new { assessmentId, taskStatus, previousStatus }
);
if (numberOfAffectedRows < 1)
{
logger.LogWarning(
"Not updating FrameworkLinksTaskStatus as db update failed. " +
$"assessmentId: {assessmentId}, taskStatus: {taskStatus}"
);
return false;
}
return true;
}

public int GetCompetencyCountByFrameworkId(int assessmentId, int frameworkId)
{
return connection.ExecuteScalar<int>(
@"SELECT COUNT(sas.CompetencyID) AS Competencies
FROM SelfAssessmentStructure AS sas INNER JOIN
FrameworkCompetencies AS fc ON sas.CompetencyID = fc.CompetencyID INNER JOIN
SelfAssessmentFrameworks AS saf ON fc.FrameworkID = saf.FrameworkId AND sas.SelfAssessmentID = saf.SelfAssessmentId
WHERE (saf.SelfAssessmentId = @assessmentId) AND (saf.FrameworkId = @frameworkId)",
new { assessmentId, frameworkId }
);
}

public bool RemoveFrameworkCompetenciesFromAssessment(int competencyAssessmentId, int frameworkId)
{
var numberOfAffectedRows = connection.Execute(
@"DELETE FROM SelfAssessmentStructure
FROM SelfAssessmentStructure INNER JOIN
FrameworkCompetencies AS fc ON SelfAssessmentStructure.CompetencyID = fc.CompetencyID INNER JOIN
SelfAssessmentFrameworks AS saf ON fc.FrameworkID = saf.FrameworkId AND SelfAssessmentStructure.SelfAssessmentID = saf.SelfAssessmentId
WHERE (saf.SelfAssessmentId = @competencyAssessmentId) AND (saf.FrameworkId = @frameworkId)",
new { competencyAssessmentId, frameworkId }
);
if (numberOfAffectedRows < 1)
{
logger.LogWarning(
"Not removing competencies linked to source framework as db update failed. " +
$"assessmentId: {competencyAssessmentId}, taskStatus: {frameworkId}"
);
return false;
}
return true;
}

public bool UpdateSelectCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus)
{
var numberOfAffectedRows = connection.Execute(
@"UPDATE SelfAssessmentTaskStatus SET SelectCompetenciesTaskStatus = @taskStatus
WHERE SelfAssessmentId = @assessmentId AND (@previousStatus IS NULL OR SelectCompetenciesTaskStatus = @previousStatus)",
new { assessmentId, taskStatus, previousStatus }
);
if (numberOfAffectedRows < 1)
{
logger.LogWarning(
"Not updating SelectCompetenciesTaskStatus as db update failed. " +
$"assessmentId: {assessmentId}, taskStatus: {taskStatus}"
);
return false;
}
return true;
}
public bool UpdateOptionalCompetenciesTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus)
{
var numberOfAffectedRows = connection.Execute(
@"UPDATE SelfAssessmentTaskStatus SET OptionalCompetenciesTaskStatus = @taskStatus
WHERE SelfAssessmentId = @assessmentId AND (@previousStatus IS NULL OR OptionalCompetenciesTaskStatus = @previousStatus)",
new { assessmentId, taskStatus, previousStatus }
);
if (numberOfAffectedRows < 1)
{
logger.LogWarning(
"Not updating OptionalCompetenciesTaskStatus as db update failed. " +
$"assessmentId: {assessmentId}, taskStatus: {taskStatus}"
);
return false;
}
return true;
}
public bool UpdateRoleRequirementsTaskStatus(int assessmentId, bool taskStatus, bool? previousStatus)
{
var numberOfAffectedRows = connection.Execute(
@"UPDATE SelfAssessmentTaskStatus SET RoleRequirementsTaskStatus = @taskStatus
WHERE SelfAssessmentId = @assessmentId AND (@previousStatus IS NULL OR RoleRequirementsTaskStatus = @previousStatus)",
new { assessmentId, taskStatus, previousStatus }
);
if (numberOfAffectedRows < 1)
{
logger.LogWarning(
"Not updating RoleRequirementsTaskStatus as db update failed. " +
$"assessmentId: {assessmentId}, taskStatus: {taskStatus}"
);
return false;
}
return true;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
using DigitalLearningSolutions.Data.Models.Centres;
using DigitalLearningSolutions.Data.Models.Frameworks;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using DigitalLearningSolutions.Data.Models.Courses;
using DigitalLearningSolutions.Web.Services;
using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.GroupCourses;

public partial class CompetencyAssessmentsController
{
Expand Down Expand Up @@ -389,5 +392,94 @@ public IActionResult SaveVocabulary(EditVocabularyViewModel model)
competencyAssessmentService.UpdateVocabularyTaskStatus(model.ID, model.TaskStatus ?? false);
return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId = model.ID });
}
[Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/{actionName}")]
public IActionResult SelectFrameworkSources(int competencyAssessmentId, string actionName)
{
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 primaryFrameworkId = competencyAssessmentService.GetPrimaryLinkedFrameworkId(competencyAssessmentId);
var additionalFrameworks = competencyAssessmentService.GetLinkedFrameworkIds(competencyAssessmentId);
var competencyAssessmentTaskStatus = competencyAssessmentService.GetCompetencyAssessmentTaskStatus(competencyAssessmentId, null);
var model = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, additionalFrameworks, primaryFrameworkId, competencyAssessmentTaskStatus.FrameworkLinksTaskStatus, actionName);
return View(model);
}
[HttpPost]
[Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/{actionName}")]
public IActionResult SelectFrameworkSources(SelectFrameworkSourcesFormData model, string actionName)
{
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 primaryFrameworkId = competencyAssessmentService.GetPrimaryLinkedFrameworkId(competencyAssessmentId);
var additionalFrameworks = competencyAssessmentService.GetLinkedFrameworkIds(competencyAssessmentId);
var viewModel = new SelectFrameworkSourcesViewModel(competencyAssessmentBase, frameworks, additionalFrameworks, primaryFrameworkId, model.TaskStatus, model.ActionName);
return View("SelectFrameworkSources", viewModel);
}
if (actionName == "AddFramework")
{
competencyAssessmentService.InsertSelfAssessmentFramework(adminId, competencyAssessmentId, model.FrameworkId);
return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId, actionName = "Summary" });
}
else
{
competencyAssessmentService.UpdateFrameworkLinksTaskStatus(model.CompetencyAssessmentId, model.TaskStatus ?? false, null);
return RedirectToAction("ManageCompetencyAssessment", new { competencyAssessmentId = model.CompetencyAssessmentId });
}
}
[Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/{frameworkId}/Remove")]
public IActionResult RemoveFramework(int frameworkId, int competencyAssessmentId)
{
var frameworkCompetencyCount = competencyAssessmentService.GetCompetencyCountByFrameworkId(competencyAssessmentId, frameworkId);
if (frameworkCompetencyCount > 0)
{
var adminId = GetAdminID();
var competencyAssessmentBase = competencyAssessmentService.GetCompetencyAssessmentBaseById(competencyAssessmentId, adminId);
var framework = frameworkService.GetFrameworkDetailByFrameworkId(frameworkId, adminId);
var model = new ConfirmRemoveFrameworkSourceViewModel(competencyAssessmentBase, framework, frameworkCompetencyCount);
return View("ConfirmRemoveFrameworkSource", model);
}
else
{
var adminId = GetAdminID();
competencyAssessmentService.RemoveSelfAssessmentFramework(competencyAssessmentId, frameworkId, adminId);
}
return RedirectToAction("SelectFrameworkSources", new { competencyAssessmentId, actionName = "Summary" });
}
[HttpPost]
[Route("/CompetencyAssessments/{competencyAssessmentId}/Frameworks/{frameworkId}/Remove")]
public IActionResult RemoveFramework(ConfirmRemoveFrameworkSourceViewModel model)
{
if (!ModelState.IsValid)
{
return View("ConfirmRemoveFrameworkSource", model);
}
var adminId = GetAdminID();
competencyAssessmentService.RemoveFrameworkCompetenciesFromAssessment(model.CompetencyAssessmentId, model.FrameworkId);
competencyAssessmentService.RemoveSelfAssessmentFramework(model.CompetencyAssessmentId, model.FrameworkId, adminId);
return RedirectToAction("SelectFrameworkSources", new { model.CompetencyAssessmentId, actionName = "Summary" });
}
}
}
15 changes: 15 additions & 0 deletions DigitalLearningSolutions.Web/Helpers/DisplayStringHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,21 @@ public static string GetPluralitySuffix(int number)
{
return number == 1 ? string.Empty : "s";
}
public static string PluraliseStringIfRequired(string input, int number)
{
if (number == 1)
{
return input;
}
else if (input.EndsWith("y"))
{
return input.Substring(0, input.Length - 1) + "ies";
}
else
{
return input + "s";
}
}

public static string? ReplaceNonAlphaNumericSpaceChars(string? input, string replacement)
{
Expand Down
Loading
Loading