diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs index f6ab9963a..a1716767a 100644 --- a/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/Api/ContributeController.cs @@ -9,6 +9,7 @@ using System.Web; using LearningHub.Nhs.Models.Enums; using LearningHub.Nhs.Models.Resource; + using LearningHub.Nhs.Models.Resource.Blocks; using LearningHub.Nhs.Models.Resource.Contribute; using LearningHub.Nhs.Models.Resource.Files; using LearningHub.Nhs.WebUI.Interfaces; @@ -224,11 +225,14 @@ public async Task DeleteResourceKeywordAsync([FromBody] KeywordDel [Route("DeleteResourceVersion/{resourceversionId}")] public async Task DeleteResourceVersion(int resourceVersionId) { - var associatedFile = await this.resourceService.GetResourceVersionExtendedAsync(resourceVersionId); + var associatedFile = await this.resourceService.GetObsoleteResourceFile(resourceVersionId, true); var validationResult = await this.contributeService.DeleteResourceVersionAsync(resourceVersionId); if (validationResult.IsValid) { - _ = Task.Run(async () => { await this.fileService.PurgeResourceFile(associatedFile); }); + if (associatedFile != null && associatedFile.Any()) + { + _ = Task.Run(async () => { await this.fileService.PurgeResourceFile(null, associatedFile); }); + } } return this.Ok(validationResult); @@ -338,7 +342,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 != null && obsoleteFiles.Any()) + { + await this.fileService.PurgeResourceFile(null, obsoleteFiles); + } + } + } return this.Ok(validationResult); } @@ -475,7 +491,9 @@ public async Task SaveWeblinkDetailAsync([FromBody] WebLinkViewMod [Route("SaveCaseDetail")] public async Task SaveCaseDetailAsync([FromBody] CaseViewModel request) { + var existingResourceState = await this.resourceService.GetResourceVersionExtendedAsync(request.ResourceVersionId); int resourceVersionId = await this.contributeService.SaveCaseDetailAsync(request); + this.RemoveDeletedCaseFiles(existingResourceState?.CaseDetails, request); return this.Ok(resourceVersionId); } @@ -608,5 +626,103 @@ private async Task UserCanEditCatalogue(int catalogueId) { return await this.catalogueService.CanCurrentUserEditCatalogue(catalogueId); } + + private void RemoveDeletedCaseFiles(CaseViewModel existingResource, CaseViewModel newResource) + { + try + { + var filePaths = new List(); + if (existingResource != null && existingResource.BlockCollection != null) + { + var allBlocks = existingResource.BlockCollection.Blocks.ToList(); + var newBlocks = newResource.BlockCollection.Blocks.ToList(); + if (allBlocks.Any()) + { + var existingAttachements = allBlocks.Where(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Attachment && x.MediaBlock.Attachment != null).ToList(); + if (existingAttachements.Any()) + { + foreach (var oldblock in existingAttachements) + { + var entry = newBlocks.FirstOrDefault(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Attachment && x.MediaBlock.Attachment != null && x.MediaBlock.Attachment.File?.FileId == oldblock.MediaBlock.Attachment?.File?.FileId); + if (entry == null) + { + filePaths.Add(oldblock.MediaBlock.Attachment?.File?.FilePath); + } + } + } + + var existingVideos = allBlocks.Where(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Video && x.MediaBlock.Video != null).ToList(); + if (existingVideos.Any()) + { + foreach (var oldblock in existingVideos) + { + var entry = newBlocks.FirstOrDefault(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Video && x.MediaBlock.Video != null && x.MediaBlock.Video.VideoFile?.File?.FileId == oldblock.MediaBlock?.Video?.VideoFile?.File?.FileId); + if (entry == null) + { + filePaths.Add(oldblock.MediaBlock.Video?.VideoFile?.File?.FilePath); + if (oldblock.MediaBlock?.Video?.VideoFile?.TranscriptFile?.File?.FilePath != null) + { + filePaths.Add(oldblock.MediaBlock.Video?.VideoFile?.TranscriptFile?.File?.FilePath); + } + } + } + } + + var existingImages = allBlocks.Where(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Image && x.MediaBlock.Image != null).ToList(); + if (existingImages.Any()) + { + foreach (var oldblock in existingImages) + { + var entry = newBlocks.FirstOrDefault(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Image && x.MediaBlock.Image != null && x.MediaBlock?.Image?.File?.FileId == oldblock.MediaBlock?.Image?.File?.FileId); + if (entry == null) + { + filePaths.Add(oldblock?.MediaBlock?.Image?.File?.FilePath); + } + } + } + + var existingImageCarousel = allBlocks.Where(x => x.BlockType == BlockType.ImageCarousel && x.ImageCarouselBlock != null && x.ImageCarouselBlock.ImageBlockCollection != null && x.ImageCarouselBlock.ImageBlockCollection.Blocks != null).ToList(); + if (existingImageCarousel.Any()) + { + foreach (var imageBlock in existingImageCarousel) + { + foreach (var oldblock in imageBlock?.ImageCarouselBlock?.ImageBlockCollection?.Blocks) + { + var entry = newBlocks.FirstOrDefault(x => x.BlockType == BlockType.ImageCarousel && x.ImageCarouselBlock != null && x.ImageCarouselBlock.ImageBlockCollection != null && x.ImageCarouselBlock.ImageBlockCollection.Blocks != null && x.ImageCarouselBlock.ImageBlockCollection.Blocks.Where(x => x.MediaBlock?.Image?.File?.FileId == oldblock.MediaBlock?.Image?.File?.FileId).Any()); + if (entry == null) + { + filePaths.Add(oldblock.MediaBlock?.Image?.File?.FilePath); + } + } + } + } + + var existingWholeSlideImages = allBlocks.Where(x => x.WholeSlideImageBlock != null && x.WholeSlideImageBlock.WholeSlideImageBlockItems.Any()).ToList(); + if (existingWholeSlideImages.Any()) + { + foreach (var wsi in existingWholeSlideImages) + { + foreach (var oldblock in wsi?.WholeSlideImageBlock?.WholeSlideImageBlockItems) + { + var entry = newBlocks.FirstOrDefault(x => x.WholeSlideImageBlock != null && x.WholeSlideImageBlock.WholeSlideImageBlockItems.Where(x => x.WholeSlideImage?.File?.FileId == oldblock.WholeSlideImage?.File?.FileId).Any()); + if (entry == null) + { + filePaths.Add(oldblock.WholeSlideImage?.File?.FilePath); + } + } + } + } + } + } + + if (filePaths != null && filePaths.Any()) + { + _ = Task.Run(async () => { await this.fileService.PurgeResourceFile(null, filePaths); }); + } + } + catch (Exception ex) + { + } + } } } diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs index cad178569..ba9ed57f3 100644 --- a/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/Api/ScormController.cs @@ -260,10 +260,6 @@ 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; } diff --git a/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs b/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs index 34fa4c19b..7a1245acc 100644 --- a/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/ResourceController.cs @@ -413,7 +413,11 @@ public async Task UnpublishConfirm(ResourceUnpublishConfirmViewMo if (validationResult.IsValid) { - _ = Task.Run(async () => { await this.fileService.PurgeResourceFile(associatedFile); }); + 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"); diff --git a/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs b/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs index e800efc41..c74a1681f 100644 --- a/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs +++ b/LearningHub.Nhs.WebUI/Interfaces/IFileService.cs @@ -48,7 +48,8 @@ public interface IFileService /// The PurgeResourceFile. /// /// The vm.. + /// . /// The . - Task PurgeResourceFile(ResourceVersionExtendedViewModel vm); + 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/Models/MyLearningViewModel.cs b/LearningHub.Nhs.WebUI/Models/MyLearningViewModel.cs index bbf6740f2..c7ae8692d 100644 --- a/LearningHub.Nhs.WebUI/Models/MyLearningViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/MyLearningViewModel.cs @@ -185,7 +185,7 @@ public List StatusFilterCheckbox() var checkboxes = new List() { new CheckboxListItemViewModel("Complete", "Completed", null), - new CheckboxListItemViewModel("Incomplete", "In Progress", null), + new CheckboxListItemViewModel("Incomplete", "In progress", null), new CheckboxListItemViewModel("Passed", "Passed", null), new CheckboxListItemViewModel("Failed", "Failed", null), new CheckboxListItemViewModel("Downloaded", "Downloaded", null), diff --git a/LearningHub.Nhs.WebUI/Services/FileService.cs b/LearningHub.Nhs.WebUI/Services/FileService.cs index 4bfc997a5..a2120a74d 100644 --- a/LearningHub.Nhs.WebUI/Services/FileService.cs +++ b/LearningHub.Nhs.WebUI/Services/FileService.cs @@ -10,7 +10,6 @@ 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; @@ -88,13 +87,13 @@ private ShareClient InputArchiveShareClient this.archiveShareClient = new ShareClient(this.settings.AzureSourceArchiveStorageConnectionString, this.settings.AzureFileStorageResourceShareName, options); - if (!this.shareClient.Exists()) + if (!this.archiveShareClient.Exists()) { throw new Exception($"Unable to access azure file storage resource {this.settings.AzureFileStorageResourceShareName}"); } } - return this.shareClient; + return this.archiveShareClient; } } @@ -129,6 +128,7 @@ public async Task DeleteChunkDirectory(string directoryRef, int chunks) public async Task DownloadFileAsync(string filePath, string fileName) { var directory = this.ShareClient.GetDirectoryClient(filePath); + var sourceDirectory = this.InputArchiveShareClient.GetDirectoryClient(filePath); if (await directory.ExistsAsync()) { @@ -139,6 +139,15 @@ public async Task DownloadFileAsync(string filePath, stri return await file.DownloadAsync(); } } + else if (await sourceDirectory.ExistsAsync()) + { + var file = sourceDirectory.GetFileClient(fileName); + + if (await file.ExistsAsync()) + { + return await file.DownloadAsync(); + } + } return null; } @@ -201,9 +210,17 @@ public async Task ProcessFile(Stream fileBytes, string fileName, string /// The PurgeResourceFile. /// /// The vm.. + /// . /// The . - public async Task PurgeResourceFile(ResourceVersionExtendedViewModel vm) + 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(); @@ -235,7 +252,29 @@ public async Task PurgeResourceFile(ResourceVersionExtendedViewModel vm) } } } + 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); } @@ -374,6 +413,10 @@ private async Task MoveInPutDirectoryToArchive(List allDirectoryRef) { var directory = this.ShareClient.GetDirectoryClient(directoryRef); var archiveDirectory = this.InputArchiveShareClient.GetDirectoryClient(directoryRef); + if (!directory.Exists()) + { + continue; + } await foreach (var fileItem in directory.GetFilesAndDirectoriesAsync()) { 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/pages/bookmark.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/bookmark.scss index bc8bac3c9..6378eae15 100644 --- a/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/bookmark.scss +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/bookmark.scss @@ -29,7 +29,7 @@ a.cancel-link:visited { } } -.folder-title { +div.folder-title { font-weight: bold; } diff --git a/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/catalogue.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/catalogue.scss index 4aba85b35..22ffd1a18 100644 --- a/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/catalogue.scss +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/catalogue.scss @@ -29,6 +29,13 @@ textarea { } } +@media(min-width: 40.0625em) { + .folder-title { + font-size: 24px; + font-size: 1.5rem; + } +} + .folder-title_empty { display: flex; @@ -91,9 +98,13 @@ textarea { padding: 20px 0 32px 0; border-bottom: 1px solid $nhsuk-grey-light; - p, h3 { + p, h2, h3 { margin: 0; } + + h2.nhsuk-u-reading-width { + font-size: x-large; + } } .personal-details-table { diff --git a/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/search.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/search.scss index 9e800942d..c43713aaa 100644 --- a/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/search.scss +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/pages/search.scss @@ -156,6 +156,10 @@ .search-filter-items { border-top: 1px $nhsuk-grey-light solid; background-color: $nhsuk-grey-white; + + h2 { + font-size: larger; + } } } diff --git a/LearningHub.Nhs.WebUI/Views/Catalogue/Catalogues.cshtml b/LearningHub.Nhs.WebUI/Views/Catalogue/Catalogues.cshtml index d184442fb..6eda29434 100644 --- a/LearningHub.Nhs.WebUI/Views/Catalogue/Catalogues.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Catalogue/Catalogues.cshtml @@ -76,7 +76,7 @@ } diff --git a/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml b/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml index 933391f2c..4a62262bc 100644 --- a/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml @@ -126,7 +126,7 @@
@if (!string.IsNullOrEmpty(Model.Catalogue.BadgeUrl)) { - catalogue badge + Provider's catalogue badge }

@(ViewBag.ActiveTab == "browse" && Model.NodeDetails != null ? Model.NodeDetails.Name : Model.Catalogue.Name)

@@ -140,13 +140,14 @@ @if (ViewBag.UserAuthenticated) {
- @(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
} diff --git a/LearningHub.Nhs.WebUI/Views/Catalogue/_ContentStructure.cshtml b/LearningHub.Nhs.WebUI/Views/Catalogue/_ContentStructure.cshtml index 492ab0933..a39cfebcd 100644 --- a/LearningHub.Nhs.WebUI/Views/Catalogue/_ContentStructure.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Catalogue/_ContentStructure.cshtml @@ -10,22 +10,22 @@ { @if (item.IsEmptyFolder) { -

+

folder icon @item.Name -

+ } else { -

+

folder icon @item.Name -

+ } } else { -

@item.Name

+

@item.Name

diff --git a/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml b/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml index 2e9c726b0..42ad771b1 100644 --- a/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml +++ b/LearningHub.Nhs.WebUI/Views/MyLearning/_filterSummary.cshtml @@ -57,7 +57,7 @@ } @if (Model.Incomplete) { - filtersummary = filtersummary + $" In Progress"; + filtersummary = filtersummary + $" In progress"; } @if (Model.Passed) { diff --git a/LearningHub.Nhs.WebUI/Views/Resource/Resource.cshtml b/LearningHub.Nhs.WebUI/Views/Resource/Resource.cshtml index 0c89a0f24..cf63994c4 100644 --- a/LearningHub.Nhs.WebUI/Views/Resource/Resource.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Resource/Resource.cshtml @@ -190,7 +190,7 @@ } - } - 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(); + @provider.Name catalogue badge + } @if (!string.IsNullOrEmpty(resourceItem.Catalogue.BadgeUrl)) { - @(resourceItem.Catalogue.Name) + Provider's catalogue badge }
diff --git a/LearningHub.Nhs.WebUI/Views/Search/_CatalogueSearchResult.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_CatalogueSearchResult.cshtml index 2bcfbf19c..a27a7aba0 100644 --- a/LearningHub.Nhs.WebUI/Views/Search/_CatalogueSearchResult.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Search/_CatalogueSearchResult.cshtml @@ -89,11 +89,11 @@
@if (provider != null) { - @provider.Name + @provider.Name catalogue badge } else @if (hasBadge) { - @(item.Name) + Provider's catalogue badge }
diff --git a/LearningHub.Nhs.WebUI/Views/Search/_ResourceFilter.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_ResourceFilter.cshtml index 818f2bf1f..429eae962 100644 --- a/LearningHub.Nhs.WebUI/Views/Search/_ResourceFilter.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Search/_ResourceFilter.cshtml @@ -89,8 +89,10 @@ }
-
-

Sort by:

+
+ +

Sort by:

+
@foreach (var sortItem in resourceResult.SortItemList) @@ -107,7 +109,7 @@ }
-
+
@if (resourceResult.SearchResourceAccessLevelFilters != null && resourceResult.SearchResourceAccessLevelFilters.Any()) @@ -115,8 +117,10 @@
-
-

Filter by audience access level:

+
+ +

Filter by audience access level:

+
@foreach (var filter in resourceResult.SearchResourceAccessLevelFilters) @@ -132,7 +136,7 @@
}
-
+ } @@ -141,8 +145,10 @@
-
-

Filter by provider:

+
+ +

Filter by provider:

+
@foreach (var filter in resourceResult.SearchProviderFilters) @@ -159,15 +165,17 @@
}
-
+ }
-
-

Filter by:

+
+ +

Filter by:

+
@foreach (var filter in resourceResult.SearchFilters) @@ -185,7 +193,7 @@ }
-
+
@await Component.InvokeAsync("NavigationItems", new { navView = "MenuNotificationDot" }) } @@ -41,7 +41,7 @@ @if (User.Identity.IsAuthenticated) {
- + @await Component.InvokeAsync("NavigationItems", new { navView = "MenuNotificationDot" })
} diff --git a/WebAPI/LearningHub.Nhs.API/Controllers/ResourceController.cs b/WebAPI/LearningHub.Nhs.API/Controllers/ResourceController.cs index 849a04ae1..18044a758 100644 --- a/WebAPI/LearningHub.Nhs.API/Controllers/ResourceController.cs +++ b/WebAPI/LearningHub.Nhs.API/Controllers/ResourceController.cs @@ -447,12 +447,14 @@ public async Task GetResourceVersionsAsync(int resourceId) /// Get file directory for unpublished or deleted versions. /// /// The resourceVersionId. + /// . /// The . [HttpGet] [Route("GetObsoleteResourceFile/{resourceVersionId}")] - public async Task> GetObsoleteResourceFile(int resourceVersionId) + [Route("GetObsoleteResourceFile/{resourceVersionId}/{deletedResource}")] + public async Task> GetObsoleteResourceFile(int resourceVersionId, bool deletedResource = false) { - return await this.resourceService.GetObsoleteResourceFile(resourceVersionId); + return await this.resourceService.GetObsoleteResourceFile(resourceVersionId, deletedResource); } /// diff --git a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLatestActivityCheck.sql b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLatestActivityCheck.sql index 235868d43..a5a351969 100644 --- a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLatestActivityCheck.sql +++ b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLatestActivityCheck.sql @@ -144,7 +144,31 @@ FROM ( WHERE ([ScormActivity].[Deleted] = 0 AND [ResourceActivity].[Id] = [ScormActivity].[ResourceActivityId]) ) IS NULL - ) + ) + AND + ( + ( + -- resource type is not video/audio and launch resource activity doesn't exists + [Res].[ResourceTypeId] NOT IN (7,2) AND NOT (EXISTS + ( + SELECT 1 FROM [activity].[ResourceActivity] AS [ResAct1] + WHERE [ResAct1].[Deleted] = 0 AND [ResourceActivity].[Id] = [ResAct1].[LaunchResourceActivityId] + )) + ) + OR + -- or launch resource activity completed + EXISTS + ( + SELECT 1 FROM [activity].[ResourceActivity] AS [ResAct2] + WHERE [ResAct2].[Deleted] = 0 AND [ResourceActivity].[Id] = [ResAct2].[LaunchResourceActivityId] AND [ResAct2].[ActivityStatusId] = 3 + ) + + ) + AND + ( + -- resource type is not assessment and activity status is launched + [Res].[ResourceTypeId] <> 11 OR [ResourceActivity].[ActivityStatusId] = 1 + ) ) AS [t2] LEFT JOIN [resources].[VideoResourceVersion] AS [VideoResourceVersion] ON [t2].[Id1] = [VideoResourceVersion].[ResourceVersionId] diff --git a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivities.sql b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivities.sql index 5eb46e6cb..def1b45e4 100644 --- a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivities.sql +++ b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivities.sql @@ -213,7 +213,30 @@ FROM ( ) IS NULL ) - + AND + ( + ( + -- resource type is not video/audio and launch resource activity doesn't exists + [Res].[ResourceTypeId] NOT IN (7,2) AND NOT (EXISTS + ( + SELECT 1 FROM [activity].[ResourceActivity] AS [ResAct1] + WHERE [ResAct1].[Deleted] = 0 AND [ResourceActivity].[Id] = [ResAct1].[LaunchResourceActivityId] + )) + ) + OR + -- or launch resource activity completed + EXISTS + ( + SELECT 1 FROM [activity].[ResourceActivity] AS [ResAct2] + WHERE [ResAct2].[Deleted] = 0 AND [ResourceActivity].[Id] = [ResAct2].[LaunchResourceActivityId] AND [ResAct2].[ActivityStatusId] = 3 + ) + + ) + AND + ( + -- resource type is not assessment and activity status is launched + [Res].[ResourceTypeId] <> 11 OR [ResourceActivity].[ActivityStatusId] = 1 + ) AND ( @filterActivityStatus = 0 diff --git a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivitiesCount.sql b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivitiesCount.sql index 329cbcfed..4bd7cf1d2 100644 --- a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivitiesCount.sql +++ b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/GetUserLearningActivitiesCount.sql @@ -128,7 +128,31 @@ FROM ( WHERE ([ScormActivity].[Deleted] = 0 AND [ResourceActivity].[Id] = [ScormActivity].[ResourceActivityId]) ) IS NULL - ) + ) + AND + ( + ( + -- resource type is not video/audio and launch resource activity doesn't exists + [Res].[ResourceTypeId] NOT IN (7,2) AND NOT (EXISTS + ( + SELECT 1 FROM [activity].[ResourceActivity] AS [ResAct1] + WHERE [ResAct1].[Deleted] = 0 AND [ResourceActivity].[Id] = [ResAct1].[LaunchResourceActivityId] + )) + ) + OR + -- or launch resource activity completed + EXISTS + ( + SELECT 1 FROM [activity].[ResourceActivity] AS [ResAct2] + WHERE [ResAct2].[Deleted] = 0 AND [ResourceActivity].[Id] = [ResAct2].[LaunchResourceActivityId] AND [ResAct2].[ActivityStatusId] = 3 + ) + + ) + AND + ( + -- resource type is not assessment and activity status is launched + [Res].[ResourceTypeId] <> 11 OR [ResourceActivity].[ActivityStatusId] = 1 + ) AND ( @filterActivityStatus = 0 diff --git a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/ScormActivityComplete.sql b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/ScormActivityComplete.sql index 48258f338..c04238a5a 100644 --- a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/ScormActivityComplete.sql +++ b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Activity/ScormActivityComplete.sql @@ -6,7 +6,7 @@ -- Modification History -- -- 11-06-2021 Killian Davies Initial Revision --- 22-03-2024 Sarathlal TD-1325 +-- 17-04-2024 Swapna Abraham Reverted TD-1325 changes ------------------------------------------------------------------------------- CREATE PROCEDURE [activity].[ScormActivityComplete] ( @@ -24,7 +24,7 @@ BEGIN DECLARE @DurationSeconds int DECLARE @ScormActivityDurationLimitHours int = 10 * 60 * 60 DECLARE @AmendDate datetimeoffset(7) = ISNULL(TODATETIMEOFFSET(DATEADD(mi, @UserTimezoneOffset, GETUTCDATE()), @UserTimezoneOffset), SYSDATETIMEOFFSET()) - DECLARE @CmiCoreSessionTime NVARCHAR(MAX) + SELECT @ScormResourceActivityId = [ResourceActivityId], @ActivityStatusId = CmiCoreLesson_status, @@ -33,8 +33,7 @@ BEGIN WHEN (activity.ScormTimeToSeconds(CmiCoreSession_time) >= @ScormActivityDurationLimitHours) THEN (@ScormActivityDurationLimitHours - 1) ELSE activity.ScormTimeToSeconds(CmiCoreSession_time) END, - @Score = CmiCoreScoreRaw, - @CmiCoreSessionTime = CmiCoreSession_time + @Score = CmiCoreScoreRaw FROM activity.ScormActivity sa INNER JOIN @@ -54,7 +53,7 @@ BEGIN END -- Validation ported from e-LfH: completed status requires duration > 0 - IF ((@ActivityStatusId IN (3, 4, 5) AND @DurationSeconds > 0) OR (@ActivityStatusId=3 AND @CmiCoreSessionTime ='')) + IF (@ActivityStatusId IN (3, 4, 5) AND @DurationSeconds > 0) BEGIN TRY BEGIN TRAN @@ -123,4 +122,6 @@ BEGIN ,@ErrorState ); END CATCH -END \ No newline at end of file +END + +GO \ No newline at end of file diff --git a/WebAPI/LearningHub.Nhs.Repository/Activity/ResourceActivityRepository.cs b/WebAPI/LearningHub.Nhs.Repository/Activity/ResourceActivityRepository.cs index 9b70c942b..1c3a96adb 100644 --- a/WebAPI/LearningHub.Nhs.Repository/Activity/ResourceActivityRepository.cs +++ b/WebAPI/LearningHub.Nhs.Repository/Activity/ResourceActivityRepository.cs @@ -96,6 +96,7 @@ public IQueryable GetByUserId(int userId) // // For assessment activities, only include the original activities that were created when starting the assessment. The created end record is only for consistency. // It's easier to get the real assessment resource activity from the original resource activity, so only fetch that one. + // TD-4047: As part of this defect bringing back the removed code which then used for the new stored procedure created as part of performance improvement. return this.DbContext.ResourceActivity .Include(r => r.Resource) .ThenInclude(r => r.ResourceReference) @@ -111,9 +112,10 @@ public IQueryable GetByUserId(int userId) .Include(r => r.NodePath) .AsNoTracking() .Where(r => - r.UserId == userId && r.ScormActivity.First().CmiCoreLessonStatus != (int)ActivityStatusEnum.Completed && - ((!r.InverseLaunchResourceActivity.Any()) || - r.InverseLaunchResourceActivity.Any())) + r.UserId == userId && r.ScormActivity.First().CmiCoreLessonStatus != (int)ActivityStatusEnum.Completed && + ((r.Resource.ResourceTypeEnum != ResourceTypeEnum.Video && r.Resource.ResourceTypeEnum != ResourceTypeEnum.Audio && !r.InverseLaunchResourceActivity.Any()) || + r.InverseLaunchResourceActivity.Any(y => y.ActivityStatusId == (int)ActivityStatusEnum.Completed)) && + (r.Resource.ResourceTypeEnum != ResourceTypeEnum.Assessment || r.ActivityStatusId == (int)ActivityStatusEnum.Launched)) .OrderByDescending(r => r.ActivityStart); } diff --git a/WebAPI/LearningHub.Nhs.Services.Interface/IResourceService.cs b/WebAPI/LearningHub.Nhs.Services.Interface/IResourceService.cs index 23929ec65..511aa8500 100644 --- a/WebAPI/LearningHub.Nhs.Services.Interface/IResourceService.cs +++ b/WebAPI/LearningHub.Nhs.Services.Interface/IResourceService.cs @@ -233,8 +233,9 @@ public interface IResourceService /// Get file directory for unpublished or deleted versions. /// /// The resourceVersionId. + /// . /// The . - Task> GetObsoleteResourceFile(int resourceVersionId); + Task> GetObsoleteResourceFile(int resourceVersionId, bool deletedResource = false); /// /// Delete resource version async. diff --git a/WebAPI/LearningHub.Nhs.Services/CatalogueService.cs b/WebAPI/LearningHub.Nhs.Services/CatalogueService.cs index f9c26859d..c34cc4b9f 100644 --- a/WebAPI/LearningHub.Nhs.Services/CatalogueService.cs +++ b/WebAPI/LearningHub.Nhs.Services/CatalogueService.cs @@ -259,6 +259,7 @@ public async Task CreateCatalogueAsync(int userId, if (cnv != null) { var searchModel = this.mapper.Map(cnv); + searchModel.Description = searchModel.Description.Substring(0, 2995) + "

"; await this.findwiseApiFacade.AddOrReplaceAsync(new List { searchModel }); } diff --git a/WebAPI/LearningHub.Nhs.Services/ResourceService.cs b/WebAPI/LearningHub.Nhs.Services/ResourceService.cs index 2993e46af..9ff98ef4a 100644 --- a/WebAPI/LearningHub.Nhs.Services/ResourceService.cs +++ b/WebAPI/LearningHub.Nhs.Services/ResourceService.cs @@ -1320,12 +1320,12 @@ public async Task> GetResourceVersionsAsync(int r /// Get file directory for unpublished or deleted versions. ///
/// The resourceVersionId. + /// . /// The . - public async Task> GetObsoleteResourceFile(int resourceVersionId) + public async Task> GetObsoleteResourceFile(int resourceVersionId, bool deletedResource = false) { var retVal = new List(); - File fileDetails = null; - var resource = await this.GetResourceVersionByIdAsync(resourceVersionId); + var resource = await this.GetResourceVersionExtendedViewModelAsync(resourceVersionId); var rvs = await this.resourceVersionRepository.GetResourceVersionsAsync(resource.ResourceId); rvs = rvs.Where(x => x.Id != resourceVersionId && x.PublicationId > 0).OrderByDescending(x => x.PublicationId).ToList(); var rv = rvs.FirstOrDefault(); @@ -1334,21 +1334,209 @@ public async Task> GetObsoleteResourceFile(int resourceVersionId) var extendedResourceVersion = await this.GetResourceVersionExtendedViewModelAsync(rv.Id); if (extendedResourceVersion.ResourceTypeEnum == ResourceTypeEnum.Scorm) { - retVal.Add(extendedResourceVersion.ScormDetails.ContentFilePath); + if (resource.ScormDetails?.ContentFilePath != extendedResourceVersion.ScormDetails.ContentFilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.ScormDetails.ContentFilePath); + } + else + { + retVal.Add(resource.ScormDetails?.File?.FilePath); + } + } } else if (extendedResourceVersion.ResourceTypeEnum == ResourceTypeEnum.Html) { - retVal.Add(extendedResourceVersion.HtmlDetails.ContentFilePath); + if (resource.HtmlDetails?.ContentFilePath != extendedResourceVersion.HtmlDetails.ContentFilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.HtmlDetails.ContentFilePath); + } + else + { + retVal.Add(resource.HtmlDetails?.File?.FilePath); + } + } + } + else if (extendedResourceVersion.ResourceTypeEnum == ResourceTypeEnum.GenericFile) + { + if (resource.GenericFileDetails.File.FilePath != extendedResourceVersion.GenericFileDetails.File.FilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.GenericFileDetails.File.FilePath); + } + else + { + retVal.Add(resource.GenericFileDetails.File.FilePath); + } + } + } + else if (extendedResourceVersion.ResourceTypeEnum == ResourceTypeEnum.Image) + { + if (resource.ImageDetails.File.FilePath != extendedResourceVersion.ImageDetails.File.FilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.ImageDetails.File.FilePath); + } + else + { + retVal.Add(resource.ImageDetails.File.FilePath); + } + } } else if (extendedResourceVersion.ResourceTypeEnum == ResourceTypeEnum.Audio) { - retVal.Add(extendedResourceVersion.AudioDetails.File.FilePath); - retVal.Add(extendedResourceVersion.AudioDetails.ResourceAzureMediaAsset.FilePath); + if (resource.AudioDetails?.File?.FilePath != extendedResourceVersion.AudioDetails.File.FilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.AudioDetails.File.FilePath); + } + else + { + retVal.Add(resource.AudioDetails.File.FilePath); + } + } + + if (resource.AudioDetails?.ResourceAzureMediaAsset?.FilePath != extendedResourceVersion.AudioDetails.ResourceAzureMediaAsset.FilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.AudioDetails.ResourceAzureMediaAsset.FilePath); + } + else + { + retVal.Add(resource.AudioDetails.ResourceAzureMediaAsset.FilePath); + } + } } else if (extendedResourceVersion.ResourceTypeEnum == ResourceTypeEnum.Video) { - retVal.Add(extendedResourceVersion.VideoDetails.File.FilePath); - retVal.Add(extendedResourceVersion.VideoDetails.ResourceAzureMediaAsset.FilePath); + if (resource.VideoDetails?.File?.FilePath != extendedResourceVersion.VideoDetails.File.FilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.VideoDetails.File.FilePath); + } + else + { + retVal.Add(resource.VideoDetails.File.FilePath); + } + } + + if (resource.VideoDetails?.ResourceAzureMediaAsset?.FilePath != extendedResourceVersion.VideoDetails.ResourceAzureMediaAsset.FilePath) + { + if (!deletedResource) + { + retVal.Add(extendedResourceVersion.VideoDetails.ResourceAzureMediaAsset.FilePath); + } + else + { + retVal.Add(resource.VideoDetails.ResourceAzureMediaAsset.FilePath); + } + } + } + else if (extendedResourceVersion.ResourceTypeEnum == ResourceTypeEnum.Article) + { + var inputResourceFiles = resource.ArticleDetails.Files.ToList(); + var previousPublishedfiles = extendedResourceVersion.ArticleDetails?.Files?.ToList(); + if (!deletedResource) + { + if (previousPublishedfiles.Any()) + { + foreach (var file in previousPublishedfiles) + { + if (!inputResourceFiles.Where(x => x.FilePath == file.FilePath).Any()) + { + retVal.Add(file.FilePath); + } + } + } + } + else + { + if (inputResourceFiles.Any()) + { + foreach (var file in inputResourceFiles) + { + if (!previousPublishedfiles.Where(x => x.FilePath == file.FilePath).Any()) + { + retVal.Add(file.FilePath); + } + } + } + } + } + else if (resource.ResourceTypeEnum == ResourceTypeEnum.Case) + { + if (deletedResource) + { + if (resource != null) + { + var allBlocks = resource.CaseDetails.BlockCollection.Blocks.ToList(); + if (allBlocks.Any()) + { + var existingAttachements = allBlocks.Where(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Attachment && x.MediaBlock.Attachment != null).ToList(); + if (existingAttachements.Any()) + { + foreach (var oldblock in existingAttachements) + { + retVal.Add(oldblock.MediaBlock.Attachment?.File?.FilePath); + } + } + + var existingVideos = allBlocks.Where(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Video && x.MediaBlock.Video != null).ToList(); + if (existingVideos.Any()) + { + foreach (var oldblock in existingVideos) + { + retVal.Add(oldblock.MediaBlock.Video?.VideoFile?.File?.FilePath); + if (oldblock.MediaBlock?.Video?.VideoFile.TranscriptFile?.File.FilePath != null) + { + retVal.Add(oldblock.MediaBlock.Video?.VideoFile?.TranscriptFile?.File?.FilePath); + } + } + } + + var existingImages = allBlocks.Where(x => x.BlockType == BlockType.Media && x.MediaBlock != null && x.MediaBlock.MediaType == MediaType.Image && x.MediaBlock.Image != null).ToList(); + if (existingImages.Any()) + { + foreach (var oldblock in existingImages) + { + retVal.Add(oldblock.MediaBlock?.Image?.File?.FilePath); + } + } + + var existingImageCarousel = allBlocks.Where(x => x.BlockType == BlockType.ImageCarousel && x.ImageCarouselBlock != null && x.ImageCarouselBlock.ImageBlockCollection != null && x.ImageCarouselBlock.ImageBlockCollection.Blocks != null).ToList(); + if (existingImageCarousel.Any()) + { + foreach (var imageBlock in existingImageCarousel) + { + foreach (var oldblock in imageBlock.ImageCarouselBlock.ImageBlockCollection.Blocks) + { + retVal.Add(oldblock.MediaBlock?.Image?.File?.FilePath); + } + } + } + + var existingWholeSlideImages = allBlocks.Where(x => x.WholeSlideImageBlock != null && x.WholeSlideImageBlock.WholeSlideImageBlockItems.Any()).ToList(); + if (existingWholeSlideImages.Any()) + { + foreach (var wsi in existingWholeSlideImages) + { + foreach (var oldblock in wsi.WholeSlideImageBlock.WholeSlideImageBlockItems) + { + retVal.Add(oldblock.WholeSlideImage?.File?.FilePath); + } + } + } + } + } + } } }