diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs index c84dbc2f..5f329c61 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs @@ -337,6 +337,7 @@ public async Task SendAdminPasswordResetEmail(int u public async Task ClearUserCachedPermissions(int userId) { await this.cacheService.RemoveAsync($"{userId}:AllRolesWithPermissions"); + await this.cacheService.RemoveAsync($"{userId}:UserHasPublishedResources"); return new LearningHubValidationResult(true); } diff --git a/LearningHub.Nhs.WebUI/Services/ResourceService.cs b/LearningHub.Nhs.WebUI/Services/ResourceService.cs index ec8eaee3..6f9ed68a 100644 --- a/LearningHub.Nhs.WebUI/Services/ResourceService.cs +++ b/LearningHub.Nhs.WebUI/Services/ResourceService.cs @@ -6,10 +6,12 @@ namespace LearningHub.Nhs.WebUI.Services using System.Net.Http; using System.Text; using System.Threading.Tasks; + using LearningHub.Nhs.Caching; using LearningHub.Nhs.Models.Common; using LearningHub.Nhs.Models.Entities.Activity; using LearningHub.Nhs.Models.Entities.Resource; using LearningHub.Nhs.Models.Enums; + using LearningHub.Nhs.Models.Extensions; using LearningHub.Nhs.Models.Hierarchy; using LearningHub.Nhs.Models.Resource; using LearningHub.Nhs.Models.Resource.Contribute; @@ -17,6 +19,7 @@ namespace LearningHub.Nhs.WebUI.Services using LearningHub.Nhs.Models.Validation; using LearningHub.Nhs.WebUI.Interfaces; using LearningHub.Nhs.WebUI.Models; + using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; @@ -29,6 +32,8 @@ public class ResourceService : BaseService, IResourceService { private readonly Settings settings; private readonly IAzureMediaService azureMediaService; + private readonly IHttpContextAccessor contextAccessor; + private readonly ICacheService cacheService; /// /// Initializes a new instance of the class. @@ -36,13 +41,17 @@ public class ResourceService : BaseService, IResourceService /// Learning hub http client. /// The Open Api Http Client. /// Azure media services. + /// The http context accessor. + /// The cacheService. /// Logger. /// Settings. - public ResourceService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, IAzureMediaService azureMediaService, ILogger logger, IOptions settings) + public ResourceService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, IAzureMediaService azureMediaService, IHttpContextAccessor contextAccessor, ICacheService cacheService, ILogger logger, IOptions settings) : base(learningHubHttpClient, openApiHttpClient, logger) { this.settings = settings.Value; this.azureMediaService = azureMediaService; + this.contextAccessor = contextAccessor; + this.cacheService = cacheService; } /// @@ -885,24 +894,8 @@ public async Task UnpublishResourceVersionAsync(int /// The . public async Task UserHasPublishedResourcesAsync() { - var client = await this.OpenApiHttpClient.GetClientAsync(); - - var request = $"Resource/HasPublishedResources"; - var response = await client.GetAsync(request).ConfigureAwait(false); - bool hasResources = false; - if (response.IsSuccessStatusCode) - { - var result = response.Content.ReadAsStringAsync().Result; - hasResources = bool.Parse(result); - } - else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized - || - response.StatusCode == System.Net.HttpStatusCode.Forbidden) - { - throw new Exception("AccessDenied"); - } - - return hasResources; + var cacheKey = $"{this.contextAccessor.HttpContext.User.Identity.GetCurrentUserId()}:UserHasPublishedResources"; + return await this.cacheService.GetOrFetchAsync("UserHasPublishedResources", () => this.HasPublishedResources()); } /// @@ -1340,5 +1333,32 @@ public async Task> GetObsoleteResourceFile(int resourceVersionId, b return filePaths; } + + /// + /// Check if the user has published resources. + /// + /// The bool. + /// + private async Task HasPublishedResources() + { + var client = await this.OpenApiHttpClient.GetClientAsync(); + + var request = $"Resource/HasPublishedResources"; + var response = await client.GetAsync(request).ConfigureAwait(false); + bool hasResources = false; + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + hasResources = bool.Parse(result); + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + + return hasResources; + } } } diff --git a/LearningHub.Nhs.WebUI/ViewComponents/NavigationItemsViewComponent.cs b/LearningHub.Nhs.WebUI/ViewComponents/NavigationItemsViewComponent.cs index 6b81891c..717e92aa 100644 --- a/LearningHub.Nhs.WebUI/ViewComponents/NavigationItemsViewComponent.cs +++ b/LearningHub.Nhs.WebUI/ViewComponents/NavigationItemsViewComponent.cs @@ -57,10 +57,19 @@ public async Task InvokeAsync(string navView = "Default", var userId = this.User.Identity.GetCurrentUserId(); var (cacheExists, _) = await this.cacheService.TryGetAsync($"{userId}:LoginWizard"); - model = await this.permissionService.GetNavigationModelAsync(this.User, !cacheExists, controllerName); - model.NotificationCount = await this.notificationService.GetUserUnreadNotificationCountAsync(userId); + // Check if NotificationCount is already stored for this request + if (this.HttpContext.Items.TryGetValue("NotificationCount", out var cachedCount)) + { + model.NotificationCount = (int)cachedCount; + } + else + { + var count = await this.notificationService.GetUserUnreadNotificationCountAsync(userId); + this.HttpContext.Items["NotificationCount"] = count; + model.NotificationCount = count; + } } return await Task.FromResult(this.View(navView, model)); diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/ResourceService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/ResourceService.cs index 4534e475..13f99992 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/ResourceService.cs +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/ResourceService.cs @@ -27,6 +27,7 @@ namespace LearningHub.Nhs.OpenApi.Services.Services using LearningHub.Nhs.Models.Resource.Contribute; using LearningHub.Nhs.Models.Resource.Files; using LearningHub.Nhs.Models.Resource.ResourceDisplay; + using LearningHub.Nhs.Models.User; using LearningHub.Nhs.Models.Validation; using LearningHub.Nhs.Models.ViewModels.Helpers; using LearningHub.Nhs.OpenApi.Models.Configuration; @@ -170,7 +171,7 @@ public class ResourceService : IResourceService /// The repository for assessment activity-question matches. /// The repository for resource version keywords. /// The repository for validation results of resource versions. - + public ResourceService(ILearningHubService learningHubService, IFileTypeService fileTypeService, IBlockCollectionRepository blockCollectionRepository, IInternalSystemService internalSystemService, IResourceVersionAuthorRepository resourceVersionAuthorRepository, IFileChunkDetailRepository fileChunkDetailRepository, IQueueCommunicatorService queueCommunicatorService, IResourceRepository resourceRepository, IResourceVersionProviderRepository resourceVersionProviderRepository, IProviderService providerService, IArticleResourceVersionFileRepository articleResourceVersionFileRepository, IPublicationRepository publicationRepository, IMigrationSourceRepository migrationSourceRepository, IQuestionBlockRepository questionBlockRepository, IVideoRepository videoRepository, IWholeSlideImageRepository wholeSlideImageRepository, IEmbeddedResourceVersionRepository embeddedResourceVersionRepository, IEquipmentResourceVersionRepository equipmentResourceVersionRepository, IImageResourceVersionRepository imageResourceVersionRepository, IBookmarkRepository bookmarkRepository, IAssessmentResourceActivityMatchQuestionRepository assessmentResourceActivityMatchQuestionRepository, IResourceVersionKeywordRepository resourceVersionKeywordRepository, IResourceVersionValidationResultRepository resourceVersionValidationResultRepository, ILogger logger, IWebLinkResourceVersionRepository webLinkResourceVersionRepository, ICaseResourceVersionRepository caseResourceVersionRepository, IScormResourceVersionRepository scormResourceVersionRepository, IGenericFileResourceVersionRepository genericFileResourceVersionRepository, IResourceVersionRepository resourceVersionRepository, IHtmlResourceVersionRepository htmlResourceVersionRepository, IMapper mapper, IFileRepository fileRepository, IOptions azureConfig, IOptions learningHubConfig, IUserProfileService userProfileService, IResourceVersionFlagRepository resourceVersionFlagRepository, IArticleResourceVersionRepository articleResourceVersionRepository, IAudioResourceVersionRepository audioResourceVersionRepository, IVideoResourceVersionRepository videoResourceVersionRepository, IAssessmentResourceVersionRepository assessmentResourceVersionRepository, IResourceLicenceRepository resourceLicenceRepository, IResourceReferenceRepository resourceReferenceRepository, IResourceVersionUserAcceptanceRepository resourceVersionUserAcceptanceRepository, ICatalogueNodeVersionRepository catalogueNodeVersionRepository, ICachingService cachingService, ISearchService searchService, ICatalogueService catalogueService, INodeResourceRepository nodeResourceRepository, INodePathRepository nodePathRepository, IUserService userService, INodeRepository nodeRepository, IResourceSyncService resourceSyncService, IResourceSyncRepository resourceSyncRepository, IResourceVersionEventRepository resourceVersionEventRepository, LearningHubDbContext dbContext) { @@ -206,8 +207,8 @@ public ResourceService(ILearningHubService learningHubService, IFileTypeService this.resourceVersionFlagRepository = resourceVersionFlagRepository; this.resourceVersionUserAcceptanceRepository = resourceVersionUserAcceptanceRepository; this.resourceVersionValidationResultRepository = resourceVersionValidationResultRepository; - this.resourceVersionKeywordRepository= resourceVersionKeywordRepository; - this.resourceVersionProviderRepository= resourceVersionProviderRepository; + this.resourceVersionKeywordRepository = resourceVersionKeywordRepository; + this.resourceVersionProviderRepository = resourceVersionProviderRepository; this.providerService = providerService; this.nodePathRepository = nodePathRepository; this.nodeResourceRepository = nodeResourceRepository; @@ -323,7 +324,7 @@ public async Task> GetResour List resourceActivities = new List() { }; List resourceReferenceWithResourceDetailsViewModelLS = new List() { }; - resourceActivities = (await this.resourceRepository.GetResourceActivityPerResourceMajorVersion(new List(){ }, new List(){ currentUserId }))?.ToList() ?? new List() { }; + resourceActivities = (await this.resourceRepository.GetResourceActivityPerResourceMajorVersion(new List() { }, new List() { currentUserId }))?.ToList() ?? new List() { }; // Removing resources that have no major versions with the required activitystatus List resourceIds = resourceActivities @@ -1332,7 +1333,21 @@ public MyContributionsTotalsViewModel GetMyContributionTotals(int catalogueId, i /// If the user has published resources. public async Task HasPublishedResourcesAsync(int userId) { - return await this.resourceRepository.UserHasPublishedResourcesAsync(userId); + string cacheKey = $"{userId}:UserHasPublishedResources"; + var userHasPublishedResourcesInCache = await this.cachingService.GetAsync(cacheKey); + var userHasPublishedResources = false; + + if (userHasPublishedResourcesInCache.ResponseEnum == CacheReadResponseEnum.Found) + { + userHasPublishedResources = userHasPublishedResourcesInCache.Item; + } + else + { + userHasPublishedResources = await this.resourceRepository.UserHasPublishedResourcesAsync(userId); + await this.cachingService.SetAsync($"{userId}:UserHasPublishedResources", userHasPublishedResources); + } + + return userHasPublishedResources; } ///