Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEST-370: Create Media Theme caching for templates #17

Merged
merged 4 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions Lombiq.Hosting.MediaTheme.Bridge/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using Lombiq.Hosting.MediaTheme.Bridge.Constants;
using Lombiq.HelpfulLibraries.OrchardCore.DependencyInjection;
using Lombiq.Hosting.MediaTheme.Bridge.Constants;
using Lombiq.Hosting.MediaTheme.Bridge.Services;
using Lombiq.Hosting.MediaTheme.Bridge.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.Extensions.Localization;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Notify;
using OrchardCore.Themes.Services;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -18,23 +21,30 @@ public class AdminController : Controller
private readonly IMediaThemeStateStore _mediaThemeStateStore;
private readonly IUpdateModelAccessor _updateModelAccessor;
private readonly IStringLocalizer<AdminController> T;
private readonly IHtmlLocalizer<AdminController> H;
private readonly IMediaThemeManager _mediaThemeManager;
private readonly ISiteThemeService _siteThemeService;
private readonly IMediaThemeCachingService _mediaThemeCachingService;
private readonly INotifier _notifier;

public AdminController(
IAuthorizationService authorizationService,
IOrchardServices<AdminController> orchardServices,
IMediaThemeStateStore mediaThemeStateStore,
IUpdateModelAccessor updateModelAccessor,
IStringLocalizer<AdminController> stringLocalizer,
IMediaThemeManager mediaThemeManager,
ISiteThemeService siteThemeService)
ISiteThemeService siteThemeService,
IMediaThemeCachingService mediaThemeCachingService,
INotifier notifier)
{
_authorizationService = authorizationService;
_authorizationService = orchardServices.AuthorizationService.Value;
_mediaThemeStateStore = mediaThemeStateStore;
_updateModelAccessor = updateModelAccessor;
T = stringLocalizer;
T = orchardServices.StringLocalizer.Value;
_mediaThemeManager = mediaThemeManager;
_siteThemeService = siteThemeService;
_mediaThemeCachingService = mediaThemeCachingService;
_notifier = notifier;
H = orchardServices.HtmlLocalizer.Value;
}

[HttpGet]
Expand Down Expand Up @@ -78,6 +88,17 @@ public async Task<ActionResult> IndexPost(MediaThemeSettingsViewModel viewModel)
return RedirectToAction(nameof(Index));
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteMediaThemeTemplateCache()
{
if (!await IsAuthorizedToManageMediaThemeAsync()) return NotFound();

await _mediaThemeCachingService.InvalidateCachedMediaThemeTemplatesAsync();
await _notifier.SuccessAsync(H["Media Theme template cache was invalidated successfully!"]);
return RedirectToAction(nameof(Index));
}

private Task<bool> IsAuthorizedToManageMediaThemeAsync() =>
_authorizationService.AuthorizeAsync(User, ManageMediaTheme);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Lombiq.Hosting.MediaTheme.Bridge.Models;
using System.Threading.Tasks;

namespace Lombiq.Hosting.MediaTheme.Bridge.Services;

/// <summary>
/// Media Theme template cache store and invalidation functions.
/// </summary>
public interface IMediaThemeCachingService
{
/// <summary>
/// Returns <see cref="MediaTemplate"/> if cached, else tries to fetch it from the storage. If not available stores
/// and returns <see langword="null"/>.
/// </summary>
/// <param name="shapeType">The searched shape type.</param>
Task<MediaTemplate> GetMemoryCachedMediaTemplateAsync(string shapeType);

/// <summary>
/// Deletes all Media Theme templates from the cache.
/// </summary>
Task InvalidateCachedMediaThemeTemplatesAsync();
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ public class MediaTemplatesShapeBindingResolver : IShapeBindingResolver
private readonly ILiquidTemplateManager _liquidTemplateManager;
private readonly IHttpContextAccessor _hca;
private readonly HtmlEncoder _htmlEncoder;
private readonly IMediaThemeManager _mediaThemeManager;
private readonly IMediaThemeCachingService _mediaThemeCachingService;

public MediaTemplatesShapeBindingResolver(
ILiquidTemplateManager liquidTemplateManager,
IHttpContextAccessor hca,
HtmlEncoder htmlEncoder,
IMediaThemeManager mediaThemeManager)
IMediaThemeCachingService mediaThemeCachingService)
{
_liquidTemplateManager = liquidTemplateManager;
_hca = hca;
_htmlEncoder = htmlEncoder;
_mediaThemeManager = mediaThemeManager;
_mediaThemeCachingService = mediaThemeCachingService;
}

public async Task<ShapeBinding> GetShapeBindingAsync(string shapeType)
Expand All @@ -34,7 +34,7 @@ public async Task<ShapeBinding> GetShapeBindingAsync(string shapeType)
return null;
}

return await _mediaThemeManager.GetMediaTemplateByShapeTypeAsync(shapeType) is not { } mediaTemplate
return await _mediaThemeCachingService.GetMemoryCachedMediaTemplateAsync(shapeType) is not { } mediaTemplate
? null
: BuildShapeBinding(shapeType, mediaTemplate.Content);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Lombiq.Hosting.MediaTheme.Bridge.Models;
using Microsoft.Extensions.Caching.Memory;
using OrchardCore.Environment.Cache;
using System.Threading.Tasks;

namespace Lombiq.Hosting.MediaTheme.Bridge.Services;

public class MediaThemeCachingService : IMediaThemeCachingService
{
private const string MediaThemeMemoryCacheKeyPrefix = "Lombiq.Hosting.MediaTheme.Bridge";

private readonly IMemoryCache _memoryCache;
private readonly IMediaThemeManager _mediaThemeManager;
private readonly ISignal _signal;

public MediaThemeCachingService(
IMemoryCache memoryCache,
IMediaThemeManager mediaThemeManager,
ISignal signal)
{
_memoryCache = memoryCache;
_mediaThemeManager = mediaThemeManager;
_signal = signal;
}

public async Task<MediaTemplate> GetMemoryCachedMediaTemplateAsync(string shapeType)
{
var cacheKey = $"{MediaThemeMemoryCacheKeyPrefix}:{shapeType}";
if (_memoryCache.TryGetValue(cacheKey, out MediaTemplate cachedMediaTemplate))
{
return cachedMediaTemplate;
}

cachedMediaTemplate = await _mediaThemeManager.GetMediaTemplateByShapeTypeAsync(shapeType);
_memoryCache.Set(cacheKey, cachedMediaTemplate, _signal.GetToken(MediaThemeMemoryCacheKeyPrefix));

return cachedMediaTemplate;
}

public Task InvalidateCachedMediaThemeTemplatesAsync() => _signal.SignalTokenAsync(MediaThemeMemoryCacheKeyPrefix);
}
1 change: 1 addition & 0 deletions Lombiq.Hosting.MediaTheme.Bridge/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public override void ConfigureServices(IServiceCollection services)
services.AddSingleton<IDeploymentStepFactory>(new DeploymentStepFactory<MediaThemeDeploymentStep>());
services.AddScoped<IDisplayDriver<DeploymentStep>, MediaThemeDeploymentStepDriver>();
services.AddScoped<IAuthorizationHandler, ManageMediaThemeFolderAuthorizationHandler>();
services.AddScoped<IMediaThemeCachingService, MediaThemeCachingService>();
}

public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
Expand Down
7 changes: 7 additions & 0 deletions Lombiq.Hosting.MediaTheme.Bridge/Views/Admin/Index.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,10 @@
<button type="submit" class="btn btn-primary">@T["Submit"]</button>
</div>
</form>

<form asp-action="DeleteMediaThemeTemplateCache" asp-controller="Admin" asp-area="Lombiq.Hosting.MediaTheme.Bridge" method="post" class="no-multisubmit">
@Html.ValidationSummary()
<div class="mb-3">
<button type="submit" class="btn btn-danger">@T["Invalidate Media Theme templates cache."]</button>
</div>
</form>