diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml
index 94fca85b0..f85aecb7c 100644
--- a/.github/workflows/continuous-integration-workflow.yml
+++ b/.github/workflows/continuous-integration-workflow.yml
@@ -3,6 +3,12 @@ on: [push]
env:
BuildParameters.RestoreBuildProjects: '**/*.csproj'
BuildParameters.TestProjects: '**/*[Tt]ests/*.csproj'
+
+ # Nuget Feed Credentials
+ TEL_GITHUB_DEVOPS_USERNAME: ${{ secrets.TEL_GITHUB_DEVOPS_USERNAME }}
+ TEL_GITHUB_PACKAGE_READ_PAT: ${{ secrets.TEL_GITHUB_PACKAGE_READ_PAT }}
+ TEL_AZURE_DEVOPS_USERNAME: ${{ secrets.TEL_AZURE_DEVOPS_USERNAME }}
+ TEL_AZURE_DEVOPS_PAT: ${{ secrets.AZURE_DEVOPS_PAT }}
jobs:
build:
name: Build and test
@@ -15,10 +21,45 @@ jobs:
with:
dotnet-version: 8.0.x
- - name: Add Azure artifact
+ # Todo: remove check once all pipeline work and have the file
+ - name: Check if nuget.config.cicd exists
+ id: check_nuget_cicd
+ run: |
+ if (Test-Path "nuget.config.cicd") {
+ echo "exists=true" >> $env:GITHUB_OUTPUT
+ echo "nuget.config.cicd exists"
+ } else {
+ echo "exists=false" >> $env:GITHUB_OUTPUT
+ echo "nuget.config.cicd doesnt exist"
+ }
+ shell: pwsh
+
+ # Remove local nuget.config (Should be gitignored) and create nuget.config from nuget.config.cicd
+ # Todo: remove if once all pipeline work and have the file
+ - name: Setup NuGet with CICD config
+ if: steps.check_nuget_cicd.outputs.exists == 'true'
+ run: |
+ if (Test-Path "nuget.config") { Remove-Item "nuget.config" }
+ Copy-Item "nuget.config.cicd" "nuget.config"
+ shell: pwsh
+
+ # Replace env values with github secrets
+ - name: Replace environment variables in nuget config
+ if: steps.check_nuget_cicd.outputs.exists == 'true'
+ run: |
+ (Get-Content nuget.config) -replace '%TEL_GITHUB_DEVOPS_USERNAME%', $env:TEL_GITHUB_DEVOPS_USERNAME | Set-Content nuget.config
+ (Get-Content nuget.config) -replace '%TEL_GITHUB_PACKAGE_READ_PAT%', $env:TEL_GITHUB_PACKAGE_READ_PAT | Set-Content nuget.config
+ (Get-Content nuget.config) -replace '%TEL_AZURE_DEVOPS_USERNAME%', $env:TEL_AZURE_DEVOPS_USERNAME | Set-Content nuget.config
+ (Get-Content nuget.config) -replace '%TEL_AZURE_DEVOPS_PAT%', $env:TEL_AZURE_DEVOPS_PAT | Set-Content nuget.config
+ shell: pwsh
+
+ # Todo: remove fallback once all pipeline work and have the file
+ - name: Setup NuGet with Azure DevOps (fallback)
+ if: steps.check_nuget_cicd.outputs.exists == 'false'
run: |
dotnet nuget remove source LearningHubFeed || true
- dotnet nuget add source 'https://pkgs.dev.azure.com/e-LfH/_packaging/LearningHubFeed/nuget/v3/index.json' --name 'LearningHubFeed' --username 'kevin.whittaker' --password ${{ secrets.AZURE_DEVOPS_PAT }} --store-password-in-clear-text
+ dotnet nuget add source 'https://pkgs.dev.azure.com/e-LfH/_packaging/LearningHubFeed/nuget/v3/index.json' --name 'LearningHubFeed' --username 'kevin.whittaker' --password ${{ secrets.AZURE_DEVOPS_PAT }} --store-password-in-clear-text
+
- name: Use Node 14
uses: actions/setup-node@v4
diff --git a/.gitignore b/.gitignore
index 8cc7d8bbe..386443c95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,3 +56,13 @@ obj
/AdminUI/LearningHub.Nhs.AdminUI/web.config
/LearningHub.Nhs.WebUI/web.config
/WebAPI/LearningHub.Nhs.API/web.config
+/.github/workflows/test.yml
+/LearningHub.Nhs.WebUI.BlazorClient/Properties/launchSettings.json
+/LearningHub.Nhs.WebUI.slnLaunch.user
+/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user
+/LearningHub.Nhs.WebUI.BlazorClient/wwwroot/appsettings.Development.json
+/nuget.config
+/LearningHub.Nhs.WebUI.slnLaunch.user
+/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user
+/LearningHub.Nhs.WebUI.BlazorClient/wwwroot/appsettings.Development.json
+/LearningHub.Nhs.WebUI.BlazorClient/Properties/launchSettings.json
\ No newline at end of file
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj
index a0de54f8f..04b499ea4 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj
+++ b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj
@@ -83,13 +83,13 @@
-
+
-
+
diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj
index 1569f9734..e9d58ce5a 100644
--- a/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj
+++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj
@@ -1,4 +1,4 @@
-
+
net8.0
@@ -11,7 +11,9 @@
+
+
diff --git a/LearningHub.Nhs.WebUI/Configuration/MoodleApiConfig.cs b/LearningHub.Nhs.WebUI/Configuration/MoodleApiConfig.cs
new file mode 100644
index 000000000..ec874477e
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Configuration/MoodleApiConfig.cs
@@ -0,0 +1,33 @@
+namespace LearningHub.Nhs.WebUI.Configuration
+{
+ ///
+ /// The Moodle Settings.
+ ///
+ public class MoodleApiConfig
+ {
+ ///
+ /// Gets or sets the base url for the Moodle service.
+ ///
+ public string BaseUrl { get; set; } = null!;
+
+ ///
+ /// Gets or sets the Web service Rest Format.
+ ///
+ public string MoodleWSRestFormat { get; set; } = null!;
+
+ ///
+ /// Gets or sets the token.
+ ///
+ public string WSToken { get; set; } = null!;
+
+ ///
+ /// Gets or sets the token.
+ ///
+ public string ApiPath { get; set; } = "webservice/rest/server.php";
+
+ ///
+ /// Gets or sets the token.
+ ///
+ public string CoursePath { get; set; } = "course/view.php";
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/MyLearningController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/MyLearningController.cs
index bcd13c08a..64b6de28d 100644
--- a/LearningHub.Nhs.WebUI/Controllers/Api/MyLearningController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/Api/MyLearningController.cs
@@ -44,6 +44,34 @@ public async Task GetActivityDetailed([FromBody] MyLearningRequest
return this.Ok(activity);
}
+ ///
+ /// Gets the detailed activity data.
+ ///
+ /// The request model - filter settings.
+ /// The .
+ [HttpPost]
+ [Route("GetUserRecentMyLearningActivities")]
+ public async Task GetUserRecentMyLearningActivities([FromBody] MyLearningRequestModel requestModel)
+ {
+ var activity = await this.myLearningService.GetUserRecentMyLearningActivities(requestModel);
+
+ return this.Ok(activity);
+ }
+
+ ///
+ /// Gets the detailed activity data.
+ ///
+ /// The request model - filter settings.
+ /// The .
+ [HttpPost]
+ [Route("GetUserLearningHistory")]
+ public async Task GetUserLearningHistory([FromBody] MyLearningRequestModel requestModel)
+ {
+ var activity = await this.myLearningService.GetUserLearningHistory(requestModel);
+
+ return this.Ok(activity);
+ }
+
///
/// Gets the played segment data for the progress modal in My Learning screen.
///
diff --git a/LearningHub.Nhs.WebUI/Controllers/ContributeController.cs b/LearningHub.Nhs.WebUI/Controllers/ContributeController.cs
index fc3b7f76a..27ae615ce 100644
--- a/LearningHub.Nhs.WebUI/Controllers/ContributeController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/ContributeController.cs
@@ -28,6 +28,7 @@ public class ContributeController : BaseController
private readonly IFileService fileService;
private readonly IResourceService resourceService;
private readonly IUserService userService;
+ private readonly IUserGroupService userGroupService;
///
/// Initializes a new instance of the class.
@@ -37,6 +38,7 @@ public class ContributeController : BaseController
/// Logger.
/// Settings.
/// User service.
+ /// userGroupService.
/// File service.
/// Resource service.
/// Azure media service.
@@ -48,6 +50,7 @@ public ContributeController(
ILogger logger,
IOptions settings,
IUserService userService,
+ IUserGroupService userGroupService,
IFileService fileService,
IResourceService resourceService,
IAzureMediaService azureMediaService,
@@ -58,6 +61,7 @@ public ContributeController(
this.authConfig = authConfig;
this.userService = userService;
+ this.userGroupService = userGroupService;
this.fileService = fileService;
this.resourceService = resourceService;
this.azureMediaService = azureMediaService;
@@ -167,7 +171,8 @@ public async Task CreateVersion(int resourceId)
[Route("my-contributions/{selectedTab}/{catalogueId}/{nodeId}")]
public async Task MyContributions()
{
- if ((this.User.IsInRole("ReadOnly") || this.User.IsInRole("BasicUser")) && !await this.resourceService.UserHasPublishedResourcesAsync())
+ bool catalogueContributionPermission = await this.userGroupService.UserHasCatalogueContributionPermission();
+ if ((this.User.IsInRole("ReadOnly") || this.User.IsInRole("BasicUser")) || (!catalogueContributionPermission && (!await this.resourceService.UserHasPublishedResourcesAsync())))
{
return this.RedirectToAction("AccessDenied", "Home");
}
diff --git a/LearningHub.Nhs.WebUI/Controllers/HomeController.cs b/LearningHub.Nhs.WebUI/Controllers/HomeController.cs
index d5f53c00d..a23e986e0 100644
--- a/LearningHub.Nhs.WebUI/Controllers/HomeController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/HomeController.cs
@@ -11,6 +11,7 @@ namespace LearningHub.Nhs.WebUI.Controllers
using LearningHub.Nhs.Models.Content;
using LearningHub.Nhs.Models.Enums.Content;
using LearningHub.Nhs.Models.Extensions;
+ using LearningHub.Nhs.Models.Moodle.API;
using LearningHub.Nhs.WebUI.Configuration;
using LearningHub.Nhs.WebUI.Filters;
using LearningHub.Nhs.WebUI.Helpers;
@@ -202,31 +203,23 @@ public IActionResult HomepageWithAuthentication()
///
/// Index.
///
+ /// The resource type.
/// The my learning dashboard type.
/// The resource dashboard type.
/// The catalogue dashboard type.
/// Home page.
- public async Task Index(string myLearningDashboard = "my-in-progress", string resourceDashboard = "popular-resources", string catalogueDashboard = "popular-catalogues")
+ public async Task Index(string dashboardTrayLearningResourceType = "all", string myLearningDashboard = "my-in-progress", string resourceDashboard = "popular-resources", string catalogueDashboard = "popular-catalogues")
{
if (this.User?.Identity.IsAuthenticated == true)
{
this.Logger.LogInformation("User is authenticated: User is {fullname} and userId is: {lhuserid}", this.User.Identity.GetCurrentName(), this.User.Identity.GetCurrentUserId());
if (this.User.IsInRole("Administrator") || this.User.IsInRole("BlueUser") || this.User.IsInRole("ReadOnly") || this.User.IsInRole("BasicUser"))
{
- var learningTask = this.dashboardService.GetMyAccessLearningsAsync(myLearningDashboard, 1);
+ var learningTask = this.dashboardService.GetMyCoursesAndElearning(dashboardTrayLearningResourceType, myLearningDashboard, 1);
var resourcesTask = this.dashboardService.GetResourcesAsync(resourceDashboard, 1);
var cataloguesTask = this.dashboardService.GetCataloguesAsync(catalogueDashboard, 1);
var userGroupsTask = this.userGroupService.UserHasCatalogueContributionPermission();
- var enrolledCoursesTask = Task.FromResult(new List());
- var enableMoodle = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.EnableMoodle)).Result;
- this.ViewBag.EnableMoodle = enableMoodle;
- this.ViewBag.ValidMoodleUser = this.CurrentMoodleUserId > 0;
- if (enableMoodle && myLearningDashboard == "my-enrolled-courses")
- {
- enrolledCoursesTask = this.dashboardService.GetEnrolledCoursesFromMoodleAsync(this.CurrentMoodleUserId, 1);
- }
-
await Task.WhenAll(learningTask, resourcesTask, cataloguesTask, userGroupsTask);
var model = new DashboardViewModel()
@@ -234,7 +227,7 @@ public async Task Index(string myLearningDashboard = "my-in-progr
MyLearnings = await learningTask,
Resources = await resourcesTask,
Catalogues = await cataloguesTask,
- EnrolledCourses = await enrolledCoursesTask,
+ DashboardTrayLearningResourceType = dashboardTrayLearningResourceType,
};
var userHasContributePermission = await userGroupsTask;
this.ViewBag.userHasContributePermission = userHasContributePermission;
@@ -261,6 +254,7 @@ public async Task Index(string myLearningDashboard = "my-in-progr
///
/// Load the specified dashobard page.
///
+ /// dashboardTrayLearningResourceType.
/// dashBoardTray.
/// myLearningDashBoard.
/// resourceDashBoard.
@@ -268,8 +262,8 @@ public async Task Index(string myLearningDashboard = "my-in-progr
/// pageNumber.
/// Dashboard page.
[Authorize]
- [Route("/Home/loadpage/{dashBoardTray}/{myLearningDashBoard}/{resourceDashBoard}/{catalogueDashBoard}/{pageNumber:int}")]
- public async Task LoadPage(string dashBoardTray = "my-learning", string myLearningDashBoard = "in-progress", string resourceDashBoard = "popular-resources", string catalogueDashBoard = "recent-catalogues", int pageNumber = 1)
+ [Route("/Home/loadpage/{dashboardTrayLearningResourceType}/{dashBoardTray}/{myLearningDashBoard}/{resourceDashBoard}/{catalogueDashBoard}/{pageNumber:int}")]
+ public async Task LoadPage(string dashboardTrayLearningResourceType = "all", string dashBoardTray = "my-learning", string myLearningDashBoard = "in-progress", string resourceDashBoard = "popular-resources", string catalogueDashBoard = "recent-catalogues", int pageNumber = 1)
{
if (this.User.IsInRole("Administrator") || this.User.IsInRole("BlueUser") || this.User.IsInRole("ReadOnly") || this.User.IsInRole("BasicUser"))
{
@@ -278,12 +272,9 @@ public async Task LoadPage(string dashBoardTray = "my-learning",
MyLearnings = new Nhs.Models.Dashboard.DashboardMyLearningResponseViewModel { Type = myLearningDashBoard },
Resources = new Nhs.Models.Dashboard.DashboardResourceResponseViewModel { Type = resourceDashBoard },
Catalogues = new Nhs.Models.Dashboard.DashboardCatalogueResponseViewModel { Type = catalogueDashBoard },
+ DashboardTrayLearningResourceType = dashboardTrayLearningResourceType,
};
- var enableMoodle = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.EnableMoodle)).Result;
- this.ViewBag.EnableMoodle = enableMoodle;
- this.ViewBag.ValidMoodleUser = this.CurrentMoodleUserId > 0;
-
bool isAjax = this.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest";
if (isAjax)
@@ -291,8 +282,8 @@ public async Task LoadPage(string dashBoardTray = "my-learning",
switch (dashBoardTray)
{
case "my-learning":
- model.MyLearnings = await this.dashboardService.GetMyAccessLearningsAsync(myLearningDashBoard, pageNumber);
- return this.PartialView("_MyAccessedLearningTray", model);
+ model.MyLearnings = await this.dashboardService.GetMyCoursesAndElearning(dashboardTrayLearningResourceType, myLearningDashBoard, pageNumber);
+ return this.PartialView("_MyCoursesAndElearning", model);
case "resources":
model.Resources = await this.dashboardService.GetResourcesAsync(resourceDashBoard, pageNumber);
return this.PartialView("_ResourceTray", model);
@@ -303,13 +294,14 @@ public async Task LoadPage(string dashBoardTray = "my-learning",
}
else
{
- var learningTask = this.dashboardService.GetMyAccessLearningsAsync(myLearningDashBoard, dashBoardTray == "my-learning" ? pageNumber : 1);
+ var learningTask = this.dashboardService.GetMyCoursesAndElearning(dashboardTrayLearningResourceType, myLearningDashBoard, dashBoardTray == "my-learning" ? pageNumber : 1);
var resourcesTask = this.dashboardService.GetResourcesAsync(resourceDashBoard, dashBoardTray == "resources" ? pageNumber : 1);
var cataloguesTask = this.dashboardService.GetCataloguesAsync(catalogueDashBoard, dashBoardTray == "catalogues" ? pageNumber : 1);
await Task.WhenAll(learningTask, resourcesTask, cataloguesTask);
model.MyLearnings = await learningTask;
model.Resources = await resourcesTask;
model.Catalogues = await cataloguesTask;
+ model.DashboardTrayLearningResourceType = dashboardTrayLearningResourceType;
return this.View("Dashboard", model);
}
}
@@ -449,5 +441,28 @@ private async Task GetLandingPageContent(bool preview = fa
return new LandingPageViewModel { PageSectionDetailViewModels = new List(), PageViewModel = new PageViewModel { PageSections = new List { } } };
}
}
+
+ ///
+ /// Asynchronously retrieves the state of the Moodle feature and the current Moodle user ID.
+ ///
+ /// The method checks if the Moodle feature is enabled and retrieves the current Moodle
+ /// user ID. If the user ID is not already set, it attempts to obtain it asynchronously from the dashboard
+ /// service.
+ /// A tuple containing a boolean indicating whether the Moodle feature is enabled and an integer representing
+ /// the current Moodle user ID.
+ private async Task<(bool enableMoodle, int currentMoodleUserId)> GetMoodleFeatureStateAsync()
+ {
+ var enableMoodle = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.EnableMoodle)).Result;
+ this.ViewBag.EnableMoodle = enableMoodle;
+ int currentMoodleUserId = this.CurrentMoodleUserId;
+
+ if (currentMoodleUserId == 0)
+ {
+ currentMoodleUserId = await this.dashboardService.GetMoodleUserIdAsync(this.CurrentUserId);
+ }
+
+ this.ViewBag.ValidMoodleUser = currentMoodleUserId > 0;
+ return (enableMoodle, currentMoodleUserId);
+ }
}
}
diff --git a/LearningHub.Nhs.WebUI/Controllers/LoginWizardController.cs b/LearningHub.Nhs.WebUI/Controllers/LoginWizardController.cs
index fab43e688..2ffc17e13 100644
--- a/LearningHub.Nhs.WebUI/Controllers/LoginWizardController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/LoginWizardController.cs
@@ -144,31 +144,7 @@ public async Task Index(string returnUrl)
if (currentStage?.Id == (int)LoginWizardStageEnum.SecurityQuestions)
{
- SecurityQuestionsViewModel securityQuestions = await this.loginWizardService.GetSecurityQuestionsModel(this.CurrentUserId);
-
- while (securityQuestions.UserSecurityQuestions.Count < this.Settings.SecurityQuestionsToAsk)
- {
- securityQuestions.UserSecurityQuestions.Add(new UserSecurityQuestionViewModel());
- }
-
- foreach (var answer in securityQuestions.UserSecurityQuestions)
- {
- if (!string.IsNullOrEmpty(answer.SecurityQuestionAnswerHash))
- {
- answer.SecurityQuestionAnswerHash = "********";
- }
- }
-
- this.TempData.Clear();
- var securityViewModel = new SecurityViewModel()
- {
- SecurityQuestions = securityQuestions.SecurityQuestions,
- UserSecurityQuestions = securityQuestions.UserSecurityQuestions,
- };
-
- await this.multiPageFormService.SetMultiPageFormData(securityViewModel, MultiPageFormDataFeature.EditRegistrationPrompt, this.TempData);
-
- return this.RedirectToAction("SelectSecurityQuestion", new RouteValueDictionary { { "questionIndex", 0 }, { "returnUrl", returnUrl } });
+ return this.RedirectToAction("SelectSecurityQuestions", new { returnUrl });
}
if (currentStage?.Id == (int)LoginWizardStageEnum.JobRole || currentStage?.Id == (int)LoginWizardStageEnum.PlaceOfWork || currentStage?.Id == (int)LoginWizardStageEnum.PersonalDetails)
@@ -201,6 +177,7 @@ public async Task Index(string returnUrl)
PrimarySpecialtyId = userEmployment.SpecialtyId.HasValue ? userEmployment.SpecialtyId.ToString() : null,
RegistrationNumber = userEmployment.MedicalCouncilNo,
StartDate = userEmployment.StartDate.HasValue ? userEmployment.StartDate.Value.DateTime : null,
+ LocationId = userEmployment.LocationId.ToString(),
};
await this.multiPageFormService.SetMultiPageFormData(
@@ -213,11 +190,19 @@ await this.multiPageFormService.SetMultiPageFormData(
{
return this.RedirectToAction("AccountInformationNeeded");
}
+ else if (currentStage?.Id == (int)LoginWizardStageEnum.JobRole || currentStage?.Id == (int)LoginWizardStageEnum.PlaceOfWork)
+ {
+ return this.RedirectToAction("MyEmploymentDetails", "MyAccount", new { returnUrl, checkDetails = true });
+ }
else
{
return this.RedirectToAction("Index", "MyAccount", new { returnUrl, checkDetails = true });
}
}
+ else if (currentStage?.Id == (int)LoginWizardStageEnum.JobRole || currentStage?.Id == (int)LoginWizardStageEnum.PlaceOfWork)
+ {
+ return this.RedirectToAction("MyEmploymentDetails", "MyAccount", new { returnUrl, checkDetails = true });
+ }
else
{
return this.RedirectToAction("Index", "MyAccount", new { returnUrl, checkDetails = true });
@@ -585,6 +570,118 @@ public async Task AccountConfirmationPost()
return this.RedirectToAction("Index", new RouteValueDictionary { { "returnUrl", accountModel.WizardReturnUrl } });
}
+ ///
+ /// Action for starting the security question multiPageForm stage of the wizard.
+ ///
+ /// The URL to return to after the login wizard has been completed.
+ /// The .
+ [ResponseCache(CacheProfileName = "Never")]
+ public async Task SelectSecurityQuestions(string returnUrl)
+ {
+ MyAcountSecurityQuestionsViewModel securityViewModel = new MyAcountSecurityQuestionsViewModel();
+ var result = await this.loginWizardService.GetSecurityQuestionsModel(this.CurrentUserId);
+
+ if (result != null)
+ {
+ securityViewModel.FirstSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedFirstQuestionId));
+ securityViewModel.SecondSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedSecondQuestionId));
+ }
+
+ this.ViewBag.ReturnUrl = returnUrl;
+ return this.View("SecurityQuestionsDetails", securityViewModel);
+ }
+
+ ///
+ /// Action for choosing security questions.
+ ///
+ /// The MyAcountSecurityQuestionsViewModel.
+ /// The URL to return to after the login wizard has been completed.
+ /// The .
+ [HttpPost]
+ [ResponseCache(CacheProfileName = "Never")]
+ public async Task UpdateSecurityQuestionPost(MyAcountSecurityQuestionsViewModel model, string returnUrl)
+ {
+ MyAcountSecurityQuestionsViewModel securityViewModel = new MyAcountSecurityQuestionsViewModel();
+ var result = await this.loginWizardService.GetSecurityQuestionsModel(this.CurrentUserId);
+
+ if (result != null)
+ {
+ securityViewModel.FirstSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedFirstQuestionId));
+ securityViewModel.SecondSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedSecondQuestionId));
+ }
+
+ if (model != null)
+ {
+ if ((model.SelectedFirstQuestionId == 0) || (model.SelectedSecondQuestionId == 0))
+ {
+ if (model.SelectedFirstQuestionId == 0)
+ {
+ this.ModelState.AddModelError(nameof(model.SelectedFirstQuestionId), CommonValidationErrorMessages.SecurityQuestionRequired);
+ }
+
+ if (model.SelectedSecondQuestionId == 0)
+ {
+ this.ModelState.AddModelError(nameof(model.SelectedSecondQuestionId), CommonValidationErrorMessages.SecurityQuestionRequired);
+ }
+
+ this.ViewBag.ReturnUrl = returnUrl;
+ return this.View("SecurityQuestionsDetails", securityViewModel);
+ }
+
+ if (model.SelectedFirstQuestionId == model.SelectedSecondQuestionId)
+ {
+ this.ModelState.AddModelError("DuplicateQuestion", CommonValidationErrorMessages.DuplicateQuestion);
+ }
+
+ if ((model.SelectedFirstQuestionId > 0 && string.IsNullOrEmpty(model.SecurityFirstQuestionAnswerHash)) || (model.SelectedSecondQuestionId > 0 && string.IsNullOrEmpty(model.SecuritySecondQuestionAnswerHash)))
+ {
+ this.ModelState.AddModelError(nameof(model.SecurityFirstQuestionAnswerHash), CommonValidationErrorMessages.InvalidSecurityQuestionAnswer);
+ this.ModelState.AddModelError(nameof(model.SecuritySecondQuestionAnswerHash), CommonValidationErrorMessages.InvalidSecurityQuestionAnswer);
+ }
+
+ if (this.ModelState.IsValid)
+ {
+ var userSecurityQuestions = new List
+ {
+ new UserSecurityQuestionViewModel
+ {
+ SecurityQuestionId = model.SelectedFirstQuestionId,
+ SecurityQuestionAnswerHash = model.SecurityFirstQuestionAnswerHash,
+ UserId = this.CurrentUserId,
+ },
+ new UserSecurityQuestionViewModel
+ {
+ SecurityQuestionId = model.SelectedSecondQuestionId,
+ SecurityQuestionAnswerHash = model.SecuritySecondQuestionAnswerHash,
+ UserId = this.CurrentUserId,
+ },
+ };
+
+ await this.userService.UpdateUserSecurityQuestions(userSecurityQuestions);
+
+ // Mark stage complete.
+ var (cacheExists, loginWizard) = await this.cacheService.TryGetAsync(this.LoginWizardCacheKey);
+
+ if (cacheExists)
+ {
+ await this.CompleteLoginWizardStageAsync(loginWizard, LoginWizardStageEnum.SecurityQuestions);
+ this.TempData.Clear();
+ return this.RedirectToAction("Index", new RouteValueDictionary { { "returnUrl", returnUrl } });
+ }
+
+ this.TempData.Clear();
+ return this.Redirect("/");
+ }
+ else
+ {
+ this.ViewBag.ReturnUrl = returnUrl;
+ return this.View("SecurityQuestionsDetails", securityViewModel);
+ }
+ }
+
+ return this.View("SecurityQuestionsDetails", securityViewModel);
+ }
+
///
/// The complete login wizard stage.
///
diff --git a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs
index d1dadb902..3bb63d6e2 100644
--- a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs
@@ -131,8 +131,333 @@ public async Task Index(string returnUrl = null, bool? checkDetai
}
}
- var userProfileSummary = await this.userService.GetUserProfileSummaryAsync();
- return this.View("Index", userProfileSummary);
+ var userPersonalDetails = await this.userService.GetMyAccountPersonalDetailsAsync();
+ return this.View("Index", userPersonalDetails);
+ }
+
+ ///
+ /// MyEmploymentDetails.
+ ///
+ /// Whether to check account details.
+ /// IActionResult.
+ [HttpGet]
+ [Route("myaccount-employment")]
+ public async Task MyEmploymentDetails(bool? checkDetails = false)
+ {
+ string loginWizardCacheKey = $"{this.CurrentUserId}:LoginWizard";
+ var (cacheExists, loginWizard) = await this.cacheService.TryGetAsync(loginWizardCacheKey);
+
+ if (checkDetails == true || cacheExists)
+ {
+ this.ViewBag.CheckDetails = true;
+
+ var rules = loginWizard.LoginWizardStagesRemaining.SelectMany(l => l.LoginWizardRules.Where(r => r.Required));
+ foreach (var rule in rules)
+ {
+ this.ModelState.AddModelError(string.Empty, rule.Description);
+ }
+
+ if (this.TempData.ContainsKey("IsJobRoleRequired"))
+ {
+ if (this.TempData["IsJobRoleRequired"] != null && (bool)this.TempData["IsJobRoleRequired"] == true)
+ {
+ this.ModelState.AddModelError(string.Empty, CommonValidationErrorMessages.RoleRequired);
+ this.TempData["IsJobRoleRequired"] = null;
+ }
+ }
+ }
+
+ var employmentDetails = await this.userService.GetMyEmploymentDetailsAsync();
+ return this.View("MyEmployment", employmentDetails);
+ }
+
+ ///
+ /// User profile actions.
+ ///
+ /// The redirect back url.
+ /// Whether to check account details.
+ /// IActionResult.
+ [HttpGet]
+ [Route("myaccount-security")]
+ public async Task MyAccountSecurity(string returnUrl = null, bool? checkDetails = false)
+ {
+ var securityDetails = await this.userService.GetMyAccountSecurityDetailsAsync();
+ return this.View("MyAccountSecurity", securityDetails);
+ }
+
+ ///
+ /// ChangePersonalDetails.
+ ///
+ /// ActionResult.
+ [HttpGet]
+ [Route("myaccount/ChangePersonalDetails")]
+ public async Task ChangePersonalDetails()
+ {
+ var userPersonalDetails = await this.userService.GetMyAccountPersonalDetailsAsync();
+ return this.View("ChangePersonalDetails", userPersonalDetails);
+ }
+
+ ///
+ /// To Update first name.
+ ///
+ /// model.
+ /// ActionResult.
+ [HttpPost]
+ public async Task UpdatePersonalDetails(MyAccountPersonalDetailsViewModel model)
+ {
+ if (!this.ModelState.IsValid)
+ {
+ return this.View("ChangePersonalDetails", model);
+ }
+
+ if (model.PrimaryEmailAddress.ToLower() == model.SecondaryEmailAddress?.ToLower())
+ {
+ this.ModelState.AddModelError(nameof(model.SecondaryEmailAddress), CommonValidationErrorMessages.SecondaryEmailShouldNotBeSame);
+ return this.View("ChangePersonalDetails", model);
+ }
+
+ bool userPrimaryEmailAddressChanged = false;
+ var user = await this.userService.GetUserByUserIdAsync(this.CurrentUserId);
+ if (user != null)
+ {
+ if (!string.IsNullOrEmpty(model.PrimaryEmailAddress) && user.EmailAddress.ToLower() != model.PrimaryEmailAddress.ToLower())
+ {
+ userPrimaryEmailAddressChanged = true;
+ }
+ }
+
+ if (userPrimaryEmailAddressChanged)
+ {
+ if (await this.userService.DoesEmailAlreadyExist(model.PrimaryEmailAddress))
+ {
+ this.ModelState.AddModelError(
+ nameof(model.PrimaryEmailAddress),
+ CommonValidationErrorMessages.DuplicateEmailAddress);
+ return this.View("ChangePersonalDetails", model);
+ }
+ else
+ {
+ await this.MyAccountUpdatePrimaryEmail(user.EmailAddress, model.PrimaryEmailAddress);
+ }
+ }
+
+ bool isSamePrimaryEmailPendingforValidate = await this.userService.CheckSamePrimaryemailIsPendingToValidate(model.SecondaryEmailAddress);
+ if (isSamePrimaryEmailPendingforValidate)
+ {
+ this.ModelState.AddModelError(string.Empty, CommonValidationErrorMessages.SecondaryEmailShouldNotBeSame);
+ return this.View("ChangePersonalDetails", model);
+ }
+
+ await this.userService.UpdateMyAccountPersonalDetailsAsync(this.CurrentUserId, model);
+ this.ViewBag.SuccessMessage = CommonValidationErrorMessages.PersonalDetailsSuccessMessage;
+ this.ViewBag.MyAction = "Index";
+ return this.View("SuccessMessageMyAccount");
+ }
+
+ ///
+ /// ChangeLocation.
+ ///
+ /// model.
+ /// formSubmission.
+ /// ActionResult.
+ [HttpGet]
+ [Route("myaccount/ChangeLocation")]
+ public async Task ChangeLocation([FromQuery] MyAccountLocationViewModel model, bool formSubmission = false)
+ {
+ var userLocationViewModel = await this.userService.GetMyAccountLocationDetailsAsync();
+ var allUKcountries = await this.countryService.GetAllUKCountries();
+ var allnonUKcountries = await this.countryService.GetAllNonUKCountries();
+ var regions = await this.regionService.GetAllAsync();
+
+ List radio = new List();
+ foreach (var country in allUKcountries)
+ {
+ var newradio = new RadiosItemViewModel(country.Id.ToString(), country.Name, false, country.Name);
+ radio.Add(newradio);
+ }
+
+ if (allnonUKcountries.Any(v => v.Id == userLocationViewModel.SelectedCountryId))
+ {
+ userLocationViewModel.SelectedOtherCountryId = userLocationViewModel.SelectedCountryId;
+ userLocationViewModel.SelectedCountryId = 0;
+ }
+
+ userLocationViewModel.Country = radio;
+ userLocationViewModel.OtherCountryOptions = SelectListHelper.MapOptionsToSelectListItems(allnonUKcountries, userLocationViewModel.SelectedOtherCountryId);
+
+ userLocationViewModel.RegionOptions = SelectListHelper.MapOptionsToSelectListItems(regions, userLocationViewModel.SelectedRegionId);
+
+ if (formSubmission)
+ {
+ if (model?.SelectedCountryId == null)
+ {
+ this.ModelState.AddModelError(nameof(model.SelectedCountryId), CommonValidationErrorMessages.CountryRequired);
+ return this.View("MyAccountChangeLocation", userLocationViewModel);
+ }
+ else if (model.SelectedCountryId == 1 && model.SelectedRegionId == null)
+ {
+ userLocationViewModel.HasSelectedRegion = true;
+ this.ModelState.AddModelError(nameof(model.SelectedRegionId), CommonValidationErrorMessages.RegionRequired);
+ return this.View("MyAccountChangeLocation", userLocationViewModel);
+ }
+ else if (model.SelectedCountryId != 1)
+ {
+ model.SelectedRegionId = null;
+ }
+
+ if (model?.SelectedCountryId == 0)
+ {
+ if (model.SelectedOtherCountryId != null && model.SelectedOtherCountryId > 0)
+ {
+ model.SelectedCountryId = model.SelectedOtherCountryId;
+ }
+ else
+ {
+ userLocationViewModel.HasSelectedOtherCountry = true;
+ this.ModelState.AddModelError(nameof(model.SelectedOtherCountryId), CommonValidationErrorMessages.CountryRequired);
+ return this.View("MyAccountChangeLocation", userLocationViewModel);
+ }
+ }
+
+ if (this.ModelState.IsValid)
+ {
+ await this.userService.UpdateMyAccountLocationDetailsAsync(this.CurrentUserId, model);
+ this.ViewBag.SuccessMessage = CommonValidationErrorMessages.LocationDetailsSuccessMessage;
+ this.ViewBag.MyAction = "MyEmploymentDetails";
+ return this.View("SuccessMessageMyAccount");
+ }
+ }
+
+ return this.View("MyAccountChangeLocation", userLocationViewModel);
+ }
+
+ ///
+ /// SecurityQuestionsDetails.
+ ///
+ /// viewModel.
+ /// formSubmission.
+ /// ActionResult.
+ [HttpGet]
+ [Route("myaccount/MyAccountSecurityQuestionsDetails")]
+ public async Task MyAccountSecurityQuestionsDetails([FromQuery] MyAcountSecurityQuestionsViewModel viewModel, bool formSubmission = false)
+ {
+ MyAcountSecurityQuestionsViewModel securityViewModel = new MyAcountSecurityQuestionsViewModel();
+ var result = await this.loginWizardService.GetSecurityQuestionsModel(this.CurrentUserId);
+
+ if (result != null)
+ {
+ if (result.UserSecurityQuestions != null && result.UserSecurityQuestions.Count > 0)
+ {
+ securityViewModel.SelectedFirstQuestionId = result.UserSecurityQuestions[0].SecurityQuestionId;
+ securityViewModel.SelectedSecondQuestionId = result.UserSecurityQuestions.Count > 1 ? result.UserSecurityQuestions[1].SecurityQuestionId : 0;
+ securityViewModel.UserSecurityFirstQuestionId = result.UserSecurityQuestions[0].Id;
+ securityViewModel.UserSecuritySecondQuestionId = result.UserSecurityQuestions.Count > 1 ? result.UserSecurityQuestions[1].Id : 0;
+ }
+
+ securityViewModel.FirstSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedFirstQuestionId));
+ securityViewModel.SecondSecurityQuestions = SelectListHelper.MapSelectListWithSelection(result.SecurityQuestions, Convert.ToString(securityViewModel.SelectedSecondQuestionId));
+ }
+
+ if (formSubmission && viewModel != null)
+ {
+ if (viewModel.SelectedFirstQuestionId == viewModel.SelectedSecondQuestionId)
+ {
+ this.ModelState.AddModelError("DuplicateQuestion", CommonValidationErrorMessages.DuplicateQuestion);
+ return this.View("MyAccountSecurityQuestionsDetails", securityViewModel);
+ }
+
+ if ((viewModel.SelectedFirstQuestionId > 0 && string.IsNullOrEmpty(viewModel.SecurityFirstQuestionAnswerHash)) || (viewModel.SelectedSecondQuestionId > 0 && string.IsNullOrEmpty(viewModel.SecuritySecondQuestionAnswerHash)))
+ {
+ this.ModelState.AddModelError(nameof(viewModel.SecurityFirstQuestionAnswerHash), CommonValidationErrorMessages.InvalidSecurityQuestionAnswer);
+ this.ModelState.AddModelError(nameof(viewModel.SecuritySecondQuestionAnswerHash), CommonValidationErrorMessages.InvalidSecurityQuestionAnswer);
+ return this.View("MyAccountSecurityQuestionsDetails", securityViewModel);
+ }
+
+ if (this.ModelState.IsValid)
+ {
+ var userSecurityQuestions = new List
+ {
+ new UserSecurityQuestionViewModel
+ {
+ Id = securityViewModel.UserSecurityFirstQuestionId,
+ SecurityQuestionId = viewModel.SelectedFirstQuestionId,
+ SecurityQuestionAnswerHash = viewModel.SecurityFirstQuestionAnswerHash,
+ UserId = this.CurrentUserId,
+ },
+ new UserSecurityQuestionViewModel
+ {
+ Id = securityViewModel.UserSecuritySecondQuestionId,
+ SecurityQuestionId = viewModel.SelectedSecondQuestionId,
+ SecurityQuestionAnswerHash = viewModel.SecuritySecondQuestionAnswerHash,
+ UserId = this.CurrentUserId,
+ },
+ };
+
+ await this.userService.UpdateUserSecurityQuestions(userSecurityQuestions);
+
+ this.ViewBag.SuccessMessage = CommonValidationErrorMessages.SecurityQuestionSuccessMessage;
+ this.ViewBag.MyAction = "MyAccountSecurity";
+ return this.View("SuccessMessageMyAccount");
+ }
+ else
+ {
+ return this.View("MyAccountSecurityQuestionsDetails", securityViewModel);
+ }
+ }
+
+ return this.View("MyAccountSecurityQuestionsDetails", securityViewModel);
+ }
+
+ ///
+ /// To update security questions.
+ ///
+ /// model.
+ /// The .
+ [HttpPost]
+ public async Task UpdateMyAccountSecurityQuestions(MyAcountSecurityQuestionsViewModel model)
+ {
+ bool duplicatesExist = false;
+
+ if (model.SelectedFirstQuestionId == model.SelectedSecondQuestionId)
+ {
+ duplicatesExist = true;
+ }
+
+ if (duplicatesExist)
+ {
+ this.ModelState.AddModelError("DuplicateQuestion", CommonValidationErrorMessages.DuplicateQuestion);
+ return this.View("MyAccountSecurityQuestionsDetails", model);
+ }
+
+ if (this.ModelState.IsValid)
+ {
+ var userSecurityQuestions = new List
+ {
+ new UserSecurityQuestionViewModel
+ {
+ Id = model.UserSecurityFirstQuestionId,
+ SecurityQuestionId = model.SelectedFirstQuestionId,
+ SecurityQuestionAnswerHash = model.SecurityFirstQuestionAnswerHash,
+ UserId = this.CurrentUserId,
+ },
+ new UserSecurityQuestionViewModel
+ {
+ Id = model.UserSecuritySecondQuestionId,
+ SecurityQuestionId = model.SelectedSecondQuestionId,
+ SecurityQuestionAnswerHash = model.SecuritySecondQuestionAnswerHash,
+ UserId = this.CurrentUserId,
+ },
+ };
+
+ await this.userService.UpdateUserSecurityQuestions(userSecurityQuestions);
+
+ this.ViewBag.SuccessMessage = CommonValidationErrorMessages.FirstQuestionSuccessMessage;
+ return this.View("SuccessMessage");
+ }
+ else
+ {
+ return this.View("MyAccountSecurityQuestionsDetails", model);
+ }
}
///
@@ -678,25 +1003,36 @@ public async Task ChangeCurrentRole([FromQuery] UserJobRoleUpdate
return this.View("ChangeCurrentRole", viewModel);
}
- if (!string.IsNullOrWhiteSpace(viewModel.FilterText))
- {
- var jobRoles = await this.jobRoleService.GetPagedFilteredAsync(viewModel.FilterText, viewModel.CurrentPage, viewModel.PageSize);
- viewModel.RoleList = jobRoles.Item2;
- viewModel.TotalItems = jobRoles.Item1;
- viewModel.HasItems = jobRoles.Item1 > 0;
- }
-
if (formSubmission)
{
- if (viewModel.SelectedJobRoleId.HasValue)
+ var hasSelectedJobRoleId = int.TryParse(viewModel.SelectedJobRoleId, out int currentRole);
+ if (hasSelectedJobRoleId && currentRole > 0)
{
- var newRoleId = viewModel.SelectedJobRoleId.Value;
+ var newRoleId = currentRole;
var jobRole = await this.jobRoleService.GetByIdAsync(newRoleId);
if (jobRole.MedicalCouncilId > 0 && jobRole.MedicalCouncilId < 4)
{
return this.RedirectToAction(nameof(this.ChangeMedicalCouncilNo), new UserMedicalCouncilNoUpdateViewModel { SelectedJobRoleId = newRoleId });
}
+ else if (this.User.IsInRole("BasicUser"))
+ {
+ await this.userService.UpdateUserEmployment(
+ new elfhHub.Nhs.Models.Entities.UserEmployment
+ {
+ Id = profile.EmploymentId,
+ UserId = profile.Id,
+ JobRoleId = newRoleId,
+ GradeId = profile.GradeId,
+ SpecialtyId = profile.SpecialtyId,
+ StartDate = profile.JobStartDate,
+ LocationId = profile.LocationId,
+ });
+
+ this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmploymentDetailsUpdated;
+ this.ViewBag.MyAction = "MyEmploymentDetails";
+ return this.View("SuccessMessageMyAccount");
+ }
else
{
return this.RedirectToAction(nameof(this.ChangeGrade), new UserGradeUpdateViewModel { SelectedJobRoleId = newRoleId });
@@ -705,10 +1041,25 @@ public async Task ChangeCurrentRole([FromQuery] UserJobRoleUpdate
else
{
this.ModelState.AddModelError(nameof(viewModel.SelectedJobRoleId), CommonValidationErrorMessages.RoleRequired);
- return this.View("ChangeCurrentRole", viewModel);
+ }
+ }
+ else
+ {
+ if (string.IsNullOrEmpty(viewModel.FilterText))
+ {
+ viewModel.FilterText = profile.JobRole;
+ viewModel.SelectedJobRoleId = profile.JobRoleId.HasValue ? profile.JobRoleId.ToString() : string.Empty;
}
}
+ if (!string.IsNullOrWhiteSpace(viewModel.FilterText))
+ {
+ var jobRoles = await this.jobRoleService.GetPagedFilteredAsync(viewModel.FilterText, viewModel.CurrentPage, viewModel.PageSize);
+ viewModel.RoleList = jobRoles.Item2;
+ viewModel.TotalItems = jobRoles.Item1;
+ viewModel.HasItems = jobRoles.Item1 > 0;
+ }
+
return this.View("ChangeCurrentRole", viewModel);
}
@@ -750,24 +1101,25 @@ public async Task ChangeMedicalCouncilNo([FromQuery] UserMedicalC
this.ModelState.AddModelError(nameof(viewModel.SelectedMedicalCouncilNo), validateMedicalCouncilNumber);
return this.View("ChangeMedicalCouncilNumber", viewModel);
}
- else if (direct)
+ else if (this.User.IsInRole("BasicUser") || direct)
{
await this.userService.UpdateUserEmployment(
- new elfhHub.Nhs.Models.Entities.UserEmployment
- {
- Id = profile.EmploymentId,
- UserId = profile.Id,
- JobRoleId = profile.JobRoleId,
- MedicalCouncilId = viewModel.SelectedMedicalCouncilId,
- MedicalCouncilNo = viewModel.SelectedMedicalCouncilNo,
- GradeId = profile.GradeId,
- SpecialtyId = profile.SpecialtyId,
- StartDate = profile.JobStartDate,
- LocationId = profile.LocationId,
- });
-
- this.ViewBag.SuccessMessage = "Your medical council number has been changed";
- return this.View("SuccessMessage");
+ new elfhHub.Nhs.Models.Entities.UserEmployment
+ {
+ Id = profile.EmploymentId,
+ UserId = profile.Id,
+ JobRoleId = viewModel.SelectedJobRoleId,
+ MedicalCouncilId = viewModel.SelectedMedicalCouncilId,
+ MedicalCouncilNo = viewModel.SelectedMedicalCouncilNo,
+ GradeId = profile.GradeId,
+ SpecialtyId = profile.SpecialtyId,
+ StartDate = profile.JobStartDate,
+ LocationId = profile.LocationId,
+ });
+
+ this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmploymentDetailsUpdated;
+ this.ViewBag.MyAction = "MyEmploymentDetails";
+ return this.View("SuccessMessageMyAccount");
}
else
{
@@ -786,6 +1138,13 @@ await this.userService.UpdateUserEmployment(
return this.View("ChangeMedicalCouncilNumber", viewModel);
}
}
+ else
+ {
+ if (string.IsNullOrEmpty(viewModel.SelectedMedicalCouncilNo))
+ {
+ viewModel.SelectedMedicalCouncilNo = profile.MedicalCouncilNo;
+ }
+ }
return this.View("ChangeMedicalCouncilNumber", viewModel);
}
@@ -827,8 +1186,7 @@ await this.userService.UpdateUserEmployment(
LocationId = profile.LocationId,
});
- this.ViewBag.SuccessMessage = "Your job details have been changed";
- return this.View("SuccessMessage");
+ return this.RedirectToAction(nameof(this.ChangePrimarySpecialty), new UserPrimarySpecialtyUpdateViewModel { });
}
else
{
@@ -862,6 +1220,9 @@ public async Task ChangePrimarySpecialty([FromQuery] UserPrimaryS
viewModel.PageSize = UserDetailContentPageSize;
viewModel.CurrentPage = viewModel.CurrentPage == 0 ? 1 : viewModel.CurrentPage;
viewModel.OptionalSpecialtyItem = optionalSpecialty.FirstOrDefault(x => x.Name.ToLower() == "not applicable");
+ viewModel.SelectedGradeId = profile.GradeId?.ToString() ?? null;
+ viewModel.SelectedJobRoleId = profile.JobRoleId;
+ viewModel.SelectedMedicalCouncilNo = profile.MedicalCouncilNo;
if (searchSubmission && string.IsNullOrWhiteSpace(viewModel.FilterText))
{
@@ -871,8 +1232,10 @@ public async Task ChangePrimarySpecialty([FromQuery] UserPrimaryS
if (formSubmission)
{
- if (viewModel.SelectedPrimarySpecialtyId.HasValue)
+ var hasSelectedPrimarySpeciality = int.TryParse(viewModel.SelectedPrimarySpecialtyId, out int selectedPrimarySpecialtyId);
+ if (hasSelectedPrimarySpeciality && selectedPrimarySpecialtyId > 0)
{
+ var newPrimarySpecialtyId = selectedPrimarySpecialtyId;
await this.userService.UpdateUserEmployment(
new elfhHub.Nhs.Models.Entities.UserEmployment
{
@@ -882,18 +1245,24 @@ await this.userService.UpdateUserEmployment(
MedicalCouncilId = profile.MedicalCouncilId,
MedicalCouncilNo = profile.MedicalCouncilNo,
GradeId = profile.GradeId,
- SpecialtyId = viewModel.SelectedPrimarySpecialtyId.Value,
+ SpecialtyId = newPrimarySpecialtyId,
StartDate = profile.JobStartDate,
LocationId = profile.LocationId,
});
- this.ViewBag.SuccessMessage = "Your primary specialty has been changed";
- return this.View("SuccessMessage");
+ return this.RedirectToAction(nameof(this.ChangeStartDate), new UserStartDateUpdateViewModel { });
}
else
{
- this.ModelState.AddModelError(nameof(viewModel.SelectedPrimarySpecialtyId), CommonValidationErrorMessages.SpecialtyNotApplicable);
- return this.View("ChangePrimarySpecialty", viewModel);
+ this.ModelState.AddModelError(nameof(viewModel.SelectedPrimarySpecialtyId), CommonValidationErrorMessages.SpecialtyRequired);
+ }
+ }
+ else
+ {
+ if (string.IsNullOrWhiteSpace(viewModel.FilterText))
+ {
+ viewModel.FilterText = profile.PrimarySpecialty;
+ viewModel.SelectedPrimarySpecialtyId = profile.SpecialtyId.HasValue ? profile.SpecialtyId.ToString() : string.Empty;
}
}
@@ -940,8 +1309,7 @@ await this.userService.UpdateUserEmployment(
LocationId = profile.LocationId,
});
- this.ViewBag.SuccessMessage = "Your job start date has been changed";
- return this.View("SuccessMessage");
+ return this.RedirectToAction(nameof(this.ChangeWorkPlace), new UserWorkPlaceUpdateViewModel { });
}
}
else
@@ -949,6 +1317,10 @@ await this.userService.UpdateUserEmployment(
this.ModelState.Remove("Day");
this.ModelState.Remove("Month");
this.ModelState.Remove("Year");
+
+ viewModel.Day = profile.JobStartDate.HasValue ? profile.JobStartDate.Value.Day : null;
+ viewModel.Month = profile.JobStartDate.HasValue ? profile.JobStartDate.GetValueOrDefault().Month : null;
+ viewModel.Year = profile.JobStartDate.HasValue ? profile.JobStartDate.Value.Year : null;
}
return this.View("ChangeStartDate", viewModel);
@@ -977,45 +1349,6 @@ public async Task ChangeWorkPlace([FromQuery] UserWorkPlaceUpdate
return this.View("ChangeWorkPlace", viewModel);
}
- if (formSubmission && viewModel.SelectedWorkPlaceId.HasValue)
- {
- await this.userService.UpdateUserEmployment(
- new elfhHub.Nhs.Models.Entities.UserEmployment
- {
- Id = profile.EmploymentId,
- UserId = profile.Id,
- JobRoleId = profile.JobRoleId,
- MedicalCouncilId = profile.MedicalCouncilId,
- MedicalCouncilNo = profile.MedicalCouncilNo,
- GradeId = profile.GradeId,
- SpecialtyId = profile.SpecialtyId,
- StartDate = profile.JobStartDate,
- LocationId = viewModel.SelectedWorkPlaceId.Value,
- });
-
- var (cacheExists, loginWizard) = await this.cacheService.TryGetAsync(this.LoginWizardCacheKey);
-
- if (cacheExists && loginWizard.LoginWizardStagesRemaining.Any(l => l.Id == (int)LoginWizardStageEnum.PlaceOfWork))
- {
- await this.loginWizardService.SaveLoginWizardStageActivity(LoginWizardStageEnum.PlaceOfWork, this.CurrentUserId);
-
- var stagePlaceOfWork = loginWizard.LoginWizardStages.FirstOrDefault(s => s.Id == (int)LoginWizardStageEnum.PlaceOfWork);
- loginWizard.LoginWizardStagesCompleted.Add(stagePlaceOfWork);
-
- var loginWizardViewModel = new LoginWizardStagesViewModel
- {
- IsFirstLogin = loginWizard.IsFirstLogin,
- LoginWizardStages = loginWizard.LoginWizardStages,
- LoginWizardStagesCompleted = loginWizard.LoginWizardStagesCompleted,
- };
-
- await this.cacheService.SetAsync(this.LoginWizardCacheKey, Newtonsoft.Json.JsonConvert.SerializeObject(loginWizardViewModel));
- }
-
- this.ViewBag.SuccessMessage = "Your place of work has been changed";
- return this.View("SuccessMessage");
- }
-
if (!string.IsNullOrWhiteSpace(viewModel.FilterText))
{
var locations = await this.locationService.GetPagedFilteredAsync(viewModel.FilterText, viewModel.CurrentPage, viewModel.PageSize);
@@ -1024,6 +1357,54 @@ await this.userService.UpdateUserEmployment(
viewModel.HasItems = locations.Item1 > 0;
}
+ if (formSubmission)
+ {
+ if (viewModel.SelectedWorkPlaceId.HasValue)
+ {
+ await this.userService.UpdateUserEmployment(
+ new elfhHub.Nhs.Models.Entities.UserEmployment
+ {
+ Id = profile.EmploymentId,
+ UserId = profile.Id,
+ JobRoleId = profile.JobRoleId,
+ MedicalCouncilId = profile.MedicalCouncilId,
+ MedicalCouncilNo = profile.MedicalCouncilNo,
+ GradeId = profile.GradeId,
+ SpecialtyId = profile.SpecialtyId,
+ StartDate = profile.JobStartDate,
+ LocationId = viewModel.SelectedWorkPlaceId.Value,
+ });
+
+ var (cacheExists, loginWizard) = await this.cacheService.TryGetAsync(this.LoginWizardCacheKey);
+
+ if (cacheExists && loginWizard.LoginWizardStagesRemaining.Any(l => l.Id == (int)LoginWizardStageEnum.PlaceOfWork))
+ {
+ await this.loginWizardService.SaveLoginWizardStageActivity(LoginWizardStageEnum.PlaceOfWork, this.CurrentUserId);
+
+ var stagePlaceOfWork = loginWizard.LoginWizardStages.FirstOrDefault(s => s.Id == (int)LoginWizardStageEnum.PlaceOfWork);
+ loginWizard.LoginWizardStagesCompleted.Add(stagePlaceOfWork);
+
+ var loginWizardViewModel = new LoginWizardStagesViewModel
+ {
+ IsFirstLogin = loginWizard.IsFirstLogin,
+ LoginWizardStages = loginWizard.LoginWizardStages,
+ LoginWizardStagesCompleted = loginWizard.LoginWizardStagesCompleted,
+ };
+
+ await this.cacheService.SetAsync(this.LoginWizardCacheKey, Newtonsoft.Json.JsonConvert.SerializeObject(loginWizardViewModel));
+ }
+
+ this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmploymentDetailsUpdated;
+ this.ViewBag.MyAction = "MyEmploymentDetails";
+ return this.View("SuccessMessageMyAccount");
+ }
+ else
+ {
+ this.ModelState.AddModelError(nameof(viewModel.SelectedWorkPlaceId), CommonValidationErrorMessages.WorkPlace);
+ return this.View("ChangeWorkPlace", viewModel);
+ }
+ }
+
return this.View("ChangeWorkPlace", viewModel);
}
@@ -1197,5 +1578,27 @@ public async Task CancelEmailChangeValidationToken()
this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmailCancelMessage;
return this.View("SuccessMessage");
}
+
+ private async Task MyAccountUpdatePrimaryEmail(string currentEmailAddress, string primaryEmailAddress)
+ {
+ var isUserRoleUpgrade = await this.userService.ValidateUserRoleUpgradeAsync(currentEmailAddress, primaryEmailAddress);
+ UserRoleUpgrade userRoleUpgradeModel = new UserRoleUpgrade()
+ {
+ UserId = this.CurrentUserId,
+ EmailAddress = primaryEmailAddress,
+ };
+ if (isUserRoleUpgrade)
+ {
+ userRoleUpgradeModel.UserHistoryTypeId = (int)UserHistoryType.UserRoleUpgarde;
+ }
+ else
+ {
+ userRoleUpgradeModel.UserHistoryTypeId = (int)UserHistoryType.UserDetails;
+ }
+
+ await this.userService.GenerateEmailChangeValidationTokenAndSendEmailAsync(primaryEmailAddress, isUserRoleUpgrade);
+ await this.userService.UpdateUserRoleUpgradeAsync();
+ await this.userService.CreateUserRoleUpgradeAsync(userRoleUpgradeModel);
+ }
}
}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs b/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs
index a791bd5d1..1157fcbec 100644
--- a/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs
@@ -31,7 +31,7 @@
[ServiceFilter(typeof(LoginWizardFilter))]
public class MyLearningController : BaseController
{
- private const int MyLearningPageSize = 10;
+ private const int MyLearningPageSize = 5;
private readonly IMyLearningService myLearningService;
private readonly IResourceService resourceService;
private readonly IHierarchyService hierarchyService;
@@ -104,7 +104,7 @@ public static string RenderRazorViewToString(Controller controller, string viewN
[Route("MyLearning/activity")]
[HttpGet]
[HttpPost]
- public async Task Index(MyLearningViewModel learningRequest = null, string myLearningDashboard = null)
+ public async Task Index(MyLearningUserActivitiesViewModel learningRequest = null, string myLearningDashboard = null)
{
var myLearningRequestModel = new MyLearningRequestModel
{
@@ -216,8 +216,6 @@ public async Task Index(MyLearningViewModel learningRequest = nul
}
myLearningRequestModel.TimePeriod = learningRequest.TimePeriod;
- myLearningRequestModel.StartDate = learningRequest.GetStartDate().HasValue ? learningRequest.GetStartDate().Value : null;
- myLearningRequestModel.EndDate = learningRequest.GetEndDate().HasValue ? learningRequest.GetEndDate().Value : null;
}
break;
@@ -234,33 +232,165 @@ public async Task Index(MyLearningViewModel learningRequest = nul
break;
}
- var result = await this.myLearningService.GetActivityDetailed(myLearningRequestModel);
- var response = new MyLearningViewModel(myLearningRequestModel);
- if (learningRequest.TimePeriod == "dateRange")
- {
- response.StartDay = learningRequest.StartDay;
- response.StartMonth = learningRequest.StartMonth;
- response.StartYear = learningRequest.StartYear;
- response.EndDay = learningRequest.EndDay;
- response.EndMonth = learningRequest.EndMonth;
- response.EndYear = learningRequest.EndYear;
- }
+ var result = await this.myLearningService.GetUserRecentMyLearningActivities(myLearningRequestModel);
+ var response = new MyLearningUserActivitiesViewModel(myLearningRequestModel);
if (result != null)
{
response.TotalCount = result.TotalCount;
- response.Activities = result.Activities.Select(entry => new ActivityDetailedItemViewModel(entry)).ToList();
- if (response.Activities.Any())
+ response.Activities = result.Activities;
+ }
+
+ response.MyLearningPaging = new MyLearningPagingModel() { CurrentPage = learningRequest.CurrentPageIndex, PageSize = MyLearningPageSize, TotalItems = response.TotalCount, HasItems = response.TotalCount > 0 };
+ this.ViewBag.MyLearningHelpUrl = this.Settings.SupportUrls.MyLearningHelpUrl;
+ return this.View(response);
+ }
+
+ ///
+ /// Index.
+ ///
+ /// learningRequest.
+ /// The my learning dashboard type.
+ /// IActionResult.
+ [Route("MyLearning/LearningHistory")]
+ [HttpGet]
+ [HttpPost]
+ public async Task LearningHistory(MyLearningUserActivitiesViewModel learningRequest = null, string myLearningDashboard = null)
+ {
+ var myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = learningRequest.SearchText?.Trim(),
+ Skip = learningRequest.CurrentPageIndex * MyLearningPageSize,
+ Take = MyLearningPageSize,
+ TimePeriod = !string.IsNullOrWhiteSpace(learningRequest.TimePeriod) ? learningRequest.TimePeriod : "allDates",
+ StartDate = learningRequest.StartDate,
+ EndDate = learningRequest.EndDate,
+ Weblink = learningRequest.Weblink,
+ File = learningRequest.File,
+ Video = learningRequest.Video,
+ Article = learningRequest.Article,
+ Case = learningRequest.Case,
+ Image = learningRequest.Image,
+ Audio = learningRequest.Audio,
+ Elearning = learningRequest.Elearning,
+ Html = learningRequest.Html,
+ Assessment = learningRequest.Assessment,
+ Complete = learningRequest.Complete,
+ Incomplete = learningRequest.Incomplete,
+ Passed = learningRequest.Passed,
+ Failed = learningRequest.Failed,
+ Downloaded = learningRequest.Downloaded,
+ Viewed = learningRequest.Viewed,
+ Launched = learningRequest.Launched,
+ CertificateEnabled = learningRequest.CertificateEnabled,
+ Courses = learningRequest.Courses,
+ };
+
+ if (myLearningDashboard != null)
+ {
+ if (myLearningDashboard == "my-in-progress")
{
- foreach (var activity in response.Activities)
+ myLearningRequestModel.Incomplete = true;
+ myLearningRequestModel.Failed = true;
+ }
+ else if (myLearningDashboard == "my-recent-completed")
+ {
+ myLearningRequestModel.Complete = true;
+ myLearningRequestModel.Passed = true;
+ myLearningRequestModel.Downloaded = true;
+ }
+ else if (myLearningDashboard == "my-certificates")
+ {
+ myLearningRequestModel.CertificateEnabled = true;
+ myLearningRequestModel.Complete = true;
+ myLearningRequestModel.Passed = true;
+ myLearningRequestModel.Downloaded = true;
+ }
+ }
+
+ switch (learningRequest.MyLearningFormActionType)
+ {
+ case MyLearningFormActionTypeEnum.NextPageChange:
+ learningRequest.CurrentPageIndex += 1;
+ myLearningRequestModel.Skip = learningRequest.CurrentPageIndex * MyLearningPageSize;
+ break;
+
+ case MyLearningFormActionTypeEnum.PreviousPageChange:
+ learningRequest.CurrentPageIndex -= 1;
+ myLearningRequestModel.Skip = learningRequest.CurrentPageIndex * MyLearningPageSize;
+ break;
+ case MyLearningFormActionTypeEnum.BasicSearch:
+
+ myLearningRequestModel = new MyLearningRequestModel
{
- if (!response.MostRecentResources.Contains(activity.ResourceId))
+ SearchText = learningRequest.SearchText?.Trim(),
+ TimePeriod = !string.IsNullOrWhiteSpace(learningRequest.TimePeriod) ? learningRequest.TimePeriod : "allDates",
+ Skip = learningRequest.CurrentPageIndex * MyLearningPageSize,
+ Take = MyLearningPageSize,
+ };
+ break;
+
+ case MyLearningFormActionTypeEnum.ApplyWeekFilter:
+ myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = learningRequest.SearchText?.Trim(),
+ TimePeriod = "thisWeek",
+ Skip = learningRequest.CurrentPageIndex * MyLearningPageSize,
+ Take = MyLearningPageSize,
+ };
+ break;
+ case MyLearningFormActionTypeEnum.ApplyMonthFilter:
+ myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = learningRequest.SearchText?.Trim(),
+ TimePeriod = "thisMonth",
+ Skip = learningRequest.CurrentPageIndex * MyLearningPageSize,
+ Take = MyLearningPageSize,
+ };
+ break;
+
+ case MyLearningFormActionTypeEnum.ApplyTwelveMonthFilter:
+ myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = learningRequest.SearchText?.Trim(),
+ TimePeriod = "last12Months",
+ Skip = learningRequest.CurrentPageIndex * MyLearningPageSize,
+ Take = MyLearningPageSize,
+ };
+ break;
+
+ case MyLearningFormActionTypeEnum.ApplyMajorFilters:
+ if (learningRequest.TimePeriod == "dateRange")
+ {
+ if (!this.ModelState.IsValid)
{
- activity.IsMostRecent = true;
- response.MostRecentResources.Add(activity.ResourceId);
+ break;
}
+
+ myLearningRequestModel.TimePeriod = learningRequest.TimePeriod;
}
- }
+
+ break;
+
+ case MyLearningFormActionTypeEnum.ClearAllFilters:
+
+ myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = learningRequest.SearchText?.Trim(),
+ Skip = learningRequest.CurrentPageIndex * MyLearningPageSize,
+ TimePeriod = "allDates",
+ Take = MyLearningPageSize,
+ };
+ break;
+ }
+
+ var result = await this.myLearningService.GetUserLearningHistory(myLearningRequestModel);
+ var response = new MyLearningUserActivitiesViewModel(myLearningRequestModel);
+
+ if (result != null)
+ {
+ response.TotalCount = result.TotalCount;
+ response.Activities = result.Activities;
}
response.MyLearningPaging = new MyLearningPagingModel() { CurrentPage = learningRequest.CurrentPageIndex, PageSize = MyLearningPageSize, TotalItems = response.TotalCount, HasItems = response.TotalCount > 0 };
@@ -323,6 +453,50 @@ public async Task ExportToPDF(MyLearningRequestModel myLearningRe
return this.View(new Tuple(userDetails, response));
}
+ ///
+ /// Function to export activity report to pdf.
+ ///
+ /// myLearningRequestModel.
+ /// A representing the result of the asynchronous operation.
+ [Route("/MyLearning/DownloadActivities")]
+ [HttpPost]
+ public async Task DownloadActivities(MyLearningRequestModel myLearningRequestModel)
+ {
+ var filter = myLearningRequestModel;
+ filter.Skip = 0;
+ filter.Take = 999;
+ var userDetails = await this.userService.GetCurrentUserBasicDetailsAsync();
+ var response = new MyLearningUserActivitiesViewModel();
+ var result = await this.myLearningService.GetUserLearningHistory(filter);
+ if (result != null)
+ {
+ response.TotalCount = result.TotalCount;
+ response.Activities = result.Activities;
+ }
+
+ Tuple modelData = Tuple.Create(userDetails, response);
+ var renderedViewHTML = RenderRazorViewToString(this, "DownloadActivityRecords", modelData);
+ ReportStatusModel reportStatusModel = new ReportStatusModel();
+ var pdfReportResponse = await this.pdfReportService.PdfReport(renderedViewHTML, userDetails.Id);
+ if (pdfReportResponse != null)
+ {
+ do
+ {
+ reportStatusModel = await this.pdfReportService.PdfReportStatus(pdfReportResponse);
+ }
+ while (reportStatusModel.Id == 1);
+
+ var pdfReportFile = await this.pdfReportService.GetPdfReportFile(pdfReportResponse);
+ if (pdfReportFile != null)
+ {
+ var fileName = "ActivityReport.pdf";
+ return this.File(pdfReportFile, FileHelper.GetContentTypeFromFileName(fileName), fileName);
+ }
+ }
+
+ return this.View(new Tuple(userDetails, response));
+ }
+
///
/// Gets the played segment data for the progress modal in My Learning screen.
///
@@ -387,6 +561,78 @@ public async Task ViewProgress(int resourceId, int resourceRefere
return this.View(vm);
}
+ ///
+ /// Get user certificates.
+ ///
+ /// The certificateRequest.
+ /// A representing the result of the asynchronous operation.
+ [Route("mylearning/certificates")]
+ [HttpGet]
+ [HttpPost]
+ public async Task Certificates(MyLearningUserCertificatesViewModel certificateRequest = null)
+ {
+ int certificatePageSize = 6;
+ var myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = certificateRequest.SearchText?.Trim(),
+ Skip = certificateRequest.CurrentPageIndex * certificatePageSize,
+ Take = certificatePageSize,
+ File = certificateRequest.File,
+ Video = certificateRequest.Video,
+ Article = certificateRequest.Article,
+ Case = certificateRequest.Case,
+ Image = certificateRequest.Image,
+ Audio = certificateRequest.Audio,
+ Elearning = certificateRequest.Elearning,
+ Html = certificateRequest.Html,
+ Assessment = certificateRequest.Assessment,
+ Courses = certificateRequest.Courses,
+ };
+
+ switch (certificateRequest.MyLearningFormActionType)
+ {
+ case MyLearningFormActionTypeEnum.NextPageChange:
+ certificateRequest.CurrentPageIndex += 1;
+ myLearningRequestModel.Skip = certificateRequest.CurrentPageIndex * certificatePageSize;
+ break;
+
+ case MyLearningFormActionTypeEnum.PreviousPageChange:
+ certificateRequest.CurrentPageIndex -= 1;
+ myLearningRequestModel.Skip = certificateRequest.CurrentPageIndex * certificatePageSize;
+ break;
+ case MyLearningFormActionTypeEnum.BasicSearch:
+
+ myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = certificateRequest.SearchText?.Trim(),
+ Skip = certificateRequest.CurrentPageIndex * certificatePageSize,
+ Take = certificatePageSize,
+ };
+ break;
+ case MyLearningFormActionTypeEnum.ClearAllFilters:
+
+ myLearningRequestModel = new MyLearningRequestModel
+ {
+ SearchText = certificateRequest.SearchText?.Trim(),
+ Skip = certificateRequest.CurrentPageIndex * certificatePageSize,
+ Take = certificatePageSize,
+ };
+ break;
+ }
+
+ var result = await this.myLearningService.GetUserCertificateDetails(myLearningRequestModel);
+ var response = new MyLearningUserCertificatesViewModel(myLearningRequestModel);
+
+ if (result != null)
+ {
+ response.TotalCount = result.TotalCount;
+ response.UserCertificates = result.Certificates;
+ }
+
+ response.MyLearningPaging = new MyLearningPagingModel() { CurrentPage = certificateRequest.CurrentPageIndex, PageSize = MyLearningPageSize, TotalItems = response.TotalCount, HasItems = response.TotalCount > 0 };
+ return this.View(response);
+ }
+
///
/// Gets the certificate details of an activity.
///
@@ -435,6 +681,7 @@ public async Task GetCertificateDetails(int resourceReferenceId,
/// The minorVersion.
/// The userId.
/// The .
+ [HttpGet]
[HttpPost]
[Route("mylearning/downloadcertificate")]
public async Task DownloadCertificate(int resourceReferenceId, int? majorVersion = 0, int? minorVersion = 0, int? userId = 0)
diff --git a/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs b/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs
index c9b3aa7bc..e41b794f1 100644
--- a/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs
+++ b/LearningHub.Nhs.WebUI/Helpers/CommonValidationErrorMessages.cs
@@ -229,5 +229,35 @@ public static class CommonValidationErrorMessages
/// Message if the validation token expired.
///
public const string EmailChangeValidationTokenInvalidMessage = "We cannot find the page you are looking for";
+
+ ///
+ /// Message if the validation token expired.
+ ///
+ public const string InvalidSecurityQuestionAnswer = "Enter an answer";
+
+ ///
+ /// Message if the validation token expired.
+ ///
+ public const string EmploymentDetailsUpdated = "Your employment details has been changed";
+
+ ///
+ /// security question Success Message.
+ ///
+ public const string SecurityQuestionSuccessMessage = "Your security questions has been changed";
+
+ ///
+ /// location Success Message.
+ ///
+ public const string LocationDetailsSuccessMessage = "Your location details has been changed";
+
+ ///
+ /// location Success Message.
+ ///
+ public const string PersonalDetailsSuccessMessage = "Your personal details has been changed";
+
+ ///
+ /// Security question Required.
+ ///
+ public const string SecurityQuestionRequired = "Please select a security question";
}
}
diff --git a/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs b/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs
deleted file mode 100644
index e0601d156..000000000
--- a/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-namespace LearningHub.Nhs.WebUI.Helpers;
-
-///
-/// Represents the types of resources available in Moodle.
-///
-public enum ResourceTypeEnumMoodle
-{
- ///
- /// The undefined resource type.
- ///
- Undefined,
-
- ///
- /// The article resource type.
- ///
- Article,
-
- ///
- /// The audio resource type.
- ///
- Audio,
-
- ///
- /// The embedded resource type.
- ///
- Embedded,
-
- ///
- /// The equipment resource type.
- ///
- Equipment,
-
- ///
- /// The image resource type.
- ///
- Image,
-
- ///
- /// The SCORM resource type.
- ///
- Scorm,
-
- ///
- /// The video resource type.
- ///
- Video,
-
- ///
- /// The web link resource type.
- ///
- WebLink,
-
- ///
- /// The generic file resource type.
- ///
- GenericFile,
-
- ///
- /// The clinical case resource type.
- ///
- Case,
-
- ///
- /// The assessment resource type.
- ///
- Assessment,
-
- ///
- /// The HTML resource type.
- ///
- Html,
-
- ///
- /// The Moodle resource type.
- ///
- Moodle,
-
- ///
- /// The Moodle course resource type.
- ///
- Course,
-}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs b/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs
new file mode 100644
index 000000000..1dcd3f53e
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Helpers/SelectListHelper.cs
@@ -0,0 +1,35 @@
+namespace LearningHub.Nhs.WebUI.Helpers
+{
+ using System.Collections.Generic;
+ using System.Linq;
+ using elfhHub.Nhs.Models.Common;
+ using Microsoft.AspNetCore.Mvc.Rendering;
+
+ ///
+ /// SelectListHelper.
+ ///
+ public static class SelectListHelper
+ {
+ ///
+ /// MapOptionsToSelectListItems.
+ ///
+ /// options.
+ /// selectedId.
+ /// SelectListItem.
+ public static IEnumerable MapOptionsToSelectListItems(IEnumerable options, int? selectedId = null)
+ {
+ return options.Select(o => new SelectListItem(o.Name, o.Id.ToString(), o.Id == selectedId)).ToList();
+ }
+
+ ///
+ /// MapSelectListWithSelection.
+ ///
+ /// options.
+ /// selectedId.
+ /// SelectListItem.
+ public static IEnumerable MapSelectListWithSelection(IEnumerable options, string selectedId = null)
+ {
+ return options.Select(o => new SelectListItem(o.Text, o.Value, o.Value == selectedId)).ToList();
+ }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs
index ef71191f9..e1732d5a3 100644
--- a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs
+++ b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs
@@ -30,25 +30,7 @@ public static class UtilityHelper
{ "genericfile", ResourceTypeEnum.GenericFile },
{ "image", ResourceTypeEnum.Image },
{ "html", ResourceTypeEnum.Html },
- };
-
- /// TODO: Remove this method after adding to Moodle resource types to models project.
- ///
- /// Findwise Moodle resource type dictionary.
- ///
- public static readonly Dictionary FindwiseResourceMoodleTypeDict = new Dictionary()
- {
- { "video", ResourceTypeEnumMoodle.Video },
- { "article", ResourceTypeEnumMoodle.Article },
- { "case", ResourceTypeEnumMoodle.Case },
- { "weblink", ResourceTypeEnumMoodle.WebLink },
- { "audio", ResourceTypeEnumMoodle.Audio },
- { "scorm", ResourceTypeEnumMoodle.Scorm },
- { "assessment", ResourceTypeEnumMoodle.Assessment },
- { "genericfile", ResourceTypeEnumMoodle.GenericFile },
- { "image", ResourceTypeEnumMoodle.Image },
- { "html", ResourceTypeEnumMoodle.Html },
- { "moodle", ResourceTypeEnumMoodle.Course },
+ { "moodle", ResourceTypeEnum.Moodle },
};
///
@@ -166,54 +148,6 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType
}
}
- /// TODO: Remove this method after adding to Moodle resource types to models project.
- ///
- /// Returns a prettified resource type name, suitable for display in the UI. Includes video/audio duration string.
- ///
- /// The resource type.
- /// The media duration in milliseconds.
- /// The resource type name, and duration if applicable.
- public static string GetPrettifiedResourceTypeNameMoodle(ResourceTypeEnumMoodle resourceType, int? durationInMilliseconds = 0)
- {
- switch (resourceType)
- {
- case ResourceTypeEnumMoodle.Assessment:
- return "Assessment";
- case ResourceTypeEnumMoodle.Article:
- return "Article";
- case ResourceTypeEnumMoodle.Audio:
- string durationText = GetDurationText(durationInMilliseconds ?? 0);
- durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText;
- return "Audio" + durationText;
- case ResourceTypeEnumMoodle.Equipment:
- return "Equipment";
- case ResourceTypeEnumMoodle.Image:
- return "Image";
- case ResourceTypeEnumMoodle.Scorm:
- return "elearning";
- case ResourceTypeEnumMoodle.Video:
- durationText = GetDurationText(durationInMilliseconds ?? 0);
- durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText;
- return "Video" + durationText;
- case ResourceTypeEnumMoodle.WebLink:
- return "Web link";
- case ResourceTypeEnumMoodle.GenericFile:
- return "File";
- case ResourceTypeEnumMoodle.Embedded:
- return "Embedded";
- case ResourceTypeEnumMoodle.Case:
- return "Case";
- case ResourceTypeEnumMoodle.Html:
- return "HTML";
- case ResourceTypeEnumMoodle.Moodle:
- return "Course";
- case ResourceTypeEnumMoodle.Course:
- return "Course";
- default:
- return "File";
- }
- }
-
///
/// Returns a prettified resource type name, suitable for display in the UI. Excludes video/audio duration string.
///
@@ -247,6 +181,8 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType
return "Case";
case ResourceTypeEnum.Html:
return "HTML";
+ case ResourceTypeEnum.Moodle:
+ return "Course";
default:
return "File";
}
diff --git a/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs
index f3bd9259c..44af540da 100644
--- a/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs
+++ b/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Linq;
using LearningHub.Nhs.Models.Enums;
+ using LearningHub.Nhs.Models.MyLearning;
using LearningHub.Nhs.WebUI.Models;
///
@@ -71,6 +72,102 @@ public static string GetResourceTypeText(this ActivityDetailedItemViewModel acti
return typeText;
}
+ ///
+ /// Get resource type details.
+ ///
+ /// resourceType.
+ /// The string.
+ public static string GetResourceTypeDesc(ResourceTypeEnum resourceType)
+ {
+ string typeText = string.Empty;
+ switch (resourceType)
+ {
+ case ResourceTypeEnum.Assessment:
+ typeText = "Assessment";
+ break;
+ case ResourceTypeEnum.Article:
+ typeText = "Article";
+ break;
+ case ResourceTypeEnum.Audio:
+ typeText = "Audio";
+ break;
+ case ResourceTypeEnum.GenericFile:
+ typeText = "File";
+ break;
+ case ResourceTypeEnum.Image:
+ typeText = "Image";
+ break;
+ case ResourceTypeEnum.Scorm:
+ typeText = "elearning";
+ break;
+ case ResourceTypeEnum.Video:
+ typeText = "Video";
+ break;
+ case ResourceTypeEnum.WebLink:
+ typeText = "Web link";
+ break;
+ case ResourceTypeEnum.Case:
+ typeText = "Case";
+ break;
+ case ResourceTypeEnum.Html:
+ typeText = "HTML";
+ break;
+ case ResourceTypeEnum.Moodle:
+ typeText = "Course";
+ break;
+ default:
+ typeText = string.Empty;
+ break;
+ }
+
+ return typeText;
+ }
+
+ ///
+ /// GetActivityStatusDisplayText.
+ ///
+ /// The activity.
+ /// The string.
+ public static string GetActivityStatusDisplayText(MyLearningCombinedActivitiesViewModel activity)
+ {
+ if (activity.ActivityStatus == ActivityStatusEnum.Completed || activity.ActivityStatus == ActivityStatusEnum.Passed || activity.ActivityStatus == ActivityStatusEnum.Passed || activity.ActivityStatus == ActivityStatusEnum.Viewed || activity.ActivityStatus == ActivityStatusEnum.Downloaded)
+ {
+ return "Completed";
+ }
+ else
+ {
+ return "InProgress";
+ }
+ }
+
+ ///
+ /// CanDownloadCertificate.
+ ///
+ /// The activityDetailedItemViewModel.
+ /// The bool.
+ public static bool CanCertificateawarded(this MyLearningCombinedActivitiesViewModel activitiesViewModel)
+ {
+ if (activitiesViewModel.CertificateEnabled == true)
+ {
+ if (activitiesViewModel.ResourceType == ResourceTypeEnum.Scorm)
+ {
+ if (GetActivityStatusDisplayText(activitiesViewModel) == "Completed" || GetActivityStatusDisplayText(activitiesViewModel) == "Passed")
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (GetActivityStatusDisplayText(activitiesViewModel) == "Completed" || GetActivityStatusDisplayText(activitiesViewModel) == "Passed" || GetActivityStatusDisplayText(activitiesViewModel) == "Downloaded")
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
///
/// GetResourceTypeVerb.
///
@@ -340,6 +437,7 @@ public static Dictionary GetActivityParameters(object model)
var routeData = model.GetType().GetProperties().ToDictionary(p => p.Name, p => p.GetValue(model)?.ToString());
routeData.Remove("MostRecentResources");
routeData.Remove("Activities");
+ routeData.Remove("UserCertificates");
routeData.Remove("TotalCount");
routeData.Remove("MyLearningPaging");
routeData.Remove("Skip");
diff --git a/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs b/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs
index 8b5fe7542..916159fe7 100644
--- a/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs
+++ b/LearningHub.Nhs.WebUI/Interfaces/ICountryService.cs
@@ -29,5 +29,17 @@ public interface ICountryService
///
/// A representing the result of the asynchronous operation.
Task> GetAllAsync();
+
+ ///
+ /// The GetAllUKCountries.
+ ///
+ /// A representing the result of the asynchronous operation.
+ Task> GetAllUKCountries();
+
+ ///
+ /// The GetAllNonUKCountries.
+ ///
+ /// A representing the result of the asynchronous operation.
+ Task> GetAllNonUKCountries();
}
}
diff --git a/LearningHub.Nhs.WebUI/Interfaces/IDashboardService.cs b/LearningHub.Nhs.WebUI/Interfaces/IDashboardService.cs
index 9eb8c3266..811dd1133 100644
--- a/LearningHub.Nhs.WebUI/Interfaces/IDashboardService.cs
+++ b/LearningHub.Nhs.WebUI/Interfaces/IDashboardService.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using LearningHub.Nhs.Models.Dashboard;
+ using LearningHub.Nhs.Models.Moodle.API;
using LearningHub.Nhs.WebUI.Models;
///
@@ -18,6 +19,15 @@ public interface IDashboardService
/// A representing the result of the asynchronous operation.
Task GetMyAccessLearningsAsync(string dashboardType, int pageNumber);
+ ///
+ /// GetResourcesAsync.
+ ///
+ /// The dashboardTrayLearningResource type.
+ /// The dashboard type.
+ /// The page Number.
+ /// A representing the result of the asynchronous operation.
+ Task GetMyCoursesAndElearning(string dashboardTrayLearningResourceType, string dashboardType, int pageNumber);
+
///
/// GetCataloguesAsync.
///
@@ -47,6 +57,13 @@ public interface IDashboardService
/// The current User Id type.
/// The page Number.
/// A representing the result of the asynchronous operation.
- Task> GetEnrolledCoursesFromMoodleAsync(int currentUserId, int pageNumber);
+ Task> GetEnrolledCoursesFromMoodleAsync(int currentUserId, int pageNumber);
+
+ ///
+ /// GetEnrolledCoursesFromMoodleAsync.
+ ///
+ /// The current User Id type.
+ /// A representing the result of the asynchronous operation.
+ Task GetMoodleUserIdAsync(int currentUserId);
}
}
diff --git a/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs b/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs
index d92c01fad..5796c3482 100644
--- a/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs
+++ b/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs
@@ -2,29 +2,34 @@
{
using System.Collections.Generic;
using System.Threading.Tasks;
- using LearningHub.Nhs.Models.Dashboard;
- using LearningHub.Nhs.WebUI.Models;
+ using LearningHub.Nhs.Models.Moodle.API;
+ using MoodleCourseCompletionModel = LearningHub.Nhs.Models.Moodle.API.MoodleCourseCompletionModel;
///
/// IMoodleApiService.
///
public interface IMoodleApiService
{
+ ///
+ /// GetMoodleUserIdByUsernameAsync.
+ ///
+ /// The current LH User Id.
+ /// A representing the result of the asynchronous operation.
+ Task GetMoodleUserIdByUsernameAsync(int currentUserId);
+
///
/// GetEnrolledCoursesAsync.
///
/// Moodle user id.
/// pageNumber.
- /// List of MoodleCourseResponseViewModel.
- Task> GetEnrolledCoursesAsync(int currentUserId, int pageNumber);
+ /// List of MoodleCourseResponseModel.
+ Task> GetEnrolledCoursesAsync(int currentUserId, int pageNumber);
///
- /// GetEnrolledCoursesAsync.
+ /// GetCourseUrl.
///
- /// Moodle user id.
- /// Moodle course id.
- /// pageNumber.
- /// List of MoodleCourseResponseViewModel.
- Task GetCourseCompletionAsync(int userId, int courseId, int pageNumber);
+ /// course Id.
+ /// return course URL.
+ string GetCourseUrl(int courseId);
}
}
diff --git a/LearningHub.Nhs.WebUI/Interfaces/IMyLearningService.cs b/LearningHub.Nhs.WebUI/Interfaces/IMyLearningService.cs
index 726f78477..e9b584cc4 100644
--- a/LearningHub.Nhs.WebUI/Interfaces/IMyLearningService.cs
+++ b/LearningHub.Nhs.WebUI/Interfaces/IMyLearningService.cs
@@ -17,6 +17,20 @@ public interface IMyLearningService
/// The .
Task GetActivityDetailed(MyLearningRequestModel requestModel);
+ ///
+ /// Gets the user recent my leraning activities..
+ ///
+ /// The request model.
+ /// The .
+ Task GetUserRecentMyLearningActivities(MyLearningRequestModel requestModel);
+
+ ///
+ /// Gets the user leraning history.
+ ///
+ /// The request model.
+ /// The .
+ Task GetUserLearningHistory(MyLearningRequestModel requestModel);
+
///
/// Gets the played segment data for the progress modal in My Learning screen.
///
@@ -34,5 +48,19 @@ public interface IMyLearningService
/// The userId.
/// The .
Task> GetResourceCertificateDetails(int resourceReferenceId, int? majorVersion = 0, int? minorVersion = 0, int? userId = 0);
+
+ ///
+ /// Gets the user certificates.
+ ///
+ /// The request model.
+ /// The .
+ Task GetUserCertificateDetails(MyLearningRequestModel requestModel);
+
+ ///
+ /// Gets the resource URL for a given resource reference ID.
+ ///
+ /// resourceReferenceId.
+ /// The .
+ string GetResourceUrl(int resourceReferenceId);
}
}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs b/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs
index 19ee0a927..4fda81d60 100644
--- a/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs
+++ b/LearningHub.Nhs.WebUI/Interfaces/IUserService.cs
@@ -478,5 +478,45 @@ public interface IUserService
/// the string.
/// base64 string.
string Base64MD5HashDigest(string szString);
+
+ ///
+ /// The get current user profile for My account.
+ ///
+ /// The .
+ Task GetMyAccountPersonalDetailsAsync();
+
+ ///
+ /// Update MyAccount Personal Details Async.
+ ///
+ /// userId.
+ /// MyAccountPersonalDetailsViewModel.
+ /// The .
+ Task UpdateMyAccountPersonalDetailsAsync(int userId, MyAccountPersonalDetailsViewModel model);
+
+ ///
+ /// Get MyEmployment Details Async.
+ ///
+ /// The .
+ Task GetMyEmploymentDetailsAsync();
+
+ ///
+ /// Get MyAccount Security Details Async.
+ ///
+ /// The .
+ Task GetMyAccountSecurityDetailsAsync();
+
+ ///
+ /// Get MyAccount Location Details Async.
+ ///
+ /// The .
+ Task GetMyAccountLocationDetailsAsync();
+
+ ///
+ /// Update MyAccount Location Details Async.
+ ///
+ /// userId.
+ /// MyAccountLocationViewModel.
+ /// The .
+ Task UpdateMyAccountLocationDetailsAsync(int userId, MyAccountLocationViewModel model);
}
}
diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
index dc2cf661d..ce55ad824 100644
--- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
+++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
@@ -107,13 +107,13 @@
-
+
-
+
diff --git a/LearningHub.Nhs.WebUI/Models/DashBoard/DashBoardPagingViewModel.cs b/LearningHub.Nhs.WebUI/Models/DashBoard/DashBoardPagingViewModel.cs
index 7f29f8f86..5b477bae9 100644
--- a/LearningHub.Nhs.WebUI/Models/DashBoard/DashBoardPagingViewModel.cs
+++ b/LearningHub.Nhs.WebUI/Models/DashBoard/DashBoardPagingViewModel.cs
@@ -50,6 +50,11 @@ public class DashBoardPagingViewModel
///
public int TotalCount { get; set; }
+ ///
+ /// Gets or sets the dashboard tray Learning resource type.
+ ///
+ public string DashboardTrayLearningResourceType { get; set; }
+
///
/// Gets the display message.
///
diff --git a/LearningHub.Nhs.WebUI/Models/DashboardViewModel.cs b/LearningHub.Nhs.WebUI/Models/DashboardViewModel.cs
index 9ac98c7e0..24677a3c9 100644
--- a/LearningHub.Nhs.WebUI/Models/DashboardViewModel.cs
+++ b/LearningHub.Nhs.WebUI/Models/DashboardViewModel.cs
@@ -2,6 +2,7 @@
{
using System.Collections.Generic;
using LearningHub.Nhs.Models.Dashboard;
+ using LearningHub.Nhs.Models.Moodle.API;
///
/// Defines the .
@@ -33,6 +34,11 @@ public DashboardViewModel()
///
/// Gets or sets a list of enrolled courses to be displayed in the dashboard.
///
- public List EnrolledCourses { get; set; }
+ public List EnrolledCourses { get; set; }
+
+ ///
+ /// Gets or sets the dashboard tray Learning resource type.
+ ///
+ public string DashboardTrayLearningResourceType { get; set; }
}
}
diff --git a/LearningHub.Nhs.WebUI/Models/MoodleCompletionResponseViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleCompletionResponseViewModel.cs
deleted file mode 100644
index 1692a32e6..000000000
--- a/LearningHub.Nhs.WebUI/Models/MoodleCompletionResponseViewModel.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace LearningHub.Nhs.WebUI.Models
-{
- ///
- /// MoodleCompletionResponseViewModel.
- ///
- public class MoodleCompletionResponseViewModel
- {
- ///
- /// Gets or sets the completion status.
- ///
- public string Exception { get; set; }
-
- ///
- /// Gets or sets error code.
- ///
- public string Errorcode { get; set; }
-
- ///
- /// Gets or sets Error message.
- ///
- public string Message { get; set; }
-
- ///
- /// Gets or sets Debug info.
- ///
- public string Debuginfo { get; set; }
- }
-}
diff --git a/LearningHub.Nhs.WebUI/Models/MoodleCourseCompletionViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleCourseCompletionViewModel.cs
deleted file mode 100644
index 06eb5cb8f..000000000
--- a/LearningHub.Nhs.WebUI/Models/MoodleCourseCompletionViewModel.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-namespace LearningHub.Nhs.WebUI.Models
-{
- using System.Collections.Generic;
-
- ///
- /// MoodleCourseCompletionViewModel.
- ///
- public class MoodleCourseCompletionViewModel
- {
- ///
- /// Gets or sets the completion status.
- ///
- public CompletStatus CompletionStatus { get; set; }
-
- ///
- /// Gets or sets the list of warnings.
- ///
- public List
public bool ShowBrowseCatalogues { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether ShowHome.
+ ///
+ public bool ShowHome { get; set; }
}
}
diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavViewModel.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavViewModel.cs
new file mode 100644
index 000000000..28ae8f060
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavViewModel.cs
@@ -0,0 +1,21 @@
+namespace LearningHub.Nhs.WebUI.Models.SideMenu
+{
+ using System.Collections.Generic;
+ using Microsoft.AspNetCore.Routing;
+
+ ///
+ /// Defines the .
+ ///
+ public class SideNavViewModel
+ {
+ ///
+ /// Gets or sets the Groups.
+ ///
+ public List Groups { get; set; } = [];
+
+ ///
+ /// Gets or sets the RouteData.
+ ///
+ public RouteValueDictionary RouteData { get; set; } = [];
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs
new file mode 100644
index 000000000..7f1184bee
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationConfiguration.cs
@@ -0,0 +1,114 @@
+namespace LearningHub.Nhs.WebUI.Models.SideMenu
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Microsoft.AspNetCore.Routing;
+
+ ///
+ /// Defines the .
+ ///
+ public static class SideNavigationConfiguration
+ {
+ ///
+ /// GetGroupedMenus.
+ ///
+ /// IEnumerable.
+ public static IEnumerable GetGroupedMenus()
+ {
+ return new List
+ {
+ new SideNavigationGroup
+ {
+ GroupTitle = "Account",
+ Items = new List
+ {
+ new SideNavigationItem
+ {
+ Text = "Personal details",
+ Controller = "MyAccount",
+ Action = "Index",
+ IsActive = route => MatchRoute(route, "MyAccount", "Index"),
+ },
+ new SideNavigationItem
+ {
+ Text = "My employment",
+ Controller = "MyAccount",
+ Action = "MyEmploymentDetails",
+ IsActive = route => MatchRoute(route, "MyAccount", "MyEmploymentDetails"),
+ },
+ new SideNavigationItem
+ {
+ Text = "Security",
+ Controller = "MyAccount",
+ Action = "MyAccountSecurity",
+ IsActive = route => MatchRoute(route, "MyAccount", "MyAccountSecurity"),
+ },
+ new SideNavigationItem
+ {
+ Text = "Notifications",
+ Controller = "Notification",
+ Action = "Index",
+ IsActive = route => MatchRoute(route, "Notification", "Index"),
+ },
+ },
+ },
+ new SideNavigationGroup
+ {
+ GroupTitle = "Activity",
+ Items = new List
+ {
+ new SideNavigationItem
+ {
+ Text = "Recent learning",
+ Controller = "MyLearning",
+ Action = "Index",
+ IsActive = route => MatchRoute(route, "MyLearning", "Index"),
+ },
+ new SideNavigationItem
+ {
+ Text = "Bookmarks",
+ Controller = "Bookmark",
+ Action = "Index",
+ IsActive = route => MatchRoute(route, "Bookmark", "Index"),
+ },
+ new SideNavigationItem
+ {
+ Text = "Certificates",
+ Controller = "MyLearning",
+ Action = "Certificates",
+ IsActive = route => MatchRoute(route, "MyLearning", "Certificates"),
+ },
+ new SideNavigationItem
+ {
+ Text = "Learning history",
+ Controller = "MyLearning",
+ Action = "LearningHistory",
+ IsActive = route => MatchRoute(route, "MyLearning", "LearningHistory"),
+ },
+ },
+ },
+ };
+ }
+
+ ///
+ /// GetMenuGroupByTitle.
+ ///
+ /// title.
+ /// string.
+ public static SideNavigationGroup? GetMenuGroupByTitle(string title)
+ {
+ return GetGroupedMenus().FirstOrDefault(g =>
+ string.Equals(g.GroupTitle, title, StringComparison.OrdinalIgnoreCase));
+ }
+
+ private static bool MatchRoute(RouteValueDictionary route, string controller, string action)
+ {
+ var currentController = route["controller"]?.ToString();
+ var currentAction = route["action"]?.ToString();
+
+ return string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase) &&
+ string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase);
+ }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationGroup.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationGroup.cs
new file mode 100644
index 000000000..ff35ed8f7
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationGroup.cs
@@ -0,0 +1,20 @@
+namespace LearningHub.Nhs.WebUI.Models.SideMenu
+{
+ using System.Collections.Generic;
+
+ ///
+ /// Defines the .
+ ///
+ public class SideNavigationGroup
+ {
+ ///
+ /// Gets or sets a value indicating GroupTitle.
+ ///
+ public string GroupTitle { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a Items.
+ ///
+ public List Items { get; set; } = [];
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationItem.cs b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationItem.cs
new file mode 100644
index 000000000..156e90893
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/SideMenu/SideNavigationItem.cs
@@ -0,0 +1,31 @@
+namespace LearningHub.Nhs.WebUI.Models.SideMenu
+{
+ using System;
+ using Microsoft.AspNetCore.Routing;
+
+ ///
+ /// Defines the .
+ ///
+ public class SideNavigationItem
+ {
+ ///
+ /// Gets or sets a value indicating Text.
+ ///
+ public string Text { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a value indicating Controller.
+ ///
+ public string Controller { get; set; } = string.Empty;
+
+ ///
+ /// Gets or sets a value indicating Action.
+ ///
+ public string Action { get; set; } = "Index";
+
+ ///
+ /// Gets or sets a value indicating IsActiven.
+ ///
+ public Func IsActive { get; set; }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountEmploymentDetailsViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountEmploymentDetailsViewModel.cs
new file mode 100644
index 000000000..41b93b692
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountEmploymentDetailsViewModel.cs
@@ -0,0 +1,95 @@
+namespace LearningHub.Nhs.WebUI.Models.UserProfile
+{
+ using System;
+
+ ///
+ /// Defines the .
+ ///
+ public class MyAccountEmploymentDetailsViewModel
+ {
+ ///
+ /// Gets or sets the Id.
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the Country.
+ ///
+ public string Country { get; set; }
+
+ ///
+ /// Gets or sets the Region.
+ ///
+ public string Region { get; set; }
+
+ ///
+ /// Gets or sets the CountryName.
+ ///
+ public string CountryName { get; set; }
+
+ ///
+ /// Gets or sets the RegionName.
+ ///
+ public string RegionName { get; set; }
+
+ ///
+ /// Gets or sets the user employment id.
+ ///
+ public int EmploymentId { get; set; }
+
+ ///
+ /// Gets or sets the job role id.
+ ///
+ public int? JobRoleId { get; set; }
+
+ ///
+ /// Gets or sets the CurrentRole.
+ ///
+ public string JobRole { get; set; }
+
+ ///
+ /// Gets or sets the medical council id.
+ ///
+ public int? MedicalCouncilId { get; set; }
+
+ ///
+ /// Gets or sets the ProfessionalRegistrationNumber.
+ ///
+ public string MedicalCouncilNo { get; set; }
+
+ ///
+ /// Gets or sets the grade id.
+ ///
+ public int? GradeId { get; set; }
+
+ ///
+ /// Gets or sets the Grade.
+ ///
+ public string Grade { get; set; }
+
+ ///
+ /// Gets or sets the specialty id.
+ ///
+ public int? SpecialtyId { get; set; }
+
+ ///
+ /// Gets or sets the PrimarySpecialty.
+ ///
+ public string PrimarySpecialty { get; set; }
+
+ ///
+ /// Gets or sets the StartDate.
+ ///
+ public DateTimeOffset? JobStartDate { get; set; }
+
+ ///
+ /// Gets or sets the location id.
+ ///
+ public int LocationId { get; set; }
+
+ ///
+ /// Gets or sets the PlaceOfWork.
+ ///
+ public string PlaceOfWork { get; set; }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs
new file mode 100644
index 000000000..58bd757ae
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountLocationViewModel.cs
@@ -0,0 +1,65 @@
+namespace LearningHub.Nhs.WebUI.Models.UserProfile
+{
+ using System.Collections.Generic;
+ using System.ComponentModel;
+ using Microsoft.AspNetCore.Mvc.Rendering;
+ using NHSUKViewComponents.Web.ViewModels;
+
+ ///
+ /// Defines the .
+ ///
+ public class MyAccountLocationViewModel
+ {
+ ///
+ /// Gets or sets the country id.
+ ///
+ [DisplayName("Country")]
+ public int? SelectedCountryId { get; set; }
+
+ ///
+ /// Gets or sets the region id.
+ ///
+ [DisplayName("Region")]
+ public int? SelectedRegionId { get; set; }
+
+ ///
+ /// Gets or sets selected country name.
+ ///
+ public string SelectedCountryName { get; set; }
+
+ ///
+ /// Gets or sets selected region name.
+ ///
+ public string SelectedRegionName { get; set; }
+
+ ///
+ /// Gets or sets the country id.
+ ///
+ public int? SelectedOtherCountryId { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether SelectedOtherCountry.
+ ///
+ public bool HasSelectedOtherCountry { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether SelectedRegion.
+ ///
+ public bool HasSelectedRegion { get; set; }
+
+ ///
+ /// Gets or sets the Country.
+ ///
+ public List Country { get; set; }
+
+ ///
+ /// Gets or sets the OtherCountryOptions.
+ ///
+ public IEnumerable OtherCountryOptions { get; set; }
+
+ ///
+ /// Gets or sets the RegionOptions.
+ ///
+ public IEnumerable RegionOptions { get; set; }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs
new file mode 100644
index 000000000..d7f6eeaf0
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs
@@ -0,0 +1,74 @@
+namespace LearningHub.Nhs.WebUI.Models.UserProfile
+{
+ using System.ComponentModel;
+ using System.ComponentModel.DataAnnotations;
+ using LearningHub.Nhs.WebUI.Attributes;
+ using LearningHub.Nhs.WebUI.Helpers;
+ using LearningHub.Nhs.WebUI.Validation;
+
+ ///
+ /// Defines the .
+ ///
+ public class MyAccountPersonalDetailsViewModel
+ {
+ ///
+ /// Gets or sets the UserName.
+ ///
+ [DisplayName("Username")]
+ public string UserName { get; set; }
+
+ ///
+ /// Gets or sets the Name.
+ ///
+ [DisplayName("Name")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the FirstName.
+ ///
+ [Required(ErrorMessage = "Enter a first name")]
+ [StringLength(50, MinimumLength = 1, ErrorMessage = "First name must be less than 50 characters.")]
+ [DisplayName("First name")]
+ public string FirstName { get; set; }
+
+ ///
+ /// Gets or sets the LastName.
+ ///
+ [Required(ErrorMessage = "Enter a last name")]
+ [StringLength(50, MinimumLength = 1, ErrorMessage = "Last name must be less than 50 characters.")]
+ [DisplayName("Last name")]
+ public string LastName { get; set; }
+
+ ///
+ /// Gets or sets the PreferredName.
+ ///
+ [StringLength(50, MinimumLength = 0, ErrorMessage = "Preferred name must be less than 50 characters.")]
+ [DisplayName("Preferred name")]
+ public string PreferredName { get; set; }
+
+ ///
+ /// Gets or sets the Primary Email Address.
+ ///
+ [DataType(DataType.EmailAddress)]
+ [Required(ErrorMessage = "Enter a primary email address")]
+ [MaxLength(100, ErrorMessage = CommonValidationErrorMessages.TooLongEmail)]
+ [EmailAddress(ErrorMessage = CommonValidationErrorMessages.InvalidEmail)]
+ [NoWhitespace(ErrorMessage = CommonValidationErrorMessages.WhitespaceInEmail)]
+ [DisplayName("Primary email address")]
+ public string PrimaryEmailAddress { get; set; }
+
+ ///
+ /// Gets or sets the new primary email address.
+ ///
+ public string NewPrimaryEmailAddress { get; set; }
+
+ ///
+ /// Gets or sets the SecondaryEmailAddress.
+ ///
+ [DataType(DataType.EmailAddress)]
+ [MaxLength(100, ErrorMessage = CommonValidationErrorMessages.TooLongEmail)]
+ [EmailAddress(ErrorMessage = CommonValidationErrorMessages.InvalidEmail)]
+ [NoWhitespace(ErrorMessage = CommonValidationErrorMessages.WhitespaceInEmail)]
+ public string SecondaryEmailAddress { get; set; }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs
new file mode 100644
index 000000000..d1a26f4c1
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountSecurityViewModel.cs
@@ -0,0 +1,45 @@
+namespace LearningHub.Nhs.WebUI.Models.UserProfile
+{
+ using System;
+
+ ///
+ /// Defines the .
+ ///
+ public class MyAccountSecurityViewModel
+ {
+ ///
+ /// Gets or sets the Id.
+ ///
+ public int Id { get; set; }
+
+ ///
+ /// Gets or sets the SecondaryEmailAddress.
+ ///
+ public string SecondaryEmailAddress { get; set; }
+
+ ///
+ /// Gets or sets the SecurityFirstQuestion.
+ ///
+ public string SecurityFirstQuestion { get; set; }
+
+ ///
+ /// Gets or sets the SecuritySecondQuestion.
+ ///
+ public string SecuritySecondQuestion { get; set; }
+
+ ///////
+ /////// Gets or sets the LastUpdated.
+ ///////
+ ////public DateTimeOffset LastUpdated { get; set; }
+
+ ///
+ /// Gets or sets the PasswordHash.
+ ///
+ public string PasswordHash { get; set; }
+
+ ///
+ /// Gets or sets the SecurityQuestionLastUpdated.
+ ///
+ public string SecurityQuestionLastUpdated { get; set; }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/MyAcountSecurityQuestionsViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAcountSecurityQuestionsViewModel.cs
new file mode 100644
index 000000000..7712ae470
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAcountSecurityQuestionsViewModel.cs
@@ -0,0 +1,54 @@
+namespace LearningHub.Nhs.WebUI.Models.UserProfile
+{
+ using System.Collections.Generic;
+ using System.ComponentModel.DataAnnotations;
+ using elfhHub.Nhs.Models.Common;
+ using Microsoft.AspNetCore.Mvc.Rendering;
+ using NHSUKViewComponents.Web.ViewModels;
+
+ ///
+ /// Defines the .
+ ///
+ public class MyAcountSecurityQuestionsViewModel
+ {
+ ///
+ /// Gets or sets selectedQuestion.
+ ///
+ public int SelectedFirstQuestionId { get; set; }
+
+ ///
+ /// Gets or sets selectedQuestion.
+ ///
+ public int SelectedSecondQuestionId { get; set; }
+
+ ///
+ /// Gets or sets the security question answer hash.
+ ///
+ public string SecurityFirstQuestionAnswerHash { get; set; }
+
+ ///
+ /// Gets or sets the security question answer hash.
+ ///
+ public string SecuritySecondQuestionAnswerHash { get; set; }
+
+ ///
+ /// Gets or sets the FirstSecurityQuestions.
+ ///
+ public IEnumerable FirstSecurityQuestions { get; set; }
+
+ ///
+ /// Gets or sets the SecondSecurityQuestions.
+ ///
+ public IEnumerable SecondSecurityQuestions { get; set; }
+
+ ///
+ /// Gets or sets the UserSecurityFirstQuestionId.
+ ///
+ public int UserSecurityFirstQuestionId { get; set; }
+
+ ///
+ /// Gets or sets the UserSecurityFirstQuestionId.
+ ///
+ public int UserSecuritySecondQuestionId { get; set; }
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/UserJobRoleUpdateViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/UserJobRoleUpdateViewModel.cs
index a48170b6c..a2e9fe004 100644
--- a/LearningHub.Nhs.WebUI/Models/UserProfile/UserJobRoleUpdateViewModel.cs
+++ b/LearningHub.Nhs.WebUI/Models/UserProfile/UserJobRoleUpdateViewModel.cs
@@ -24,7 +24,7 @@ public class UserJobRoleUpdateViewModel : PagingViewModel
///
/// Gets or sets the selected job role id.
///
- public int? SelectedJobRoleId { get; set; }
+ public string SelectedJobRoleId { get; set; }
///
/// Gets or sets the RoleList.
diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs
index 8dd1546ed..563b2b668 100644
--- a/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs
+++ b/LearningHub.Nhs.WebUI/Models/UserProfile/UserPrimarySpecialtyUpdateViewModel.cs
@@ -24,7 +24,7 @@ public class UserPrimarySpecialtyUpdateViewModel : PagingViewModel
///
/// Gets or sets the selected primary specialty id.
///
- public int? SelectedPrimarySpecialtyId { get; set; }
+ public string SelectedPrimarySpecialtyId { get; set; }
///
/// Gets or sets the SpecialtyList.
@@ -36,6 +36,21 @@ public class UserPrimarySpecialtyUpdateViewModel : PagingViewModel
///
public GenericListViewModel OptionalSpecialtyItem { get; set; }
+ ///
+ /// Gets or sets the selected job role id.
+ ///
+ public int? SelectedJobRoleId { get; set; }
+
+ ///
+ /// Gets or sets the selected grade id.
+ ///
+ public string SelectedGradeId { get; set; }
+
+ ///
+ /// Gets or sets the selected medical council number.
+ ///
+ public string SelectedMedicalCouncilNo { get; set; }
+
///
/// sets the list of radio specialty.
///
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue
index 25ef12656..84fb2eb0c 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/notification/notification.vue
@@ -1,7 +1,7 @@
-
{{priorityTypeText}}
+
{{priorityTypeText}}