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..126c014ef 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj +++ b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -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..a423f7061 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/AccountController.cs b/LearningHub.Nhs.WebUI/Controllers/AccountController.cs index 2d2017cd2..d22a8485e 100644 --- a/LearningHub.Nhs.WebUI/Controllers/AccountController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/AccountController.cs @@ -999,7 +999,7 @@ public async Task CreateAccountWorkPlace(AccountCreationViewModel if (!string.IsNullOrWhiteSpace(accountCreation.LocationId)) { var selectedLocation = await this.locationService.GetByIdAsync(int.Parse(accountCreation.LocationId)); - return this.View(new AccountCreationListViewModel { WorkPlaceList = new List { selectedLocation }, FilterText = selectedLocation.Name, AccountCreationPaging = new AccountCreationPagingModel { TotalItems = 1, PageSize = UserRegistrationContentPageSize, HasItems = selectedLocation != null, CurrentPage = 1 }, LocationId = accountCreation.LocationId, ReturnToConfirmation = accountCreationViewModel.ReturnToConfirmation }); + return this.View(new AccountCreationListViewModel { WorkPlaceList = new List { selectedLocation }, FilterText = selectedLocation.NameWithoutSubName, AccountCreationPaging = new AccountCreationPagingModel { TotalItems = 1, PageSize = UserRegistrationContentPageSize, HasItems = selectedLocation != null, CurrentPage = 1 }, LocationId = accountCreation.LocationId, ReturnToConfirmation = accountCreationViewModel.ReturnToConfirmation }); } accountCreationViewModel.PrimarySpecialtyId = accountCreation.PrimarySpecialtyId; 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..5f4540b57 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 = "my-recent-completed", 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..d9ececfed 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,43 +1349,60 @@ public async Task ChangeWorkPlace([FromQuery] UserWorkPlaceUpdate return this.View("ChangeWorkPlace", viewModel); } - if (formSubmission && viewModel.SelectedWorkPlaceId.HasValue) + if (formSubmission) { - 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)) + var hasSelectedWorkPlace = int.TryParse(viewModel.SelectedWorkPlaceId, out int selectedWorkPlaceId); + if (hasSelectedWorkPlace && selectedWorkPlaceId > 0) { - await this.loginWizardService.SaveLoginWizardStageActivity(LoginWizardStageEnum.PlaceOfWork, this.CurrentUserId); + 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 = selectedWorkPlaceId, + }); + + 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 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, - }; + var loginWizardViewModel = new LoginWizardStagesViewModel + { + IsFirstLogin = loginWizard.IsFirstLogin, + LoginWizardStages = loginWizard.LoginWizardStages, + LoginWizardStagesCompleted = loginWizard.LoginWizardStagesCompleted, + }; - await this.cacheService.SetAsync(this.LoginWizardCacheKey, Newtonsoft.Json.JsonConvert.SerializeObject(loginWizardViewModel)); - } + 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"); + this.ViewBag.SuccessMessage = CommonValidationErrorMessages.EmploymentDetailsUpdated; + this.ViewBag.MyAction = "MyEmploymentDetails"; + return this.View("SuccessMessageMyAccount"); + } + else + { + this.ModelState.AddModelError(nameof(viewModel.SelectedWorkPlaceId), CommonValidationErrorMessages.WorkPlace); + } + } + else + { + if (!searchSubmission) + { + viewModel.SelectedWorkPlaceId = profile.LocationId.ToString(); + viewModel.FilterText = profile.LocationName; + } } if (!string.IsNullOrWhiteSpace(viewModel.FilterText)) @@ -1197,5 +1586,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..3dc2fe732 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 { @@ -139,20 +139,15 @@ public async Task Index(MyLearningViewModel learningRequest = nul if (myLearningDashboard == "my-in-progress") { 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; } } @@ -216,8 +211,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 +227,160 @@ 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; + } + else if (myLearningDashboard == "my-recent-completed") + { + myLearningRequestModel.Complete = true; + } + else if (myLearningDashboard == "my-certificates") + { + myLearningRequestModel.CertificateEnabled = true; + myLearningRequestModel.Complete = 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 +443,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 +551,79 @@ 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, + Weblink = certificateRequest.Weblink, + 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 = certificatePageSize, TotalItems = response.TotalCount, HasItems = response.TotalCount > 0 }; + return this.View(response); + } + /// /// Gets the certificate details of an activity. /// @@ -435,6 +672,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..9f60a93dc 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 }, }; /// @@ -161,53 +143,7 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType return "Case"; case ResourceTypeEnum.Html: return "HTML"; - default: - return "File"; - } - } - - /// 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: + case ResourceTypeEnum.Moodle: return "Course"; default: return "File"; @@ -247,6 +183,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..a357fa371 100644 --- a/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs +++ b/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs @@ -2,8 +2,10 @@ { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Linq; using LearningHub.Nhs.Models.Enums; + using LearningHub.Nhs.Models.MyLearning; using LearningHub.Nhs.WebUI.Models; /// @@ -71,6 +73,127 @@ 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.Viewed || activity.ActivityStatus == ActivityStatusEnum.Downloaded) + { + return "Completed"; + } + else + { + return "InProgress"; + } + } + + /// + /// GetCertificateStatusDisplayText. + /// + /// The activity. + /// The string. + public static string GetCertificateStatusDisplayText(ActivityDetailedItemViewModel activity) + { + if (activity.ActivityStatus == ActivityStatusEnum.Completed || 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 (activitiesViewModel.ResourceType == ResourceTypeEnum.Assessment && activitiesViewModel.AssessmentType == (int)AssessmentTypeEnum.Informal && activitiesViewModel.AssesmentScore >= activitiesViewModel.AssessmentPassMark) + { + return true; + } + else if (activitiesViewModel.ResourceType == ResourceTypeEnum.Assessment && activitiesViewModel.AssessmentType == (int)AssessmentTypeEnum.Informal) + { + return false; + } + else + { + if (GetActivityStatusDisplayText(activitiesViewModel) == "Completed" || GetActivityStatusDisplayText(activitiesViewModel) == "Passed" || GetActivityStatusDisplayText(activitiesViewModel) == "Downloaded") + { + return true; + } + } + } + + return false; + } + /// /// GetResourceTypeVerb. /// @@ -286,6 +409,21 @@ public static bool CanViewProgress(this ActivityDetailedItemViewModel activityDe return false; } + /// + /// CanView Video Progress. + /// + /// The MyLearningCombinedActivitiesViewModel. + /// The bool. + public static bool CanViewVidoProgress(this MyLearningCombinedActivitiesViewModel activitiesViewModel) + { + if ((activitiesViewModel.ResourceType == ResourceTypeEnum.Video || activitiesViewModel.ResourceType == ResourceTypeEnum.Audio) && activitiesViewModel.ActivityStatus == ActivityStatusEnum.Incomplete && activitiesViewModel.IsCurrentResourceVersion && activitiesViewModel.IsMostRecent) + { + return true; + } + + return false; + } + /// /// GetDurationText. /// @@ -340,6 +478,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..ac23486b8 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 Warnings { get; set; } - - /// - /// CompletionStatus. - /// - public class CompletStatus - { - /// - /// Gets or sets a value indicating whether the course is completed. - /// - public bool Completed { get; set; } - - /// - /// Gets or sets the aggregation method. - /// - public int Aggregation { get; set; } - - /// - /// Gets or sets the list of completions. - /// - public List Completions { get; set; } - - /// - /// Completion. - /// - public class Completion - { - /// - /// Gets or sets the type of completion. - /// - public int Type { get; set; } - - /// - /// Gets or sets the title of the completion requirement. - /// - public string Title { get; set; } - - /// - /// Gets or sets the status of the completion. - /// - public string Status { get; set; } - - /// - /// Gets or sets a value indicating whether the requirement is complete. - /// - public bool Complete { get; set; } - - /// - /// Gets or sets the timestamp when completion was achieved. - /// - public long? TimeCompleted { get; set; } - - /// - /// Gets or sets the completion details. - /// - public CompletionDetails Details { get; set; } - - /// - /// CompletionDetails. - /// - public class CompletionDetails - { - /// - /// Gets or sets the type of completion requirement. - /// - public string Type { get; set; } - - /// - /// Gets or sets the criteria for completion. - /// - public string Criteria { get; set; } - - /// - /// Gets or sets the requirement for completion. - /// - public string Requirement { get; set; } - - /// - /// Gets or sets the status of the requirement. - /// - public string Status { get; set; } - } - } - } - } -} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs deleted file mode 100644 index b214cf072..000000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs +++ /dev/null @@ -1,165 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - using System.Collections.Generic; - - /// - /// MoodleCourseResponseViewModel. - /// - public class MoodleCourseResponseViewModel - { - /// - /// Gets or sets the ID. - /// - public int? Id { get; set; } - - /// - /// Gets or sets the short name. - /// - public string ShortName { get; set; } - - /// - /// Gets or sets the full name. - /// - public string FullName { get; set; } - - /// - /// Gets or sets the display name. - /// - public string DisplayName { get; set; } - - /// - /// Gets or sets the enrolled user count. - /// - public int? EnrolledUserCount { get; set; } - - /// - /// Gets or sets the ID number. - /// - public string IdNumber { get; set; } - - /// - /// Gets or sets the visibility status. - /// - public int? Visible { get; set; } - - /// - /// Gets or sets the summary. - /// - public string Summary { get; set; } - - /// - /// Gets or sets the summary format. - /// - public int? SummaryFormat { get; set; } - - /// - /// Gets or sets the format. - /// - public string Format { get; set; } - - /// - /// Gets or sets the course image URL. - /// - public string CourseImage { get; set; } - - /// - /// Gets or sets a value indicating whether grades are shown. - /// - public bool? ShowGrades { get; set; } - - /// - /// Gets or sets the language. - /// - public string Lang { get; set; } - - /// - /// Gets or sets a value indicating whether completion is enabled. - /// - public bool? EnableCompletion { get; set; } - - /// - /// Gets or sets a value indicating whether completion has criteria. - /// - public bool? CompletionHasCriteria { get; set; } - - /// - /// Gets or sets a value indicating whether completion is user-tracked. - /// - public bool? CompletionUserTracked { get; set; } - - /// - /// Gets or sets the category ID. - /// - public int? Category { get; set; } - - /// - /// Gets the progress percentage formatted as a string. - /// - public string ProgressPercentage => $"{System.Math.Round(this.Progress ?? 0)}%"; - - /// - /// Gets or sets the progress. - /// - public double? Progress { get; set; } - - /// - /// Gets or sets the completion status. - /// - public bool? Completed { get; set; } - - /// - /// Gets or sets the start date (Unix timestamp). - /// - public long? StartDate { get; set; } - - /// - /// Gets or sets the end date. - /// - public int? EndDate { get; set; } - - /// - /// Gets or sets the marker. - /// - public int? Marker { get; set; } - - /// - /// Gets or sets the last access timestamp. - /// - public int? LastAccess { get; set; } - - /// - /// Gets or sets a value indicating whether the course is a favorite. - /// - public bool? IsFavourite { get; set; } - - /// - /// Gets or sets a value indicating whether the course is hidden. - /// - public bool? Hidden { get; set; } - - /// - /// Gets or sets the list of overview files. - /// - public List OverviewFiles { get; set; } - - /// - /// Gets or sets a value indicating whether activity dates are shown. - /// - public bool? ShowActivityDates { get; set; } - - /// - /// Gets or sets a value indicating whether completion conditions are shown. - /// - public bool? ShowCompletionConditions { get; set; } - - /// - /// Gets or sets the last modified timestamp (Unix timestamp). - /// - public long? TimeModified { get; set; } - - /// - /// Gets or sets the moodle course completion view model. - /// - public MoodleCourseCompletionViewModel CourseCompletionViewModel { get; set; } - } -} diff --git a/LearningHub.Nhs.WebUI/Models/MoodleOverviewFileViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleOverviewFileViewModel.cs deleted file mode 100644 index 3dd335c41..000000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleOverviewFileViewModel.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - /// - /// MoodleOverviewFileViewModel. - /// - public class MoodleOverviewFileViewModel - { - /// - /// Gets or sets the file name. - /// - public string? FileName { get; set; } - - /// - /// Gets or sets the file path. - /// - public string? FilePath { get; set; } - - /// - /// Gets or sets the file size in bytes. - /// - public int FileSize { get; set; } - - /// - /// Gets or sets the file URL. - /// - public string? FileUrl { get; set; } - - /// - /// Gets or sets the time the file was modified (Unix timestamp). - /// - public long TimeModified { get; set; } - - /// - /// Gets or sets the MIME type of the file. - /// - public string? MimeType { get; set; } - } -} diff --git a/LearningHub.Nhs.WebUI/Models/MoodleUserResponseViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleUserResponseViewModel.cs deleted file mode 100644 index 7940dc725..000000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleUserResponseViewModel.cs +++ /dev/null @@ -1,121 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - using System.Collections.Generic; - - /// - /// MoodleUserResponseViewModel. - /// - public class MoodleUserResponseViewModel - { - /// - /// Gets or sets the list of users. - /// - public List Users { get; set; } - - /// - /// Gets or sets the warnings. - /// - public List Warnings { get; set; } - - /// - /// MoodleUser. - /// - public class MoodleUser - { - /// - /// Gets or sets the user ID. - /// - public int Id { get; set; } - - /// - /// Gets or sets the username. - /// - public string Username { get; set; } - - /// - /// Gets or sets the first name. - /// - public string FirstName { get; set; } - - /// - /// Gets or sets the last name. - /// - public string LastName { get; set; } - - /// - /// Gets or sets the full name. - /// - public string FullName { get; set; } - - /// - /// Gets or sets the email. - /// - public string Email { get; set; } - - /// - /// Gets or sets the department. - /// - public string Department { get; set; } - - /// - /// Gets or sets the first access timestamp. - /// - public long FirstAccess { get; set; } - - /// - /// Gets or sets the last access timestamp. - /// - public long LastAccess { get; set; } - - /// - /// Gets or sets the authentication method. - /// - public string Auth { get; set; } - - /// - /// Gets or sets a value indicating whether the user is suspended. - /// - public bool Suspended { get; set; } - - /// - /// Gets or sets a value indicating whether the user is confirmed. - /// - public bool Confirmed { get; set; } - - /// - /// Gets or sets the language. - /// - public string Lang { get; set; } - - /// - /// Gets or sets the theme. - /// - public string Theme { get; set; } - - /// - /// Gets or sets the timezone. - /// - public string Timezone { get; set; } - - /// - /// Gets or sets the mail format. - /// - public int MailFormat { get; set; } - - /// - /// Gets or sets the forum tracking preference. - /// - public int TrackForums { get; set; } - - /// - /// Gets or sets the small profile image URL. - /// - public string ProfileImageUrlSmall { get; set; } - - /// - /// Gets or sets the profile image URL. - /// - public string ProfileImageUrl { get; set; } - } - } -} diff --git a/LearningHub.Nhs.WebUI/Models/MyLearningUserActivitiesViewModel.cs b/LearningHub.Nhs.WebUI/Models/MyLearningUserActivitiesViewModel.cs new file mode 100644 index 000000000..0042021cb --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/MyLearningUserActivitiesViewModel.cs @@ -0,0 +1,122 @@ +namespace LearningHub.Nhs.WebUI.Models +{ + using System; + using System.Collections.Generic; + using System.ComponentModel.DataAnnotations; + using System.Linq; + using System.Reflection; + using LearningHub.Nhs.Models.Enums; + using LearningHub.Nhs.Models.MyLearning; + using LearningHub.Nhs.Models.Paging; + using LearningHub.Nhs.Models.Search; + using LearningHub.Nhs.WebUI.Helpers; + using LearningHub.Nhs.WebUI.Models.Learning; + using NHSUKViewComponents.Web.ViewModels; + + /// + /// Defines the . + /// + public class MyLearningUserActivitiesViewModel : MyLearningRequestModel + { + /// + /// Initializes a new instance of the class. + /// + public MyLearningUserActivitiesViewModel() + { + this.Activities = new List(); + } + + /// + /// Initializes a new instance of the class. + /// + /// MyLearningRequestModel. + public MyLearningUserActivitiesViewModel(MyLearningRequestModel requestModel) + { + this.Activities = new List(); + foreach (PropertyInfo prop in requestModel.GetType().GetProperties()) + { + this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(requestModel, null), null); + } + } + + /// + /// Gets or sets the learning form event. + /// + public MyLearningFormActionTypeEnum MyLearningFormActionType { get; set; } + + /// + /// Gets or sets the page item index. + /// + public int CurrentPageIndex { get; set; } = 0; + + /// + /// Gets or sets the TotalCount. + /// + public int TotalCount { get; set; } + + /// + /// Gets or sets the MostRecentResources. + /// + public List MostRecentResources { get; set; } + + /// + /// Gets or sets the Activities. + /// + public List Activities { get; set; } + + /// + /// Gets or sets the learning result paging. + /// + public PagingViewModel MyLearningPaging { get; set; } + + /// + /// sets the list of certificate checkboxes. + /// + /// The . + public List CertificateFilterCheckbox() + { + var checkboxes = new List() + { + new CheckboxListItemViewModel("CertificateEnabled", "Certificate", null), + }; + return checkboxes; + } + + /// + /// sets the list of status checkboxes. + /// + /// The . + public List StatusFilterCheckbox() + { + var checkboxes = new List() + { + new CheckboxListItemViewModel("Complete", "Completed", null), + new CheckboxListItemViewModel("Incomplete", "In progress", null), + }; + return checkboxes; + } + + /// + /// sets the list of type checkboxes. + /// + /// The . + public List TypeFilterCheckbox() + { + var checkboxes = new List() + { + new CheckboxListItemViewModel("Article", "Article", null), + new CheckboxListItemViewModel("Assessment", "Assessment", null), + new CheckboxListItemViewModel("Audio", "Audio", null), + new CheckboxListItemViewModel("Case", "Case", null), + new CheckboxListItemViewModel("Elearning", "elearning", null), + new CheckboxListItemViewModel("File", "File", null), + new CheckboxListItemViewModel("Html", "HTML", null), + new CheckboxListItemViewModel("Image", "Image", null), + new CheckboxListItemViewModel("Video", "Video", null), + new CheckboxListItemViewModel("Weblink", "Weblink", null), + new CheckboxListItemViewModel("Courses", "Courses", null), + }; + return checkboxes; + } + } +} diff --git a/LearningHub.Nhs.WebUI/Models/MyLearningUserCertificatesViewModel.cs b/LearningHub.Nhs.WebUI/Models/MyLearningUserCertificatesViewModel.cs new file mode 100644 index 000000000..b1abc7c52 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/MyLearningUserCertificatesViewModel.cs @@ -0,0 +1,84 @@ +namespace LearningHub.Nhs.WebUI.Models +{ + using System.Collections.Generic; + using System.Reflection; + using LearningHub.Nhs.Models.MyLearning; + using LearningHub.Nhs.Models.Paging; + using LearningHub.Nhs.WebUI.Models.Learning; + using NHSUKViewComponents.Web.ViewModels; + + /// + /// Defines the . + /// + public class MyLearningUserCertificatesViewModel : MyLearningRequestModel + { + /// + /// Initializes a new instance of the class. + /// + public MyLearningUserCertificatesViewModel() + { + this.UserCertificates = new List(); + } + + /// + /// Initializes a new instance of the class. + /// + /// MyLearningRequestModel. + public MyLearningUserCertificatesViewModel(MyLearningRequestModel requestModel) + { + this.UserCertificates = new List(); + foreach (PropertyInfo prop in requestModel.GetType().GetProperties()) + { + this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(requestModel, null), null); + } + } + + /// + /// Gets or sets the learning form event. + /// + public MyLearningFormActionTypeEnum MyLearningFormActionType { get; set; } + + /// + /// Gets or sets the page item index. + /// + public int CurrentPageIndex { get; set; } = 0; + + /// + /// Gets or sets the TotalCount. + /// + public int TotalCount { get; set; } + + /// + /// Gets or sets the Activities. + /// + public List UserCertificates { get; set; } + + /// + /// Gets or sets the learning result paging. + /// + public PagingViewModel MyLearningPaging { get; set; } + + /// + /// sets the list of type checkboxes. + /// + /// The . + public List TypeFilterCheckbox() + { + var checkboxes = new List() + { + new CheckboxListItemViewModel("Article", "Article", null), + new CheckboxListItemViewModel("Assessment", "Assessment", null), + new CheckboxListItemViewModel("Audio", "Audio", null), + new CheckboxListItemViewModel("Case", "Case", null), + new CheckboxListItemViewModel("Elearning", "elearning", null), + new CheckboxListItemViewModel("File", "File", null), + new CheckboxListItemViewModel("Html", "HTML", null), + new CheckboxListItemViewModel("Image", "Image", null), + new CheckboxListItemViewModel("Video", "Video", null), + new CheckboxListItemViewModel("Weblink", "Weblink", null), + new CheckboxListItemViewModel("Courses", "Courses", null), + }; + return checkboxes; + } + } +} diff --git a/LearningHub.Nhs.WebUI/Models/NavigationModel.cs b/LearningHub.Nhs.WebUI/Models/NavigationModel.cs index 950343bde..25b51671c 100644 --- a/LearningHub.Nhs.WebUI/Models/NavigationModel.cs +++ b/LearningHub.Nhs.WebUI/Models/NavigationModel.cs @@ -74,5 +74,10 @@ public class NavigationModel /// Gets or sets a value indicating whether to show Browse Catalogues. /// 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..2ce51c9ce --- /dev/null +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/MyAccountPersonalDetailsViewModel.cs @@ -0,0 +1,72 @@ +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. + /// + [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. + /// + [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/Models/UserProfile/UserProfileSummaryViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/UserProfileSummaryViewModel.cs index 38f821c59..69e317be1 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/UserProfileSummaryViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/UserProfileSummaryViewModel.cs @@ -146,5 +146,10 @@ public class UserProfileSummaryViewModel /// Gets or sets the new primary email address. /// public string NewPrimaryEmailAddress { get; set; } + + /// + /// Gets or sets the location name without sub name. + /// + public string LocationName { get; set; } } } diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/UserWorkPlaceUpdateViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/UserWorkPlaceUpdateViewModel.cs index dd7652194..add909fc6 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/UserWorkPlaceUpdateViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/UserWorkPlaceUpdateViewModel.cs @@ -25,7 +25,7 @@ public class UserWorkPlaceUpdateViewModel : PagingViewModel /// /// Gets or sets the selected work place id. /// - public int? SelectedWorkPlaceId { get; set; } + public string SelectedWorkPlaceId { get; set; } /// /// Gets or sets the WorkPlaceList. 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 @@