@@ -78,10 +81,14 @@
SectionTemplateType: SectionTemplateType,
pageSectionDetail: null as PageSectionDetailModel,
disableVideoControl: false,
+ displayAVFlag: false,
+ audioVideoUnavailableView : '' as string,
};
},
created() {
this.load();
+ this.getDisplayAVFlag();
+ this.getAudioVideoUnavailableView();
},
computed: {
getStyle() {
@@ -125,7 +132,7 @@
returnClass = "information-page__text-container--no-padding-right";
}
}
- return returnClass;
+ return returnClass;
},
getDescription() {
if (this.section.description) {
@@ -138,50 +145,60 @@
},
isRightSectionLayout() {
return this.section.sectionLayoutType == SectionLayoutType.Right;
- }
+ },
},
methods: {
+ getDisplayAVFlag() {
+ contentData.getDisplayAVFlag().then(response => {
+ this.displayAVFlag = response;
+ });
+ },
+ getAudioVideoUnavailableView() {
+ contentData.getAVUnavailableView().then(response => {
+ this.audioVideoUnavailableView = response;
+ });
+ },
load() {
if (this.sectionTemplateType === SectionTemplateType.Video) {
- contentData.getPageSectionDetailVideo(this.section.id).then(response => {
- this.pageSectionDetail = response;
+ contentData.getPageSectionDetailVideo(this.section.id).then(response => {
+ this.pageSectionDetail = response;
- if (!this.pageSectionDetail.videoAsset)
- return;
+ if (!this.pageSectionDetail.videoAsset)
+ return;
- const id = 'azureMediaPlayer' + this.pageSectionDetail.id;
- let azureMediaPlayer = amp(id);
+ const id = 'azureMediaPlayer' + this.pageSectionDetail.id;
+ let azureMediaPlayer = amp(id);
- if (this.pageSectionDetail.videoAsset.azureMediaAsset) {
- $(`#${id}`).css({ 'height': '', 'border': '1px solid #768692' });
- this.disableVideoControl = false;
- } else {
- this.disableVideoControl = true;
- }
+ if (this.pageSectionDetail.videoAsset.azureMediaAsset) {
+ $(`#${id}`).css({ 'height': '', 'border': '1px solid #768692' });
+ this.disableVideoControl = false;
+ } else {
+ this.disableVideoControl = true;
+ }
- if (this.pageSectionDetail.videoAsset.thumbnailImageFile) {
- azureMediaPlayer.poster(`/file/download/${this.pageSectionDetail.videoAsset.thumbnailImageFile.filePath}/${this.pageSectionDetail.videoAsset.thumbnailImageFile.fileName}`);
- }
- if (this.pageSectionDetail.videoAsset.azureMediaAsset && this.pageSectionDetail.videoAsset.closedCaptionsFile) {
- azureMediaPlayer.src([{
- type: "application/vnd.ms-sstr+xml",
- src: this.pageSectionDetail.videoAsset.azureMediaAsset.locatorUri,
- protectionInfo: [{ type: 'AES', authenticationToken: `Bearer=${this.pageSectionDetail.videoAsset.azureMediaAsset.authenticationToken}` }]
- }],
- [{ kind: "captions", src: `/file/download/${this.pageSectionDetail.videoAsset.closedCaptionsFile.filePath}/${this.pageSectionDetail.videoAsset.closedCaptionsFile.fileName}`, srclang: "en", label: "english" }]);
- }
- else if (this.pageSectionDetail.videoAsset.azureMediaAsset && !this.pageSectionDetail.videoAsset.closedCaptionsFile) {
- azureMediaPlayer.src([{
- type: "application/vnd.ms-sstr+xml",
- src: this.pageSectionDetail.videoAsset.azureMediaAsset.locatorUri,
- protectionInfo: [{ type: 'AES', authenticationToken: `Bearer=${this.pageSectionDetail.videoAsset.azureMediaAsset.authenticationToken}` }]
- }]);
- }
- });
- } else {
- contentData.getPageSectionDetail(this.section.id).then(x => this.pageSectionDetail = x);
- }
- },
+ if (this.pageSectionDetail.videoAsset.thumbnailImageFile) {
+ azureMediaPlayer.poster(`/file/download/${this.pageSectionDetail.videoAsset.thumbnailImageFile.filePath}/${this.pageSectionDetail.videoAsset.thumbnailImageFile.fileName}`);
+ }
+ if (this.pageSectionDetail.videoAsset.azureMediaAsset && this.pageSectionDetail.videoAsset.closedCaptionsFile) {
+ azureMediaPlayer.src([{
+ type: "application/vnd.ms-sstr+xml",
+ src: this.pageSectionDetail.videoAsset.azureMediaAsset.locatorUri,
+ protectionInfo: [{ type: 'AES', authenticationToken: `Bearer=${this.pageSectionDetail.videoAsset.azureMediaAsset.authenticationToken}` }]
+ }],
+ [{ kind: "captions", src: `/file/download/${this.pageSectionDetail.videoAsset.closedCaptionsFile.filePath}/${this.pageSectionDetail.videoAsset.closedCaptionsFile.fileName}`, srclang: "en", label: "english" }]);
+ }
+ else if (this.pageSectionDetail.videoAsset.azureMediaAsset && !this.pageSectionDetail.videoAsset.closedCaptionsFile) {
+ azureMediaPlayer.src([{
+ type: "application/vnd.ms-sstr+xml",
+ src: this.pageSectionDetail.videoAsset.azureMediaAsset.locatorUri,
+ protectionInfo: [{ type: 'AES', authenticationToken: `Bearer=${this.pageSectionDetail.videoAsset.azureMediaAsset.authenticationToken}` }]
+ }]);
+ }
+ });
+ } else {
+ contentData.getPageSectionDetail(this.section.id).then(x => this.pageSectionDetail = x);
+ }
+ },
getAESProtection(token: string): string {
var aesProtectionInfo = '{"protectionInfo": [{"type": "AES", "authenticationToken":"Bearer=' + token + '"}], "streamingFormats":["SMOOTH","DASH"]}';
return aesProtectionInfo;
@@ -198,7 +215,7 @@
},
watch: {
section() {
- this.load();
+ this.load();
}
}
})
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/contentState.ts b/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/contentState.ts
index af39cb191..32777ec0b 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/contentState.ts
+++ b/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/contentState.ts
@@ -25,7 +25,8 @@ export class State {
isVideoFileValid: boolean;
isTranscriptFileValid: boolean;
isCaptionFileValid: boolean;
- isThumbnailFileValid: boolean;
+ isThumbnailFileValid: boolean;
+ getAVUnavailableView: string = '';
}
const state = new State();
@@ -37,7 +38,10 @@ class ApiRequest {
const mutations = {
async populateUploadSettings(state: State) {
state.uploadSettings = await contentData.getUploadSettings();
- },
+ },
+ async populateAVUnavailableView(state: State) {
+ state.getAVUnavailableView = await contentData.getAVUnavailableView();
+ },
setCurrentUserName(state: State, payload: string) {
state.currentUserName = payload;
},
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/pageVideoSection.vue b/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/pageVideoSection.vue
index 216daecd7..74e0ab031 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/pageVideoSection.vue
+++ b/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/content/pageVideoSection.vue
@@ -66,7 +66,12 @@
-
+
+
+
Feature Video
@@ -284,7 +289,8 @@ Vue.use(Vuelidate as any);
deleteWarning: false,
fileDeleteWarning: false,
fileOrTypeToBeDeleted: 0,
- videoErrorMessage: ''
+ videoErrorMessage: '',
+ addAVFlag: false
}
},
validations: {
@@ -294,7 +300,9 @@ Vue.use(Vuelidate as any);
}
},
async created() {
- this.$store.commit('populateUploadSettings');
+ this.$store.commit('populateUploadSettings');
+ this.$store.commit('populateAVUnavailableView');
+ this.getAddAudioVideoFlag();
const pageSectionId = this.$route.params.sectionId;
@@ -348,7 +356,10 @@ Vue.use(Vuelidate as any);
},
videoAsset(): VideoAssetModel {
return this.$store.state.pageSectionDetail.videoAsset;
- }
+ },
+ audioVideoUnavailableView(): string {
+ return this.$store.state.getAVUnavailableView;
+ },
},
methods: {
setSectionLayoutType(sectionLayoutType: SectionLayoutType) {
@@ -492,7 +503,12 @@ Vue.use(Vuelidate as any);
this.fileErrorType = FileErrorTypeEnum.NoError
this.fileUploadServerError = '';
$('#fileUpload').val(null);
- },
+ },
+ getAddAudioVideoFlag() {
+ contentData.getAddAVFlag().then(response => {
+ this.addAVFlag = response;
+ });
+ },
},
});
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/data/content.ts b/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/data/content.ts
index e5d06dbf3..4af805bad 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/data/content.ts
+++ b/AdminUI/LearningHub.Nhs.AdminUI/Scripts/vuesrc/data/content.ts
@@ -241,6 +241,38 @@ const updateVideoAsset = async function (videoAsset: VideoAssetModel): Promise {
+ return await axios.get('/Resource/GetAddAVFlag')
+ .then(response => {
+ return response.data;
+ })
+ .catch(e => {
+ console.log('getAddAVFlag:' + e);
+ throw e;
+ });
+};
+
+const getDisplayAVFlag = async function (): Promise {
+ return await axios.get('/Resource/GetDisplayAVFlag')
+ .then(response => {
+ return response.data;
+ })
+ .catch(e => {
+ console.log('getDisplayAVFlag:' + e);
+ throw e;
+ });
+};
+
+const getAVUnavailableView = async function (): Promise {
+ return await axios.get('/Resource/GetAVUnavailableView')
+ .then(response => {
+ return response.data;
+ })
+ .catch(e => {
+ console.error('Error fetching shared partial view:', e)
+ throw e;
+ });
+};
export const contentData = {
getUploadSettings,
@@ -260,5 +292,8 @@ export const contentData = {
createPageSection,
updatePageSectionDetail,
getPageSectionDetailVideo,
- updateVideoAsset
+ updateVideoAsset,
+ getAddAVFlag,
+ getDisplayAVFlag,
+ getAVUnavailableView
};
\ No newline at end of file
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs b/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs
index 3b1cd833f..0b115922f 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs
+++ b/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs
@@ -32,6 +32,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
+ using Microsoft.FeatureManagement;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
@@ -219,6 +220,8 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur
{
options.Filters.Add(typeof(CheckInitialLogonFilter));
});
+
+ services.AddFeatureManagement();
}
private static async Task UserSessionBegins(TokenValidatedContext context)
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Views/Catalogue/Edit.cshtml b/AdminUI/LearningHub.Nhs.AdminUI/Views/Catalogue/Edit.cshtml
index eb2d3312c..15013bb91 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/Views/Catalogue/Edit.cshtml
+++ b/AdminUI/LearningHub.Nhs.AdminUI/Views/Catalogue/Edit.cshtml
@@ -138,7 +138,6 @@
Description
- You have 1800 characters remaining
@@ -413,13 +412,6 @@
var editorData = editor.getData();
var data = $("
").html(editorData).text();
var textData = data.replace(/\s\n\n/g, ' ').replace(/\n\n/g, ' ').replace(/\s\n/g, '').replace(/\n/g, '');
- var remaining = 1800 - textData.length;
-
- if (remaining >= 0) {
- $('#with-hint-info').text("You have " + remaining + " characters remaining").removeClass('text-danger');
- } else {
- $('#with-hint-info').text("You have " + (-1 * remaining) + " character too many").addClass('text-danger');
- }
});
editor.fire('change');
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Views/Shared/_AudioVideoUnavailable.cshtml b/AdminUI/LearningHub.Nhs.AdminUI/Views/Shared/_AudioVideoUnavailable.cshtml
new file mode 100644
index 000000000..b8e71596e
--- /dev/null
+++ b/AdminUI/LearningHub.Nhs.AdminUI/Views/Shared/_AudioVideoUnavailable.cshtml
@@ -0,0 +1,9 @@
+
+
+
+ Important:
+ Video and audio unavailable
+
+
+
The video and audio upload and streaming services on the Learning Hub platform are temporarily unavailable. We are working to resolve this as quickly as possible.
+
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Views/User/_UserLearningRecord.cshtml b/AdminUI/LearningHub.Nhs.AdminUI/Views/User/_UserLearningRecord.cshtml
index e47a5b66a..7dafcfd9b 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/Views/User/_UserLearningRecord.cshtml
+++ b/AdminUI/LearningHub.Nhs.AdminUI/Views/User/_UserLearningRecord.cshtml
@@ -81,36 +81,48 @@
- @if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Completed)
+ @if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Completed.ToString())
{
Completed
}
- else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Passed)
+ else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == "Viewed")
+ {
+
+ Viewed
+
+ }
+ else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Passed.ToString())
{
Passed
}
- else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Downloaded)
+ else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Downloaded.ToString())
{
-
+
Downloaded
}
- else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.InProgress)
+ else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.InProgress.ToString())
{
- Incomplete
+ In progress
}
- else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Failed)
+ else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Failed.ToString())
{
Failed
}
+ else if (LearningActivityHelper.GetActivityStatus(userLearningRecord) == ActivityStatusEnum.Launched.ToString())
+ {
+
+ Launched
+
+ }
diff --git a/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json b/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json
index 1deeae8b4..4f68451d4 100644
--- a/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json
+++ b/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json
@@ -51,5 +51,9 @@
"NLogDb": "",
"LearningHubRedis": ""
},
- "APPINSIGHTS_INSTRUMENTATIONKEY": ""
+ "APPINSIGHTS_INSTRUMENTATIONKEY": "",
+ "FeatureManagement": {
+ "AddAudioVideo": true,
+ "DisplayAudioVideo": true
+ }
}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Configuration/Settings.cs b/LearningHub.Nhs.WebUI/Configuration/Settings.cs
index 0ef2e69af..7797a36c2 100644
--- a/LearningHub.Nhs.WebUI/Configuration/Settings.cs
+++ b/LearningHub.Nhs.WebUI/Configuration/Settings.cs
@@ -151,6 +151,16 @@ public Settings()
///
public string AzureFileStorageConnectionString { get; set; }
+ ///
+ /// Gets or sets the AzureSourceFileStorageConnectionString.
+ ///
+ public string AzureSourceArchiveStorageConnectionString { get; set; }
+
+ ///
+ /// Gets or sets the AzurePurgedFileStorageConnectionString.
+ ///
+ public string AzureContentArchiveStorageConnectionString { get; set; }
+
///
/// Gets or sets the AzureFileStorageResourceShareName.
///
diff --git a/LearningHub.Nhs.WebUI/Controllers/AccountController.cs b/LearningHub.Nhs.WebUI/Controllers/AccountController.cs
index 2f000ea71..dac3a38e9 100644
--- a/LearningHub.Nhs.WebUI/Controllers/AccountController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/AccountController.cs
@@ -953,7 +953,6 @@ public async Task
CreateAccountWorkPlaceSearch()
public async Task CreateAccountWorkPlace(AccountCreationViewModel accountCreationViewModel)
{
var accountCreation = await this.multiPageFormService.GetMultiPageFormData(MultiPageFormDataFeature.AddRegistrationPrompt, this.TempData);
-
if (string.IsNullOrWhiteSpace(accountCreationViewModel.FilterText))
{
if (!string.IsNullOrWhiteSpace(accountCreation.LocationId))
@@ -1265,10 +1264,11 @@ private async Task GetAccountConfirmationDetails(Ac
var employer = await this.locationService.GetByIdAsync(int.TryParse(accountCreationViewModel.LocationId, out int primaryEmploymentId) ? primaryEmploymentId : 0);
var region = await this.regionService.GetAllAsync();
var specialty = await this.specialtyService.GetSpecialtiesAsync();
- var role = await this.jobRoleService.GetPagedFilteredAsync(accountCreationViewModel.CurrentRoleName, accountCreationViewModel.CurrentPageIndex, UserRegistrationContentPageSize);
- if (role.Item1 > 0)
+
+ var role = await this.jobRoleService.GetFilteredAsync(accountCreationViewModel.CurrentRoleName);
+ if (role.Count > 0)
{
- accountCreationViewModel.CurrentRoleName = role.Item2.FirstOrDefault(x => x.Id == int.Parse(accountCreationViewModel.CurrentRole)).NameWithStaffGroup;
+ accountCreationViewModel.CurrentRoleName = role.FirstOrDefault(x => x.Id == int.Parse(accountCreationViewModel.CurrentRole)).NameWithStaffGroup;
}
var grade = await this.gradeService.GetGradesForJobRoleAsync(int.TryParse(accountCreationViewModel.CurrentRole, out int roleId) ? roleId : 0);
diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs
index 5bacf44d1..279bda210 100644
--- a/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs
@@ -1,6 +1,8 @@
namespace LearningHub.Nhs.WebUI.Controllers.Api
{
using System;
+ using System.Collections.Generic;
+ using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
@@ -222,7 +224,16 @@ public async Task DeleteResourceKeywordAsync([FromBody] KeywordDel
[Route("DeleteResourceVersion/{resourceversionId}")]
public async Task DeleteResourceVersion(int resourceVersionId)
{
+ var associatedFile = await this.resourceService.GetObsoleteResourceFile(resourceVersionId, true);
var validationResult = await this.contributeService.DeleteResourceVersionAsync(resourceVersionId);
+ if (validationResult.IsValid)
+ {
+ if (associatedFile.Any())
+ {
+ _ = Task.Run(async () => { await this.fileService.PurgeResourceFile(null, associatedFile); });
+ }
+ }
+
return this.Ok(validationResult);
}
@@ -330,7 +341,19 @@ public ActionResult GetSettings()
[Route("PublishResourceVersion")]
public async Task PublishResourceVersionAsync([FromBody] PublishViewModel publishViewModel)
{
+ var associatedResource = await this.resourceService.GetResourceVersionExtendedAsync(publishViewModel.ResourceVersionId);
var validationResult = await this.contributeService.SubmitResourceVersionForPublishAsync(publishViewModel);
+ if (validationResult.IsValid)
+ {
+ if (associatedResource.ResourceTypeEnum != ResourceTypeEnum.Scorm && associatedResource.ResourceTypeEnum != ResourceTypeEnum.Html)
+ {
+ var obsoleteFiles = await this.resourceService.GetObsoleteResourceFile(publishViewModel.ResourceVersionId);
+ if (obsoleteFiles.Any())
+ {
+ await this.fileService.PurgeResourceFile(null, obsoleteFiles);
+ }
+ }
+ }
return this.Ok(validationResult);
}
diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/ResourceController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/ResourceController.cs
index c61201d4c..7f0c1feee 100644
--- a/LearningHub.Nhs.WebUI/Controllers/Api/ResourceController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/Api/ResourceController.cs
@@ -101,7 +101,7 @@ public async Task DownloadResourceAndRecordActivity(int resourceV
ResourceVersionId = resourceVersionId,
NodePathId = nodePathId,
ActivityStart = DateTime.UtcNow, // TODO: What about user's timezone offset when Javascript is disabled? Needs JavaScript.
- ActivityStatus = ActivityStatusEnum.Downloaded,
+ ActivityStatus = ActivityStatusEnum.Completed,
};
await this.activityService.CreateResourceActivityAsync(activity);
@@ -128,7 +128,7 @@ public async Task NavigateToWeblinkAndRecordActivity(int resource
ResourceVersionId = resourceVersionId,
NodePathId = nodePathId,
ActivityStart = DateTime.UtcNow, // TODO: What about user's timezone offset when Javascript is disabled? Needs JavaScript.
- ActivityStatus = ActivityStatusEnum.Launched,
+ ActivityStatus = ActivityStatusEnum.Completed,
};
await this.activityService.CreateResourceActivityAsync(activity);
diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs
index 6f053036c..66516430e 100644
--- a/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs
@@ -230,6 +230,11 @@ private async Task Commit(SCO scoObject)
try
{
var activeContent = this.userService.GetActiveContentAsync().Result;
+ ////if (activeContent.Count == 0)
+ ////{
+ //// return false;
+ ////}
+
if (!activeContent.Any(ac => ac.ScormActivityId == scoObject.InstanceId))
{
throw new Exception($"User does not have ActiveContent for ScormActivityId={scoObject.InstanceId}");
@@ -260,6 +265,11 @@ private async Task Commit(SCO scoObject)
// Persist update.
await this.activityService.UpdateScormActivityAsync(scoObject);
+ ////if (scoObject.LessonStatusId == ScormLessionStatus.ActivityStatusId(ScormLessionStatus.Completed) || scoObject.LessonStatusId == ScormLessionStatus.ActivityStatusId(ScormLessionStatus.Passed))
+ ////{
+ //// await this.activityService.CompleteScormActivity(scoObject);
+ ////}
+
return true;
}
catch (Exception ex)
diff --git a/LearningHub.Nhs.WebUI/Controllers/HomeController.cs b/LearningHub.Nhs.WebUI/Controllers/HomeController.cs
index daa8612ee..f524fe458 100644
--- a/LearningHub.Nhs.WebUI/Controllers/HomeController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/HomeController.cs
@@ -12,6 +12,7 @@ namespace LearningHub.Nhs.WebUI.Controllers
using LearningHub.Nhs.Models.Extensions;
using LearningHub.Nhs.WebUI.Configuration;
using LearningHub.Nhs.WebUI.Filters;
+ using LearningHub.Nhs.WebUI.Helpers;
using LearningHub.Nhs.WebUI.Interfaces;
using LearningHub.Nhs.WebUI.Models;
using Microsoft.ApplicationInsights.AspNetCore;
@@ -23,6 +24,7 @@ namespace LearningHub.Nhs.WebUI.Controllers
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+ using Microsoft.FeatureManagement;
using Settings = LearningHub.Nhs.WebUI.Configuration.Settings;
///
@@ -36,6 +38,7 @@ public class HomeController : BaseController
private readonly IUserService userService;
private readonly IDashboardService dashboardService;
private readonly IContentService contentService;
+ private readonly IFeatureManager featureManager;
///
/// Initializes a new instance of the class.
@@ -49,6 +52,7 @@ public class HomeController : BaseController
/// Auth config.
/// Dashboard service.
/// Content service.
+ /// featureManager.
public HomeController(
IHttpClientFactory httpClientFactory,
IWebHostEnvironment hostingEnvironment,
@@ -58,7 +62,8 @@ public HomeController(
IResourceService resourceService,
LearningHubAuthServiceConfig authConfig,
IDashboardService dashboardService,
- IContentService contentService)
+ IContentService contentService,
+ IFeatureManager featureManager)
: base(hostingEnvironment, httpClientFactory, logger, settings.Value)
{
this.authConfig = authConfig;
@@ -66,6 +71,7 @@ public HomeController(
this.resourceService = resourceService;
this.dashboardService = dashboardService;
this.contentService = contentService;
+ this.featureManager = featureManager;
}
///
@@ -367,6 +373,7 @@ private async Task GetLandingPageContent(bool preview = fa
var model = new LandingPageViewModel { PageSectionDetailViewModels = new List() };
var pageViewModel = await this.contentService.GetPageByIdAsync(1, preview);
model.PageViewModel = pageViewModel;
+ model.DisplayAudioVideo = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.DisplayAudioVideoResource)).Result;
if (pageViewModel != null && pageViewModel.PageSections.Any())
{
foreach (var item in pageViewModel.PageSections)
diff --git a/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs b/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs
index 1061fd44e..c583859bb 100644
--- a/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/MyLearningController.cs
@@ -129,6 +129,8 @@ public async Task Index(MyLearningViewModel learningRequest = nul
Passed = learningRequest.Passed,
Failed = learningRequest.Failed,
Downloaded = learningRequest.Downloaded,
+ Viewed = learningRequest.Viewed,
+ Launched = learningRequest.Launched,
CertificateEnabled = learningRequest.CertificateEnabled,
};
diff --git a/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs b/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs
index 4ad026334..7a1245acc 100644
--- a/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs
+++ b/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs
@@ -23,6 +23,7 @@
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
+ using Microsoft.FeatureManagement;
///
/// Defines the .
@@ -41,6 +42,7 @@ public class ResourceController : BaseController
private readonly IMyLearningService myLearningService;
private readonly IFileService fileService;
private readonly ICacheService cacheService;
+ private readonly IFeatureManager featureManager;
///
/// Initializes a new instance of the class.
@@ -60,6 +62,7 @@ public class ResourceController : BaseController
/// The hierarchyService.
/// The fileService.
/// The cacheService.
+ /// The Feature flag manager.
public ResourceController(
IWebHostEnvironment hostingEnvironment,
ILogger logger,
@@ -75,7 +78,8 @@ public ResourceController(
IMyLearningService myLearningService,
IHierarchyService hierarchyService,
IFileService fileService,
- ICacheService cacheService)
+ ICacheService cacheService,
+ IFeatureManager featureManager)
: base(hostingEnvironment, httpClientFactory, logger, settings.Value)
{
this.azureMediaService = azureMediaService;
@@ -89,6 +93,7 @@ public ResourceController(
this.myLearningService = myLearningService;
this.fileService = fileService;
this.cacheService = cacheService;
+ this.featureManager = featureManager;
}
///
@@ -108,6 +113,8 @@ public async Task Index(int resourceReferenceId, bool? acceptSens
this.ViewBag.MediaActivityPlayingEventIntervalSeconds = this.Settings.MediaActivityPlayingEventIntervalSeconds;
this.ViewBag.KeepUserSessionAliveIntervalSeconds = Convert.ToInt32(this.Settings.KeepUserSessionAliveIntervalMins) * 60000;
this.ViewBag.SupportUrl = this.Settings.SupportUrls.SupportForm;
+ var displayAVResourceFlag = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.DisplayAudioVideoResource)).Result;
+ this.ViewBag.DisplayAVResourceFlag = displayAVResourceFlag;
if (resourceReferenceId == 0)
{
@@ -173,14 +180,14 @@ public async Task Index(int resourceReferenceId, bool? acceptSens
}
// For article/image resources, immediately record the resource activity for this user.
- if ((resource.ResourceTypeEnum == ResourceTypeEnum.Article || resource.ResourceTypeEnum == ResourceTypeEnum.Image) && ((resource.SensitiveContent && acceptSensitiveContent.HasValue && acceptSensitiveContent.Value) || !resource.SensitiveContent) && canAccessResource)
+ if ((resource.ResourceTypeEnum == ResourceTypeEnum.Article || resource.ResourceTypeEnum == ResourceTypeEnum.Image) && (!resource.SensitiveContent))
{
var activity = new CreateResourceActivityViewModel()
{
ResourceVersionId = resource.ResourceVersionId,
NodePathId = resource.NodePathId,
ActivityStart = DateTime.UtcNow, // TODO: What about user's timezone offset when Javascript is disabled? Needs JavaScript.
- ActivityStatus = ActivityStatusEnum.Launched,
+ ActivityStatus = ActivityStatusEnum.Completed,
};
await this.activityService.CreateResourceActivityAsync(activity);
}
@@ -400,11 +407,17 @@ public IActionResult UnpublishConfirm(ResourceIndexViewModel viewModel)
[Route("Resource/UnpublishConfirmPost")]
public async Task UnpublishConfirm(ResourceUnpublishConfirmViewModel viewModel)
{
+ var associatedFile = await this.resourceService.GetResourceVersionExtendedAsync(viewModel.ResourceVersionId);
var validationResult = await this.resourceService.UnpublishResourceVersionAsync(viewModel.ResourceVersionId);
var catalogue = await this.catalogueService.GetCatalogueAsync(viewModel.CatalogueNodeVersionId);
if (validationResult.IsValid)
{
+ if (associatedFile.ScormDetails != null || associatedFile.HtmlDetails != null)
+ {
+ _ = Task.Run(async () => { await this.fileService.PurgeResourceFile(associatedFile, null); });
+ }
+
if (viewModel.CatalogueNodeVersionId == 1)
{
return this.Redirect("/my-contributions/unpublished");
@@ -472,7 +485,7 @@ public async Task HtmlResourceContent(int resourceReferenceId, st
ResourceVersionId = resourceVersionId,
NodePathId = nodePathId,
ActivityStart = DateTime.UtcNow, // TODO: What about user's timezone offset when Javascript is disabled? Needs JavaScript.
- ActivityStatus = ActivityStatusEnum.Launched,
+ ActivityStatus = ActivityStatusEnum.Completed,
};
await this.activityService.CreateResourceActivityAsync(activity);
}
@@ -501,5 +514,32 @@ public async Task HtmlResourceContent(int resourceReferenceId, st
return this.Ok(this.Content("No file found"));
}
+
+ ///
+ /// The GetAVUnavailableView.
+ ///
+ /// partial view.
+ [Route("Resource/GetAVUnavailableView")]
+ [HttpGet("GetAVUnavailableView")]
+ public IActionResult GetAVUnavailableView()
+ {
+ return this.PartialView("_AudioVideoUnavailable");
+ }
+
+ ///
+ /// The GetContributeAVResourceFlag.
+ ///
+ /// Return Contribute Resource AV Flag.
+ [Route("Resource/GetContributeAVResourceFlag")]
+ [HttpGet("GetContributeAVResourceFlag")]
+ public bool GetContributeResourceAVFlag() => this.featureManager.IsEnabledAsync(FeatureFlags.ContributeAudioVideoResource).Result;
+
+ ///
+ /// The GetDisplayAVResourceFlag.
+ ///
+ /// Return Display AV Resource Flag.
+ [Route("Resource/GetDisplayAVResourceFlag")]
+ [HttpGet("GetDisplayAVResourceFlag")]
+ public bool GetDisplayAVResourceFlag() => this.featureManager.IsEnabledAsync(FeatureFlags.DisplayAudioVideoResource).Result;
}
}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Helpers/FeatureFlags.cs b/LearningHub.Nhs.WebUI/Helpers/FeatureFlags.cs
new file mode 100644
index 000000000..f4b01af4d
--- /dev/null
+++ b/LearningHub.Nhs.WebUI/Helpers/FeatureFlags.cs
@@ -0,0 +1,18 @@
+namespace LearningHub.Nhs.WebUI.Helpers
+{
+ ///
+ /// Defines the .
+ ///
+ public static class FeatureFlags
+ {
+ ///
+ /// The ContributeAudioVideoResource.
+ ///
+ public const string ContributeAudioVideoResource = "ContributeAudioVideoResource";
+
+ ///
+ /// The DisplayAudioVideoResource.
+ ///
+ public const string DisplayAudioVideoResource = "DisplayAudioVideoResource";
+ }
+}
diff --git a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs
index 3f42256e1..03e93fc07 100644
--- a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs
+++ b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs
@@ -110,7 +110,7 @@ public static string GetResourceTypeIconClass(ResourceTypeEnum resourceType)
/// The resource type.
/// The media duration in milliseconds.
/// The resource type name, and duration if applicable.
- public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType, int? durationInMilliseconds)
+ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType, int? durationInMilliseconds = 0)
{
switch (resourceType)
{
@@ -119,7 +119,9 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType
case ResourceTypeEnum.Article:
return "Article";
case ResourceTypeEnum.Audio:
- return "Audio - " + GetDurationText(durationInMilliseconds.Value);
+ string durationText = GetDurationText(durationInMilliseconds ?? 0);
+ durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText;
+ return "Audio" + durationText;
case ResourceTypeEnum.Equipment:
return "Equipment";
case ResourceTypeEnum.Image:
@@ -127,7 +129,9 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType
case ResourceTypeEnum.Scorm:
return "elearning";
case ResourceTypeEnum.Video:
- return "Video - " + GetDurationText(durationInMilliseconds.Value);
+ durationText = GetDurationText(durationInMilliseconds ?? 0);
+ durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText;
+ return "Video" + durationText;
case ResourceTypeEnum.WebLink:
return "Web link";
case ResourceTypeEnum.GenericFile:
diff --git a/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs
index 571cdfb5f..f77383f0c 100644
--- a/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs
+++ b/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs
@@ -127,7 +127,7 @@ public static string GetResourceTypeVerb(this ActivityDetailedItemViewModel acti
/// The .
public static string GetActivityStatusDisplayText(this ActivityDetailedItemViewModel activityDetailedItemViewModel)
{
- if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Launched
+ if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Completed
&& (activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.Article
|| activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.WebLink
|| activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.Image
@@ -136,7 +136,7 @@ public static string GetActivityStatusDisplayText(this ActivityDetailedItemViewM
{
return "Completed";
}
- else if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Launched
+ else if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Completed
&& (activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.GenericFile))
{
return "Downloaded";
@@ -163,36 +163,33 @@ public static string GetActivityStatusDisplayText(this ActivityDetailedItemViewM
///
/// The activityDetailedItemViewModel.
/// The .
- public static ActivityStatusEnum GetActivityStatus(this ActivityDetailedItemViewModel activityDetailedItemViewModel)
+ public static string GetActivityStatus(this ActivityDetailedItemViewModel activityDetailedItemViewModel)
{
- if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Launched
+ if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Completed
&& (activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.Article
- || activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.WebLink
|| activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.Image
|| activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.Html
|| activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.Case))
{
- return ActivityStatusEnum.Completed;
+ return "Viewed";
}
- else if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Launched
- && (activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.GenericFile))
+ else if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Completed
+ && (activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.WebLink))
{
- return ActivityStatusEnum.Downloaded;
+ return "Launched";
}
- else if (activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.Assessment)
+ else if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Completed
+ && (activityDetailedItemViewModel.ResourceType == ResourceTypeEnum.GenericFile))
{
- if (activityDetailedItemViewModel.Complete)
- {
- return activityDetailedItemViewModel.ScorePercentage >= activityDetailedItemViewModel.AssessmentDetails.PassMark ? ActivityStatusEnum.Passed : ActivityStatusEnum.Failed;
- }
- else
- {
- return activityDetailedItemViewModel.ScorePercentage >= activityDetailedItemViewModel.AssessmentDetails.PassMark ? ActivityStatusEnum.Passed : ActivityStatusEnum.InProgress;
- }
+ return ActivityStatusEnum.Downloaded.ToString();
+ }
+ else if (activityDetailedItemViewModel.ActivityStatus == ActivityStatusEnum.Incomplete)
+ {
+ return ActivityStatusEnum.InProgress.ToString();
}
else
{
- return activityDetailedItemViewModel.ActivityStatus;
+ return activityDetailedItemViewModel.ActivityStatus.ToString();
}
}
diff --git a/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs b/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs
index 8351dde97..c74a1681f 100644
--- a/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs
+++ b/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs
@@ -1,8 +1,10 @@
namespace LearningHub.Nhs.WebUI.Interfaces
{
+ using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Azure.Storage.Files.Shares.Models;
+ using LearningHub.Nhs.Models.Resource;
///
/// Defines the .
@@ -41,5 +43,13 @@ public interface IFileService
/// The directoryRef.
/// The .
Task ProcessFile(Stream fileBytes, string fileName, string directoryRef = "");
+
+ ///
+ /// The PurgeResourceFile.
+ ///
+ /// The vm. .
+ /// .
+ /// The .
+ Task PurgeResourceFile(ResourceVersionExtendedViewModel vm = null, List filePaths = null);
}
}
diff --git a/LearningHub.Nhs.WebUI/Interfaces/IResourceService.cs b/LearningHub.Nhs.WebUI/Interfaces/IResourceService.cs
index fb54a2777..c09ab0704 100644
--- a/LearningHub.Nhs.WebUI/Interfaces/IResourceService.cs
+++ b/LearningHub.Nhs.WebUI/Interfaces/IResourceService.cs
@@ -282,5 +282,13 @@ public interface IResourceService
/// resource version id.
/// The .
Task DeleteAllResourceVersionProviderAsync(int resourceVersionId);
+
+ ///
+ /// The GetObsoleteResourceFile.
+ ///
+ /// The resourceVersionId.
+ /// .
+ /// The .
+ Task> GetObsoleteResourceFile(int resourceVersionId, bool deletedResource = false);
}
}
diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
index c052f2516..817199786 100644
--- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
+++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj
@@ -28,10 +28,6 @@
-
-
-
-
@@ -112,7 +108,7 @@
-
+
@@ -122,6 +118,8 @@
+
+
diff --git a/LearningHub.Nhs.WebUI/Models/LandingPageViewModel.cs b/LearningHub.Nhs.WebUI/Models/LandingPageViewModel.cs
index 1db8f021b..aa6666b55 100644
--- a/LearningHub.Nhs.WebUI/Models/LandingPageViewModel.cs
+++ b/LearningHub.Nhs.WebUI/Models/LandingPageViewModel.cs
@@ -46,5 +46,10 @@ public LandingPageViewModel()
/// Gets or sets get or sets the pageSectionDetailViewModels.
///
public List PageSectionDetailViewModels { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether gets or sets the DisplayAVFromAMS.
+ ///
+ public bool DisplayAudioVideo { get; set; }
}
}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Models/MyLearningViewModel.cs b/LearningHub.Nhs.WebUI/Models/MyLearningViewModel.cs
index b83a536e5..c7ae8692d 100644
--- a/LearningHub.Nhs.WebUI/Models/MyLearningViewModel.cs
+++ b/LearningHub.Nhs.WebUI/Models/MyLearningViewModel.cs
@@ -184,11 +184,13 @@ public List StatusFilterCheckbox()
{
var checkboxes = new List()
{
- new CheckboxListItemViewModel("Complete", "Complete", null),
- new CheckboxListItemViewModel("Incomplete", "Incomplete", null),
+ new CheckboxListItemViewModel("Complete", "Completed", null),
+ new CheckboxListItemViewModel("Incomplete", "In progress", null),
new CheckboxListItemViewModel("Passed", "Passed", null),
new CheckboxListItemViewModel("Failed", "Failed", null),
new CheckboxListItemViewModel("Downloaded", "Downloaded", null),
+ new CheckboxListItemViewModel("Viewed", "Viewed", null),
+ new CheckboxListItemViewModel("Launched", "Launched", null),
};
return checkboxes;
}
diff --git a/LearningHub.Nhs.WebUI/Models/Resource/EsrLinkViewModel.cs b/LearningHub.Nhs.WebUI/Models/Resource/EsrLinkViewModel.cs
deleted file mode 100644
index 4af72e435..000000000
--- a/LearningHub.Nhs.WebUI/Models/Resource/EsrLinkViewModel.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace LearningHub.Nhs.WebUI.Models.Resource
-{
- using LearningHub.Nhs.Models.Resource;
-
- ///
- /// Defines the .
- ///
- public class EsrLinkViewModel
- {
- ///
- /// Gets or sets the ScormContentDetails.
- ///
- public ScormContentDetailsViewModel ScormContentDetails { get; set; }
-
- ///
- /// Gets or sets the ReturnUrl.
- ///
- public string ReturnUrl { get; set; }
- }
-}
diff --git a/LearningHub.Nhs.WebUI/Models/RestrictedAccessBannerViewModel.cs b/LearningHub.Nhs.WebUI/Models/RestrictedAccessBannerViewModel.cs
index 59176251f..d229a1a88 100644
--- a/LearningHub.Nhs.WebUI/Models/RestrictedAccessBannerViewModel.cs
+++ b/LearningHub.Nhs.WebUI/Models/RestrictedAccessBannerViewModel.cs
@@ -1,9 +1,11 @@
namespace LearningHub.Nhs.WebUI.Models
{
+ using System.Collections.Generic;
using LearningHub.Nhs.Models.Catalogue;
using LearningHub.Nhs.Models.Entities.Hierarchy;
+ using LearningHub.Nhs.Models.User;
- ///
+ ///
/// Defines the .
///
public class RestrictedAccessBannerViewModel
@@ -37,5 +39,10 @@ public class RestrictedAccessBannerViewModel
/// Gets or sets the CatalogueAccessRequest if there is one.
///
public CatalogueAccessRequestViewModel CatalogueAccessRequest { get; set; }
+
+ ///
+ /// Gets or sets the current user's usergroups.
+ ///
+ public List UserGroups { get; set; }
}
}
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/activity.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/activity.ts
index bedfd27c5..bc5a08bbb 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/activity.ts
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/activity.ts
@@ -1,13 +1,12 @@
import AxiosWrapper from './axiosWrapper';
-import { ActivityStatus, MediaResourceActivityType } from './constants';
+import { ActivityStatus, MediaResourceActivityType, ResourceType } from './constants';
import { LearningHubValidationResultModel } from './models/learningHubValidationResultModel';
import 'navigator.sendbeacon';
import { AssessmentModel } from './models/contribute-resource/assessmentModel';
-import { QuestionBlockModel } from "./models/contribute-resource/blocks/questionBlockModel";
-import { BlockCollectionModel } from "./models/contribute-resource/blocks/blockCollectionModel";
import { MatchQuestionState } from "./models/mylearning/matchQuestionState";
const recordActivityLaunched = async function (
+ resourceType: ResourceType,
resourceVersionId: number,
nodePathId: number,
activityDatetime: Date,
@@ -16,7 +15,8 @@ const recordActivityLaunched = async function (
var data = {
resourceVersionId: resourceVersionId,
nodePathId: nodePathId,
- activityStatus: ActivityStatus.Launched,
+ activityStatus: (resourceType == ResourceType.ASSESSMENT || resourceType == ResourceType.VIDEO || resourceType == ResourceType.AUDIO ||
+ resourceType == ResourceType.SCORM) ? ActivityStatus.Incomplete : ActivityStatus.Completed,
activityStart: activityDatetime,
extraAttemptReason
};
@@ -37,32 +37,6 @@ const recordActivityLaunched = async function (
});
};
-
-const recordActivityDownloaded = async function (
- resourceVersionId: number,
- nodePathId: number,
- activityDatetime: Date): Promise {
-
- var data = {
- resourceVersionId: resourceVersionId,
- nodePathId: nodePathId,
- activityStatus: ActivityStatus.Downloaded,
- activityStart: activityDatetime
- };
-
- return await AxiosWrapper.axios.post('/api/activity/CreateResourceActivity', data)
- .then(response => {
- if (!response.data.isValid) {
- window.location.pathname = './Home/Error';
- }
- return response.data;
- })
- .catch(e => {
- console.log('recordActivityDownloaded:' + e);
- throw e;
- });
-};
-
const recordActivity = async function (
resourceVersionId: number,
nodePathId: number,
@@ -243,7 +217,6 @@ const recordAssessmentResourceActivityInteraction = async function (
export const activityRecorder = {
recordActivityLaunched,
- recordActivityDownloaded,
recordActivity,
recordMediaResourceActivity,
recordMediaResourceActivityInteraction,
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/constants.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/constants.ts
index 10a8d4486..4f3a44c0a 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/constants.ts
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/constants.ts
@@ -60,7 +60,8 @@ export enum ActivityStatus {
Completed = 3,
Failed = 4,
Passed = 5,
- Downloaded = 6
+ Downloaded = 6,
+ Incomplete = 7
};
export enum AccessRequestStatus {
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/SelectResourceType.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/SelectResourceType.vue
index 4fb3f6621..d43ed711a 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/SelectResourceType.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/SelectResourceType.vue
@@ -6,19 +6,23 @@
{{title}}
{{description}}
-
-
+
+ Select
+
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts
index c75681e0e..89b5e0d27 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts
@@ -55,7 +55,10 @@ export class State {
counterInterval: any = undefined;
hierarchyEdit: HierarchyEditModel = null;
hierarchyEditLoaded: boolean = false;
- userProviders : ProviderModel[] = null;
+ userProviders: ProviderModel[] = null;
+ contributeAVResourceFlag: boolean;
+ learnAVResourceFlag: boolean;
+ getAVUnavailableView: string = '';
get previousVersionExists(): boolean {
if (this.resourceDetail.currentResourceVersionId) {
@@ -242,6 +245,15 @@ const mutations = {
async populateContributeSettings(state: State) {
state.contributeSettings = await resourceData.getContributeSettings();
},
+ async populateContributeAVResourceFlag(state: State) {
+ state.contributeAVResourceFlag = await resourceData.getContributeAVResourceFlag();
+ },
+ async populateDisplayAVResourceFlag(state: State) {
+ state.learnAVResourceFlag = await resourceData.getDisplayAVResourceFlag();
+ },
+ async populateAVUnavailableView(state: State) {
+ state.getAVUnavailableView = await resourceData.getAVUnavailableView();
+ },
async populateScormDetails(state: State, payload: number) {
const scormDetail = await resourceData.getScormDetail(payload);
state.scormDetail.canDownload = scormDetail.canDownload;
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributecontainer.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributecontainer.ts
index bec5583e5..23259accb 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributecontainer.ts
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributecontainer.ts
@@ -23,6 +23,8 @@ new Vue({
},
created() {
this.$store.commit('populateContributeSettings');
+ this.$store.commit('populateContributeAVResourceFlag');
+ this.$store.commit('populateAVUnavailableView');
if (this.$route.params.rvId) {
this.$store.commit('populateResource', this.$route.params.rvId);
}
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/resource.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/resource.ts
index 13523c021..738b53ca2 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/resource.ts
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/resource.ts
@@ -502,6 +502,38 @@ const getMyContributions = async function (resourceType: ResourceType, status: V
});
};
+const getContributeAVResourceFlag = async function (): Promise
{
+ return await AxiosWrapper.axios.get('/Resource/GetContributeAVResourceFlag')
+ .then(response => {
+ return response.data;
+ })
+ .catch(e => {
+ console.log('GetContributeAVResourceFlag:' + e);
+ throw e;
+ });
+};
+
+const getDisplayAVResourceFlag = async function (): Promise {
+ return await AxiosWrapper.axios.get('/Resource/GetDisplayAVResourceFlag')
+ .then(response => {
+ return response.data;
+ })
+ .catch(e => {
+ console.log('GetDisplayAVResourceFlag:' + e);
+ throw e;
+ });
+};
+
+const getAVUnavailableView = async function (): Promise {
+ return await AxiosWrapper.axios.get('/Resource/GetAVUnavailableView')
+ .then(response => {
+ return response.data;
+ })
+ .catch(e => {
+ console.error('Error fetching shared partial view:', e)
+ throw e;
+ });
+};
export const resourceData = {
getContributeConfiguration,
@@ -541,4 +573,7 @@ export const resourceData = {
getAssessmentDetail,
duplicateBlocks,
getMyContributions,
+ getContributeAVResourceFlag,
+ getDisplayAVResourceFlag,
+ getAVUnavailableView
};
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/globalcomponents/IconButton.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/globalcomponents/IconButton.vue
index 2ff2c9110..7e644a318 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/globalcomponents/IconButton.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/globalcomponents/IconButton.vue
@@ -48,7 +48,8 @@
}"
v-bind:disabled="disabled">
+ v-bind:aria-label="ariaLabel"
+ v-bind:role="iconRole">
{{ label }}
@@ -65,6 +66,7 @@
color: String,
shape: String,
size: String,
+ iconRole: String,
},
});
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/cmiVocabulary.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/cmiVocabulary.ts
index 902bc1f01..f5123d287 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/cmiVocabulary.ts
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/cmiVocabulary.ts
@@ -18,7 +18,8 @@
Entry = 16,
Interaction = 17,
Result = 18,
- TimeLimitAction = 19
+ TimeLimitAction = 19,
+ CMIString64000 = 20
};
export enum CMIVocabularyMode {
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/scormApiModel.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/scormApiModel.ts
index 362aa0acb..8555d67d9 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/scormApiModel.ts
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/models/learningsessions/scormApiModel.ts
@@ -480,13 +480,13 @@ export class ScormApiModel {
}
}
else if (paramName === "cmi.suspend_data") {
- if (this.isValidateDataType(paramValue, CMIDataType.CMIString4096)) {
+ if (this.isValidateDataType(paramValue, CMIDataType.CMIString64000)) {
this.sco.suspendData = paramValue;
result = true;
}
}
else if (paramName === "cmi.comments") {
- if (this.isValidateDataType(paramValue, CMIDataType.CMIString4096)) {
+ if (this.isValidateDataType(paramValue, CMIDataType.CMIString64000)) {
this.sco.comments = paramValue;
result = true;
}
@@ -1019,6 +1019,11 @@ export class ScormApiModel {
response = true;
}
break;
+ case CMIDataType.CMIString64000:
+ if (value.length < 64000) {
+ response = true;
+ }
+ break;
case CMIDataType.CMITime:
if (value.match(/^\d{2}:\d{2}:\d{2}(.\d{1,2})?$/)) {
response = true;
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/CaseOrAssessmentResource.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/CaseOrAssessmentResource.vue
index e53397927..e3f75c8d8 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/CaseOrAssessmentResource.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/CaseOrAssessmentResource.vue
@@ -307,7 +307,7 @@
// Only make a new activity if the latest activity is finished
if (typeof latest.userScore === 'number') {
- const result = await activityRecorder.recordActivityLaunched(this.resourceItem.resourceVersionId, this.resourceItem.nodePathId, new Date(), reason);
+ const result = await activityRecorder.recordActivityLaunched(this.resourceItem.resourceTypeEnum, this.resourceItem.resourceVersionId, this.resourceItem.nodePathId, new Date(), reason);
this.shuffleMatchQuestionsState();
await activityRecorder.recordAssessmentResourceActivity(result.createdId, this.matchQuestionsState, reason);
}
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/ResourceContent.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/ResourceContent.vue
index 909fd8396..bfc9598f5 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/ResourceContent.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/ResourceContent.vue
@@ -205,17 +205,13 @@
methods: {
initialise(): void {
// record activity on page created for resource article
- if (this.userAuthenticated && (
- this.resourceItem.resourceTypeEnum === ResourceType.ARTICLE
- || this.resourceItem.resourceTypeEnum === ResourceType.IMAGE
- || this.resourceItem.resourceTypeEnum === ResourceType.CASE) && this.hasResourceAccess()) {
-
+ if (this.userAuthenticated && this.resourceItem.resourceTypeEnum === ResourceType.CASE) {
this.recordActivityLaunched();
}
- else if (this.userAuthenticated && this.resourceItem.resourceTypeEnum === ResourceType.ASSESSMENT && this.hasResourceAccess()) {
+ else if (this.userAuthenticated && this.resourceItem.resourceTypeEnum === ResourceType.ASSESSMENT) {
this.getCurrentAssessmentActivity();
}
- if (this.resourceItem.resourceTypeEnum === ResourceType.AUDIO || this.resourceItem.resourceTypeEnum === ResourceType.VIDEO) {
+ else if (this.resourceItem.resourceTypeEnum === ResourceType.AUDIO || this.resourceItem.resourceTypeEnum === ResourceType.VIDEO) {
window.setTimeout(this.handleResize, 100);
}
},
@@ -252,8 +248,8 @@
if (!this.activityLogged) {
this.activityLogged = true;
-
- await activityRecorder.recordActivityLaunched(this.resourceItem.resourceVersionId, this.resourceItem.nodePathId, new Date())
+ await activityRecorder.recordActivityLaunched(this.resourceItem.resourceTypeEnum, this.resourceItem.resourceVersionId, this.resourceItem.nodePathId, new Date())
+ // await activityRecorder.recordActivityLaunched(this.resourceItem.resourceVersionId, this.resourceItem.nodePathId, new Date())
.then(response => {
this.launchedResourceActivityId = response.createdId;
this.checkUserCertificateAvailability();
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/QuestionBlock.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/QuestionBlock.vue
index 6366ec7fe..20945e6f2 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/QuestionBlock.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/QuestionBlock.vue
@@ -9,7 +9,8 @@
+ :ariaLabel="isOpen ? `hide content` : `reveal content`"
+ iconRole="img">
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/SingleQuestionAnswerView.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/SingleQuestionAnswerView.vue
index 21925aa52..c325b1446 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/SingleQuestionAnswerView.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/resource/blocks/SingleQuestionAnswerView.vue
@@ -17,7 +17,8 @@
:class="getStyleFromAnswerType(answer.status)"/>
+ src="/images/medal-icon.svg"
+ alt="Medal Icon"/>
{{ answer.blockCollection.blocks[0].textBlock.content }}
diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/roadmap/roadmap.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/roadmap/roadmap.vue
index 54d0c5f75..21307a74e 100644
--- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/roadmap/roadmap.vue
+++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/roadmap/roadmap.vue
@@ -1,7 +1,7 @@
-
+
{{ item.title }}
{{ item.roadmapDate | formatDate('DD MMM YYYY') }}
diff --git a/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs b/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs
index 20582b444..dad5f5001 100644
--- a/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs
+++ b/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs
@@ -20,6 +20,7 @@
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
+ using Microsoft.FeatureManagement;
using Microsoft.IdentityModel.Logging;
///
@@ -129,6 +130,8 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur
});
services.AddControllersWithViews().AddRazorRuntimeCompilation();
+
+ services.AddFeatureManagement();
}
}
}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Services/FileService.cs b/LearningHub.Nhs.WebUI/Services/FileService.cs
index b47caf186..1aa8078e8 100644
--- a/LearningHub.Nhs.WebUI/Services/FileService.cs
+++ b/LearningHub.Nhs.WebUI/Services/FileService.cs
@@ -1,12 +1,17 @@
namespace LearningHub.Nhs.WebUI.Services
{
using System;
+ using System.Collections.Generic;
using System.IO;
+ using System.Linq;
using System.Threading.Tasks;
using Azure.Storage.Files.Shares;
using Azure.Storage.Files.Shares.Models;
+ using LearningHub.Nhs.Models.Enums;
+ using LearningHub.Nhs.Models.Resource;
using LearningHub.Nhs.WebUI.Configuration;
using LearningHub.Nhs.WebUI.Interfaces;
+ using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Options;
@@ -17,6 +22,7 @@ public class FileService : IFileService
{
private readonly Settings settings;
private ShareClient shareClient;
+ private ShareClient archiveShareClient;
///
/// Initializes a new instance of the class.
@@ -49,6 +55,50 @@ private ShareClient ShareClient
}
}
+ private ShareClient OutputArchiveShareClient
+ {
+ get
+ {
+ if (this.archiveShareClient == null)
+ {
+ var options = new ShareClientOptions();
+ options.Retry.MaxRetries = 3;
+ options.Retry.Delay = TimeSpan.FromSeconds(10);
+
+ this.archiveShareClient = new ShareClient(this.settings.AzureContentArchiveStorageConnectionString, this.settings.AzureFileStorageResourceShareName, options);
+
+ if (!this.archiveShareClient.Exists())
+ {
+ throw new Exception($"Unable to access azure content archive file storage resource {this.settings.AzureFileStorageResourceShareName}");
+ }
+ }
+
+ return this.archiveShareClient;
+ }
+ }
+
+ private ShareClient InputArchiveShareClient
+ {
+ get
+ {
+ if (this.archiveShareClient == null)
+ {
+ var options = new ShareClientOptions();
+ options.Retry.MaxRetries = 3;
+ options.Retry.Delay = TimeSpan.FromSeconds(10);
+
+ this.archiveShareClient = new ShareClient(this.settings.AzureSourceArchiveStorageConnectionString, this.settings.AzureFileStorageResourceShareName, options);
+
+ if (!this.shareClient.Exists())
+ {
+ throw new Exception($"Unable to access azure file storage resource {this.settings.AzureFileStorageResourceShareName}");
+ }
+ }
+
+ return this.archiveShareClient;
+ }
+ }
+
///
/// The DeleteChunkDirectory.
///
@@ -147,5 +197,240 @@ public async Task ProcessFile(Stream fileBytes, string fileName, string
return directoryRef;
}
+
+ ///
+ /// The PurgeResourceFile.
+ ///
+ /// The vm. .
+ /// .
+ /// The .
+ public async Task PurgeResourceFile(ResourceVersionExtendedViewModel vm = null, List filePaths = null)
+ {
+ if (filePaths != null
+ && filePaths.Any())
+ {
+ await this.MoveInPutDirectoryToArchive(filePaths);
+ return;
+ }
+
+ if (vm != null)
+ {
+ var allContentPath = new List();
+ var allFilePath = new List();
+ if (vm.ScormDetails != null && !string.IsNullOrWhiteSpace(vm.ScormDetails.ContentFilePath))
+ {
+ allContentPath.Add(vm.ScormDetails.ContentFilePath);
+ }
+ else if (vm.GenericFileDetails != null && !string.IsNullOrWhiteSpace(vm.GenericFileDetails.File.FilePath))
+ {
+ allFilePath.Add(vm.GenericFileDetails.File.FilePath);
+ }
+ else if (vm.HtmlDetails != null && !string.IsNullOrWhiteSpace(vm.HtmlDetails.ContentFilePath))
+ {
+ allContentPath.Add(vm.HtmlDetails.ContentFilePath);
+ }
+ else if (vm.ImageDetails != null && !string.IsNullOrWhiteSpace(vm.ImageDetails.File?.FilePath))
+ {
+ allFilePath.Add(vm.ImageDetails.File?.FilePath);
+ }
+ else if (vm.ArticleDetails != null)
+ {
+ var files = vm.ArticleDetails.Files.ToList();
+ if (files.Any())
+ {
+ foreach (var file in files)
+ {
+ allFilePath.Add(file.FilePath);
+ }
+ }
+ }
+ else if (vm.CaseDetails != null)
+ {
+ var blockCollection = vm.CaseDetails.BlockCollection;
+ foreach (var entry in blockCollection.Blocks)
+ {
+ if (entry.ImageCarouselBlock != null)
+ {
+ foreach (var item in entry.ImageCarouselBlock?.ImageBlockCollection?.Blocks)
+ {
+ allFilePath.Add(item?.MediaBlock?.Image?.File.FilePath);
+ }
+ }
+ else if (entry.WholeSlideImageBlock != null)
+ {
+ foreach (var item in entry.WholeSlideImageBlock.WholeSlideImageBlockItems)
+ {
+ allFilePath.Add(item?.WholeSlideImage?.File.FilePath);
+ }
+ }
+ }
+ }
+
+ // audio and video to be added
+ await this.MoveInPutDirectoryToArchive(allFilePath);
+ await this.MoveOutPutDirectoryToArchive(allContentPath);
+ }
+ }
+
+ private static async Task WaitForCopyAsync(ShareFileClient fileClient)
+ {
+ // Wait for the copy operation to complete
+ ShareFileProperties copyInfo;
+ do
+ {
+ await Task.Delay(500); // Delay before checking the status again
+ copyInfo = await fileClient.GetPropertiesAsync().ConfigureAwait(false);
+ }
+ while (copyInfo.CopyStatus == CopyStatus.Pending);
+
+ if (copyInfo.CopyStatus != CopyStatus.Success)
+ {
+ throw new InvalidOperationException($"Copy failed: {copyInfo.CopyStatus}");
+ }
+ }
+
+ private async Task MoveOutPutDirectoryToArchive(List allDirectoryRef)
+ {
+ try
+ {
+ if (allDirectoryRef.Any())
+ {
+ foreach (var directoryRef in allDirectoryRef)
+ {
+ var directory = this.ShareClient.GetDirectoryClient(directoryRef);
+ var archiveDirectory = this.OutputArchiveShareClient.GetDirectoryClient(directoryRef);
+
+ await foreach (var fileItem in directory.GetFilesAndDirectoriesAsync())
+ {
+ var sourceFileClient = directory.GetFileClient(fileItem.Name);
+
+ archiveDirectory.CreateIfNotExists();
+ if (fileItem.IsDirectory)
+ {
+ if (await archiveDirectory.GetSubdirectoryClient(fileItem.Name).ExistsAsync() == false)
+ {
+ archiveDirectory.CreateSubdirectory(fileItem.Name);
+ }
+
+ await this.MigrateSubdirectory(sourceFileClient.Path);
+ }
+ else
+ {
+ var destinationFileClient = archiveDirectory.GetFileClient(fileItem.Name);
+ var uri = sourceFileClient.GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions.Read, DateTime.UtcNow.AddHours(24));
+
+ await destinationFileClient.StartCopyAsync(uri);
+
+ await WaitForCopyAsync(destinationFileClient);
+ }
+ }
+
+ if (await directory.ExistsAsync())
+ {
+ foreach (var fileItem in directory.GetFilesAndDirectories())
+ {
+ var sourceFileClient = directory.GetFileClient(fileItem.Name);
+ if (fileItem.IsDirectory)
+ {
+ await this.DeleteSubdirectory(sourceFileClient.Path);
+ }
+ else
+ {
+ await sourceFileClient.DeleteIfExistsAsync();
+ }
+ }
+
+ await directory.DeleteAsync();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+
+ private async Task MigrateSubdirectory(string pathDirectory)
+ {
+ var sourceDirectory = this.ShareClient.GetDirectoryClient(pathDirectory);
+ var archiveDirectory = this.OutputArchiveShareClient.GetDirectoryClient(pathDirectory);
+
+ await foreach (var fileDirectory in sourceDirectory.GetFilesAndDirectoriesAsync())
+ {
+ if (fileDirectory.IsDirectory)
+ {
+ if (await archiveDirectory.GetSubdirectoryClient(fileDirectory.Name).ExistsAsync() == false)
+ {
+ archiveDirectory.CreateSubdirectory(fileDirectory.Name);
+ }
+
+ var sourceFileClient = sourceDirectory.GetFileClient(fileDirectory.Name);
+ await this.MigrateSubdirectory(sourceFileClient.Path);
+ }
+ else
+ {
+ var sourceFileClient = sourceDirectory.GetFileClient(fileDirectory.Name);
+ var destinationFileClient = archiveDirectory.GetFileClient(fileDirectory.Name);
+ var uri = sourceFileClient.GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions.Read, DateTime.UtcNow.AddHours(24));
+ await destinationFileClient.StartCopyAsync(uri);
+ await WaitForCopyAsync(destinationFileClient);
+ }
+ }
+ }
+
+ private async Task DeleteSubdirectory(string pathDirectory)
+ {
+ var sourceDirectory = this.ShareClient.GetDirectoryClient(pathDirectory);
+
+ await foreach (var fileDirectory in sourceDirectory.GetFilesAndDirectoriesAsync())
+ {
+ if (fileDirectory.IsDirectory)
+ {
+ var sourceFileClient = sourceDirectory.GetFileClient(fileDirectory.Name);
+ await this.DeleteSubdirectory(sourceFileClient.Path);
+ }
+ else
+ {
+ var sourceFileClient = sourceDirectory.GetFileClient(fileDirectory.Name);
+ await sourceFileClient.DeleteIfExistsAsync();
+ }
+ }
+ }
+
+ private async Task MoveInPutDirectoryToArchive(List allDirectoryRef)
+ {
+ if (allDirectoryRef.Any())
+ {
+ foreach (var directoryRef in allDirectoryRef)
+ {
+ var directory = this.ShareClient.GetDirectoryClient(directoryRef);
+ var archiveDirectory = this.InputArchiveShareClient.GetDirectoryClient(directoryRef);
+
+ await foreach (var fileItem in directory.GetFilesAndDirectoriesAsync())
+ {
+ var sourceFileClient = directory.GetFileClient(fileItem.Name);
+
+ archiveDirectory.CreateIfNotExists();
+ var destinationFileClient = archiveDirectory.GetFileClient(fileItem.Name);
+ var uri = sourceFileClient.GenerateSasUri(Azure.Storage.Sas.ShareFileSasPermissions.Read, DateTime.UtcNow.AddHours(24));
+
+ await destinationFileClient.StartCopyAsync(uri);
+
+ await WaitForCopyAsync(destinationFileClient);
+ }
+
+ if (await directory.ExistsAsync())
+ {
+ foreach (var fileItem in directory.GetFilesAndDirectories())
+ {
+ var sourceFileClient = directory.GetFileClient(fileItem.Name);
+ await sourceFileClient.DeleteIfExistsAsync();
+ }
+
+ await directory.DeleteAsync();
+ }
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Services/ResourceService.cs b/LearningHub.Nhs.WebUI/Services/ResourceService.cs
index 31608b797..ade01a5f8 100644
--- a/LearningHub.Nhs.WebUI/Services/ResourceService.cs
+++ b/LearningHub.Nhs.WebUI/Services/ResourceService.cs
@@ -1274,5 +1274,35 @@ public async Task DeleteAllResourceVersionProviderA
return apiResponse.ValidationResult;
}
+
+ ///
+ /// The GetObsoleteResourceFile.
+ ///
+ /// The resourceVersionId.
+ /// .
+ /// The .
+ public async Task> GetObsoleteResourceFile(int resourceVersionId, bool deletedResource = false)
+ {
+ List filePaths = null;
+
+ var client = await this.LearningHubHttpClient.GetClientAsync();
+
+ var request = $"Resource/GetObsoleteResourceFile/{resourceVersionId}/{deletedResource}";
+ var response = await client.GetAsync(request).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var result = response.Content.ReadAsStringAsync().Result;
+ filePaths = JsonConvert.DeserializeObject>(result);
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized
+ ||
+ response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ return filePaths;
+ }
}
}
diff --git a/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss
index 72d1fe015..ec574a288 100644
--- a/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss
+++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss
@@ -142,11 +142,16 @@
#maincontent {
button[class^='nhsuk-search__submit'] span.nhsuk-u-visually-hidden {
- color: #595959;
- background-color: #fff;
+ color: $color_nhsuk-grey-1;
+ background-color: $color_nhsuk-white;
}
}
+form label.nhsuk-u-visually-hidden {
+ color: $color_nhsuk-grey-1;
+ background-color: $color_nhsuk-white;
+}
+
/* One third column layout that switches to full width at the small desktop breakpoint (990px) instead of mobile. */
.nhsuk-grid-column-one-third-small-desktop {
@extend .nhsuk-grid-column-one-third;
diff --git a/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml b/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml
index 76dba2b01..23be8c9a0 100644
--- a/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml
@@ -79,7 +79,8 @@
CatalogueNodeVersionId = Model.Catalogue.Id,
RestrictedAccess = Model.Catalogue.RestrictedAccess,
HasCatalogueAccess = Unlocked(),
- CatalogueAccessRequest = Model.CatalogueAccessRequest
+ CatalogueAccessRequest = Model.CatalogueAccessRequest,
+ UserGroups = Model.UserGroups
};
}
@@ -125,7 +126,7 @@
@if (!string.IsNullOrEmpty(Model.Catalogue.BadgeUrl))
{
-
+
}
@(ViewBag.ActiveTab == "browse" && Model.NodeDetails != null ? Model.NodeDetails.Name : Model.Catalogue.Name)
@@ -145,7 +146,8 @@
asp-route-title="@Model.Catalogue.Name.Truncate(60)"
asp-route-nodeId="@Model.Catalogue.NodeId"
asp-route-path="@Model.Catalogue.Url"
- asp-route-returnUrl="@(Context.Request.Path + Context.Request.QueryString)">@(Model.Catalogue.IsBookmarked ? "Remove from" : "Add to") my bookmarks
+ asp-route-returnUrl="@(Context.Request.Path + Context.Request.QueryString)"
+ aria-label="@(Model.Catalogue.IsBookmarked ? "Remove from" : "Add to") my bookmarks">@(Model.Catalogue.IsBookmarked ? "Remove from" : "Add to") my bookmarks
}
@@ -164,12 +166,13 @@
@* Tab header *@
-
+
@GetActiveTabName()
-
+
+ label
diff --git a/LearningHub.Nhs.WebUI/Views/Catalogue/_SearchBar.cshtml b/LearningHub.Nhs.WebUI/Views/Catalogue/_SearchBar.cshtml
index 34a983eaa..2e7f5c50b 100644
--- a/LearningHub.Nhs.WebUI/Views/Catalogue/_SearchBar.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Catalogue/_SearchBar.cshtml
@@ -2,8 +2,8 @@
diff --git a/LearningHub.Nhs.WebUI/Views/Home/Contactus.cshtml b/LearningHub.Nhs.WebUI/Views/Home/Contactus.cshtml
index 6f1654c7c..83f69b5eb 100644
--- a/LearningHub.Nhs.WebUI/Views/Home/Contactus.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Home/Contactus.cshtml
@@ -86,7 +86,7 @@
@{
- var now = new DateTime(2020, 4, 30);
+ var now = new DateTime(2024, 4, 30);
}
@await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = now, NextReviewDate = now.AddYears(3) })
diff --git a/LearningHub.Nhs.WebUI/Views/Home/NhsSites.cshtml b/LearningHub.Nhs.WebUI/Views/Home/NhsSites.cshtml
index b0fadfc6e..2af4bc4bc 100644
--- a/LearningHub.Nhs.WebUI/Views/Home/NhsSites.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Home/NhsSites.cshtml
@@ -1,33 +1,32 @@
@{
ViewData["Title"] = "NHS sites";
}
-@section styles{
+@section styles {
}
-
+
-
-
-
- @ViewData["Title"]
-
-
-
+
+
+
+ @ViewData["Title"]
+
+
+
-
-
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Views/Home/_CatalogueCard.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_CatalogueCard.cshtml
index 735a0d209..4512c50f7 100644
--- a/LearningHub.Nhs.WebUI/Views/Home/_CatalogueCard.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Home/_CatalogueCard.cshtml
@@ -63,11 +63,11 @@
@if (providerExists)
{
var provider = @Model.Providers.First();
-
+
}
else if (!string.IsNullOrEmpty(Model.BadgeUrl))
{
-
+
}
diff --git a/LearningHub.Nhs.WebUI/Views/Home/_CatalogueTray.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_CatalogueTray.cshtml
index c54316298..9b3bf931d 100644
--- a/LearningHub.Nhs.WebUI/Views/Home/_CatalogueTray.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Home/_CatalogueTray.cshtml
@@ -34,7 +34,7 @@
@GetActiveTabName()
-
+
Show Catalogue Options
Hide Catalogue Options
diff --git a/LearningHub.Nhs.WebUI/Views/Home/_CmsPageRow.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_CmsPageRow.cshtml
index 4b8b5e9e4..fb0d553de 100644
--- a/LearningHub.Nhs.WebUI/Views/Home/_CmsPageRow.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Home/_CmsPageRow.cshtml
@@ -6,6 +6,11 @@
{
foreach (var pageModel in Model.PageViewModel.PageSections)
{
+ if (pageModel.PageSectionDetail.PageSection.SectionTemplateType == SectionTemplateType.Video && !Model.DisplayAudioVideo)
+ {
+
+ }
+
@if (!string.IsNullOrEmpty(pageModel.PageSectionDetail.SectionTitle))
@@ -18,7 +23,7 @@
}
- @if (pageModel.PageSectionDetail.PageSection.SectionTemplateType == SectionTemplateType.Video)
+ @if (pageModel.PageSectionDetail.PageSection.SectionTemplateType == SectionTemplateType.Video && Model.DisplayAudioVideo)
{
diff --git a/LearningHub.Nhs.WebUI/Views/Home/_ResourceTray.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_ResourceTray.cshtml
index bf4f0c840..cffb07772 100644
--- a/LearningHub.Nhs.WebUI/Views/Home/_ResourceTray.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Home/_ResourceTray.cshtml
@@ -35,7 +35,7 @@
@GetActiveTabName()
-
+
Show Resource Options
Hide Resource Options
diff --git a/LearningHub.Nhs.WebUI/Views/MyLearning/ExportToPDF.cshtml b/LearningHub.Nhs.WebUI/Views/MyLearning/ExportToPDF.cshtml
index 6031c8faf..d0ba0a0ca 100644
--- a/LearningHub.Nhs.WebUI/Views/MyLearning/ExportToPDF.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/MyLearning/ExportToPDF.cshtml
@@ -130,7 +130,7 @@
@activity.Version
@ViewActivityHelper.GetResourceTypeText(activity)
- @ViewActivityHelper.GetActivityStatusDisplayText(activity)
+ @ViewActivityHelper.GetActivityStatus(activity)
}
diff --git a/LearningHub.Nhs.WebUI/Views/MyLearning/LearningCertificate.cshtml b/LearningHub.Nhs.WebUI/Views/MyLearning/LearningCertificate.cshtml
index dbecd677b..87f37db09 100644
--- a/LearningHub.Nhs.WebUI/Views/MyLearning/LearningCertificate.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/MyLearning/LearningCertificate.cshtml
@@ -1216,7 +1216,7 @@
Last Date Completed @Model.ActivityDetailedItemViewModel.ActivityDate.ToString("dd/MM/yyyy")
- Overall Status @ViewActivityHelper.GetActivityStatusDisplayText(Model.ActivityDetailedItemViewModel)
+ Overall Status @ViewActivityHelper.GetActivityStatus(Model.ActivityDetailedItemViewModel)
@@ -1399,7 +1399,7 @@
Last Date Completed @Model.ActivityDetailedItemViewModel.ActivityDate.ToString("dd/MM/yyyy")
- Overall Status @ViewActivityHelper.GetActivityStatusDisplayText(Model.ActivityDetailedItemViewModel)
+ Overall Status @ViewActivityHelper.GetActivityStatus(Model.ActivityDetailedItemViewModel)
diff --git a/LearningHub.Nhs.WebUI/Views/MyLearning/_ActivityTable.cshtml b/LearningHub.Nhs.WebUI/Views/MyLearning/_ActivityTable.cshtml
index 9851b0001..9df2b40fa 100644
--- a/LearningHub.Nhs.WebUI/Views/MyLearning/_ActivityTable.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/MyLearning/_ActivityTable.cshtml
@@ -3,159 +3,165 @@
@using LearningHub.Nhs.WebUI.Models
@model MyLearningViewModel;
@{
- var returnUrl = $"{Context.Request.Path}{Context.Request.QueryString}";
+ var returnUrl = $"{Context.Request.Path}{Context.Request.QueryString}";
}
@if (Model.TotalCount > 0)
{
-
-
-
-
- Learning resource
-
-
- Version
-
-
- Type
-
-
- Certificate
-
-
- Status
-
-
-
-
- @foreach (var activity in Model.Activities)
- {
-
-
- Learning resource
-
- @if (activity.IsCurrentResourceVersion && activity.ResourceReferenceId > 0 && activity.VersionStatusId != (int?) VersionStatusEnum.Unpublished)
- {
-
- @activity.Title
- Last @ViewActivityHelper.GetResourceTypeVerb(activity).ToLower() on : @activity.ActivityDate.DateTime.ToString("dd MMM yyyy") at @activity.ActivityDate.DateTime.ToShortTimeString()
-
- }
- else
- {
-
- @activity.Title
-
+
+
+
+
+ Learning resource
+
+
+ Version
+
+
+ Type
+
+
+ Certificate
+
+
+ Status
+
+
+
+
+ @foreach (var activity in Model.Activities)
+ {
+
+
+ Learning resource
+
+ @if (activity.IsCurrentResourceVersion && activity.ResourceReferenceId > 0 && activity.VersionStatusId != (int?)VersionStatusEnum.Unpublished)
+ {
+
+ @activity.Title
+ Last @ViewActivityHelper.GetResourceTypeVerb(activity).ToLower() on : @activity.ActivityDate.DateTime.ToString("dd MMM yyyy") at @activity.ActivityDate.DateTime.ToShortTimeString()
+
+ }
+ else
+ {
+
+ @activity.Title
+
- }
- @if (activity.IsCurrentResourceVersion && activity.ResourceType == ResourceTypeEnum.Assessment)
- {
- string linkName = "Resume";
- if (ViewActivityHelper.CanShowScore(activity)) linkName = "View summary";
+ }
+ @if (activity.IsCurrentResourceVersion && activity.ResourceType == ResourceTypeEnum.Assessment)
+ {
+ string linkName = "Resume";
+ if (ViewActivityHelper.CanShowScore(activity)) linkName = "View summary";
- @linkName
+ @linkName
- }
+ }
- @if (ViewActivityHelper.CanViewPercentage(activity))
- {
-
- @activity.CompletionPercentage% complete
- @if (activity.IsMostRecent && ViewActivityHelper.CanViewProgress(activity))
- {
- View Progress
- }
-
- }
- else if (ViewActivityHelper.CanShowScore(activity))
- {
-
- Scored : @activity.ScorePercentage%
-
+ @if (ViewActivityHelper.CanViewPercentage(activity))
+ {
+
+ @activity.CompletionPercentage% complete
+ @if (activity.IsMostRecent && ViewActivityHelper.CanViewProgress(activity))
+ {
+ View Progress
+ }
+
+ }
+ else if (ViewActivityHelper.CanShowScore(activity))
+ {
+
+ Scored : @activity.ScorePercentage%
+
- }
+ }
- @if (activity.AssessmentDetails != null && !string.IsNullOrEmpty(activity.AssessmentDetails.ExtraAttemptReason))
- {
+ @if (activity.AssessmentDetails != null && !string.IsNullOrEmpty(activity.AssessmentDetails.ExtraAttemptReason))
+ {
- Reason : @activity.AssessmentDetails.ExtraAttemptReason
- }
-
-
-
- Version
- @activity.Version
+ Reason : @activity.AssessmentDetails.ExtraAttemptReason
+ }
+
+
+
+ Version
+ @activity.Version
-
-
- Type
- @ViewActivityHelper.GetResourceTypeText(activity)
+
+
+ Type
+ @ViewActivityHelper.GetResourceTypeText(activity)
-
-
- Certificate
-
- @if(ViewActivityHelper.CanDownloadCertificate(activity))
- {
- @if (activity.IsCurrentResourceVersion)
- {
- View certificate
- }
- else
- {
- View certificate
- }
- }
-
-
-
- Status
-
- @if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Completed)
- {
-
- Completed
-
- }
- else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Passed)
- {
-
- Passed
-
- }
- else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Downloaded)
- {
-
- Downloaded
-
- }
- else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.InProgress)
- {
-
- Incomplete
-
- }
- else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Failed)
- {
-
- Failed
-
- }
- else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Launched)
- {
-
- Launched
-
- }
-
-
-
+
+
+ Certificate
+
+ @if (ViewActivityHelper.CanDownloadCertificate(activity))
+ {
+ @if (activity.IsCurrentResourceVersion)
+ {
+ View certificate
+ }
+ else
+ {
+ View certificate
+ }
+ }
+
+
+
+ Status
+
+ @if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Completed.ToString())
+ {
+
+ Completed
+
+ }
+ else if (ViewActivityHelper.GetActivityStatus(activity) == "Viewed")
+ {
+
+ Viewed
+
+ }
+ else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Passed.ToString())
+ {
+
+ Passed
+
+ }
+ else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Downloaded.ToString())
+ {
+
+ Downloaded
+
+ }
+ else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.InProgress.ToString())
+ {
+
+ In progress
+
+ }
+ else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Failed.ToString())
+ {
+
+ Failed
+
+ }
+ else if (ViewActivityHelper.GetActivityStatus(activity) == ActivityStatusEnum.Launched.ToString())
+ {
+
+ Launched
+
+ }
+
+
+
- }
+ }
-
-
+
+
}
diff --git a/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml b/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml
index 4bc43f0f5..42ad771b1 100644
--- a/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml
@@ -53,11 +53,11 @@
}
@if (Model.Complete)
{
- filtersummary = filtersummary + $" Complete ";
+ filtersummary = filtersummary + $" Completed ";
}
@if (Model.Incomplete)
{
- filtersummary = filtersummary + $" Incomplete ";
+ filtersummary = filtersummary + $" In progress ";
}
@if (Model.Passed)
{
@@ -71,6 +71,14 @@
{
filtersummary = filtersummary + $" Downloaded ";
}
+ @if (Model.Viewed)
+ {
+ filtersummary = filtersummary + $" Viewed ";
+ }
+ @if (Model.Launched)
+ {
+ filtersummary = filtersummary + $" Launched ";
+ }
@if (string.IsNullOrWhiteSpace(filtersummary))
{
statusFilter = string.Empty;
diff --git a/LearningHub.Nhs.WebUI/Views/Policies/AcceptableUsePolicy.cshtml b/LearningHub.Nhs.WebUI/Views/Policies/AcceptableUsePolicy.cshtml
index a574bead9..9b120fef4 100644
--- a/LearningHub.Nhs.WebUI/Views/Policies/AcceptableUsePolicy.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Policies/AcceptableUsePolicy.cshtml
@@ -162,23 +162,23 @@
Metadata
-
+
When making any Contribution, you must where prompted include a sufficient description of the Content so that other users can understand the description, source, and age of the Content. For example, if Content has been quality assured, then the relevant information should be posted in the appropriate field. All metadata fields on the Platform must be completed appropriately before initiating upload. Including the correct information is important in order to help other users locate the Content (otherwise the Content may not appear in search results for others to select).
-
+
Updates
-
+
You must update each Contribution at least once every 3 (three) years, or update or remove it should it cease to be relevant or become outdated or revealed or generally perceived to be unsafe or otherwise unsuitable for inclusion on the Platform.
-
+
Accessibility
-
+
Where practicable, all Contributions should aim to meet the accessibility standards as described in our Accessibility Statement
https://learninghub.nhs.uk/Home/Accessibility and as set out in the AA Standard Web Content Accessibility Guidelines v2.1 found here:
https://www.w3.org/TR/WCAG21/ .
-
+
Rules about linking to the Platform
@@ -203,9 +203,11 @@
Breach of this Acceptable Use Policy
-
- Failure to comply with this Acceptable Use Policy constitutes a material breach of this Acceptable Use Policy upon which you are permitted to use the Platform and may result in our taking all or any of the following actions:
- immediate, temporary, or permanent withdrawal of your right to use the Platform;
+
+ Failure to comply with this Acceptable Use Policy constitutes a material breach of this Acceptable Use Policy upon which you are permitted to use the Platform and may result in our taking all or any of the following actions:
+
+
+ immediate, temporary, or permanent withdrawal of your right to use the Platform;
immediate, temporary, or permanent removal of any Contribution uploaded by you to the Platform;
issue of a warning to you;
legal proceedings against you for reimbursement of all costs on an indemnity basis (including, but not limited to, reasonable administrative and legal costs) resulting from the breach, and/or further legal action against you;
@@ -216,7 +218,7 @@
- @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2023, 6, 01), NextReviewDate = new DateTime(2026, 6, 01) })
+ @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2023, 6, 01), NextReviewDate = new DateTime(2026, 8, 16) })
diff --git a/LearningHub.Nhs.WebUI/Views/Policies/ContentPolicy.cshtml b/LearningHub.Nhs.WebUI/Views/Policies/ContentPolicy.cshtml
index 5a08729a2..b8910df0e 100644
--- a/LearningHub.Nhs.WebUI/Views/Policies/ContentPolicy.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Policies/ContentPolicy.cshtml
@@ -53,7 +53,9 @@
You agree to at all times process their personal data in accordance with the requirements of data protection legislation
+
You agree to promptly notify NHSE of any data protection breach that you become aware of concerning third party personal data that you have uploaded to the Learning Hub
+
You agree to promptly notify NHSE when a data subject in respect of any third party personal data that you have uploaded to the Learning Hub notifies you that they wish to exercise their data subject rights
@@ -123,7 +125,7 @@
We ask that where practicable, all content should aim to meet accessibility standards as described in our Accessibility Statement and as set out in the AA standard Web Content Accessibility Guidelines v2.0.
- @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2020, 5, 26), NextReviewDate = new DateTime(2023, 5, 26) })
+ @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2020, 5, 26), NextReviewDate = new DateTime(2026, 8, 16) })
\ No newline at end of file
diff --git a/LearningHub.Nhs.WebUI/Views/Policies/CookiePolicy.cshtml b/LearningHub.Nhs.WebUI/Views/Policies/CookiePolicy.cshtml
index e378741c0..232966df9 100644
--- a/LearningHub.Nhs.WebUI/Views/Policies/CookiePolicy.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Policies/CookiePolicy.cshtml
@@ -317,7 +317,7 @@
@await Html.PartialAsync("_CookiePolicyConfirmation", new CookieConsentViewModel {UserConsent = cookieBannerCookieValue, Layout = Layout})
- @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2020, 5, 26), NextReviewDate = new DateTime(2023, 5, 26) })
+ @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2020, 5, 26), NextReviewDate = new DateTime(2026, 8, 16) })
diff --git a/LearningHub.Nhs.WebUI/Views/Policies/PrivacyPolicy.cshtml b/LearningHub.Nhs.WebUI/Views/Policies/PrivacyPolicy.cshtml
index 24a877359..924eee723 100644
--- a/LearningHub.Nhs.WebUI/Views/Policies/PrivacyPolicy.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Policies/PrivacyPolicy.cshtml
@@ -208,7 +208,7 @@
- @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2023, 6, 01), NextReviewDate = new DateTime(2026, 6, 01) })
+ @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = new DateTime(2023, 6, 01), NextReviewDate = new DateTime(2026, 8, 16) })
diff --git a/LearningHub.Nhs.WebUI/Views/Policies/TermsConditions.cshtml b/LearningHub.Nhs.WebUI/Views/Policies/TermsConditions.cshtml
index 75646cc53..f8596604d 100644
--- a/LearningHub.Nhs.WebUI/Views/Policies/TermsConditions.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Policies/TermsConditions.cshtml
@@ -1,6 +1,7 @@
@model LearningHub.Nhs.WebUI.Models.Policies.TermsAndConditionsViewModel
@{
ViewData["Title"] = "Terms and Conditions";
+ var nextDate = new DateTime(2026, 8, 16);
}
@section styles{
@@ -14,7 +15,7 @@
@Html.Raw(Model.TermsAndConditions)
- @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = Model.CreatedDate, NextReviewDate = Model.CreatedDate.AddYears(3) })
+ @await Html.PartialAsync("~/Views/Shared/_PageReviewPartial.cshtml", new PageReviewModel { LastReviewedDate = Model.CreatedDate, NextReviewDate = nextDate })
diff --git a/LearningHub.Nhs.WebUI/Views/Resource/_RatingSummary.cshtml b/LearningHub.Nhs.WebUI/Views/Resource/_RatingSummary.cshtml
index e8cdf78f5..9a932d2a7 100644
--- a/LearningHub.Nhs.WebUI/Views/Resource/_RatingSummary.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Resource/_RatingSummary.cshtml
@@ -65,7 +65,7 @@
5 star
@Model.RatingSummary.Rating5StarPercent%
@@ -74,7 +74,7 @@
4 star
@Model.RatingSummary.Rating4StarPercent%
@@ -83,7 +83,7 @@
3 star
@Model.RatingSummary.Rating3StarPercent%
@@ -92,7 +92,7 @@
2 star
@Model.RatingSummary.Rating2StarPercent%
@@ -101,7 +101,7 @@
1 star
@Model.RatingSummary.Rating1StarPercent%
diff --git a/LearningHub.Nhs.WebUI/Views/Resource/_ResourceInformation.cshtml b/LearningHub.Nhs.WebUI/Views/Resource/_ResourceInformation.cshtml
index 97ec1f190..98342b4db 100644
--- a/LearningHub.Nhs.WebUI/Views/Resource/_ResourceInformation.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Resource/_ResourceInformation.cshtml
@@ -7,6 +7,7 @@
@inject Microsoft.Extensions.Options.IOptions
options
@{
var resourceItem = Model.ResourceItem;
+ bool providerExists = Model.ResourceItem.Providers?.Count > 0;
bool CanDisplayEsrLink()
{
@@ -39,9 +40,15 @@
Resource details
+ @if (providerExists)
+ {
+ var providersss = @resourceItem.Providers;
+ var provider = @resourceItem.Providers.First();
+
+ }
@if (!string.IsNullOrEmpty(resourceItem.Catalogue.BadgeUrl))
{
-
+
}
diff --git a/LearningHub.Nhs.WebUI/Views/Resource/_ResourceItem.cshtml b/LearningHub.Nhs.WebUI/Views/Resource/_ResourceItem.cshtml
index cb8c0bb84..53a8e2521 100644
--- a/LearningHub.Nhs.WebUI/Views/Resource/_ResourceItem.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Resource/_ResourceItem.cshtml
@@ -107,6 +107,21 @@
}
+ @* Html Resource *@
+ @if (canShowMoreDetails && resourceItem.ResourceTypeEnum == ResourceTypeEnum.Html)
+ {
+
+ }
@* Generic File *@
@if (canShowMoreDetails && resourceItem.ResourceTypeEnum == ResourceTypeEnum.GenericFile)
@@ -146,23 +161,7 @@
}
}
- @* Html Resource *@
- @if (canShowMoreDetails && resourceItem.ResourceTypeEnum == ResourceTypeEnum.Html)
- {
-
- }
-
-
+
@if (canShowMoreDetails && resourceItem.ResourceTypeEnum == ResourceTypeEnum.Video || resourceItem.ResourceTypeEnum == ResourceTypeEnum.Audio || resourceItem.ResourceTypeEnum == ResourceTypeEnum.Scorm ||
resourceItem.ResourceTypeEnum == ResourceTypeEnum.Case || resourceItem.ResourceTypeEnum == ResourceTypeEnum.Assessment)
{
@@ -173,11 +172,18 @@
@* Video/Audio/Scorm/Case/Assessment require JavaScript - use Vue.js resource app. *@
-
-
-
+ if (!@ViewBag.DisplayAVResourceFlag)
+ {
+
+ }
+ else
+ {
+
+
+
+ }
}
diff --git a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml
index 07c2caa6e..6e0f806bd 100644
--- a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml
@@ -82,7 +82,7 @@
@if (!string.IsNullOrWhiteSpace(item.CatalogueBadgeUrl) && showCatalogueFieldsInResources)
{
-
+
}
@if (!string.IsNullOrEmpty(item.CatalogueName) && !this.Model.CatalogueId.HasValue && showCatalogueFieldsInResources)
diff --git a/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml
index 2beea978a..961f9c1aa 100644
--- a/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml
@@ -2,8 +2,8 @@