From c5b632cb244018180bc25de02a77b4269fcd9a8d Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Tue, 4 Oct 2022 19:20:02 -0400 Subject: [PATCH] Enhance SyncManager to raise events which can be handled on the server within hosted services. Raise create, update, delete events for all major entities. Include support for refresh and reload events to synchronize client state. Move client state cache invalidation to a hosted service to separate concerns and demonstrate events. --- Oqtane.Client/UI/Refresh.cs | 9 ---- Oqtane.Client/UI/SiteRouter.razor | 22 ++++----- Oqtane.Server/Controllers/AliasController.cs | 7 ++- Oqtane.Server/Controllers/FileController.cs | 13 ++++-- Oqtane.Server/Controllers/FolderController.cs | 8 +++- .../Controllers/LanguageController.cs | 6 ++- Oqtane.Server/Controllers/ModuleController.cs | 9 ++-- .../Controllers/ModuleDefinitionController.cs | 6 ++- .../Controllers/NotificationController.cs | 8 +++- Oqtane.Server/Controllers/PageController.cs | 16 ++++--- .../Controllers/PageModuleController.cs | 13 ++++-- .../Controllers/ProfileController.cs | 7 ++- Oqtane.Server/Controllers/RoleController.cs | 7 ++- .../Controllers/SettingController.cs | 12 ++--- Oqtane.Server/Controllers/SiteController.cs | 9 ++-- Oqtane.Server/Controllers/TenantController.cs | 6 +-- .../Controllers/UrlMappingController.cs | 7 ++- Oqtane.Server/Controllers/UserController.cs | 9 ++-- .../Controllers/UserRoleController.cs | 9 ++-- .../OqtaneServiceCollectionExtensions.cs | 2 +- .../CacheInvalidationService.cs | 45 +++++++++++++++++++ .../Infrastructure/Interfaces/ISyncManager.cs | 4 +- Oqtane.Server/Infrastructure/SyncManager.cs | 32 ++++++------- Oqtane.Server/Startup.cs | 2 +- Oqtane.Shared/Models/Sync.cs | 4 +- Oqtane.Shared/Shared/EntityNames.cs | 20 ++++++--- Oqtane.Shared/Shared/SyncEventActions.cs | 12 +++++ 27 files changed, 212 insertions(+), 92 deletions(-) delete mode 100644 Oqtane.Client/UI/Refresh.cs create mode 100644 Oqtane.Server/Infrastructure/CacheInvalidationService.cs create mode 100644 Oqtane.Shared/Shared/SyncEventActions.cs diff --git a/Oqtane.Client/UI/Refresh.cs b/Oqtane.Client/UI/Refresh.cs deleted file mode 100644 index d6cd771c..00000000 --- a/Oqtane.Client/UI/Refresh.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Oqtane.UI -{ - public enum Refresh - { - None, - Site, - Application - } -} diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 523acfe8..de6707bc 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -79,7 +79,7 @@ Page page; User user = null; var editmode = false; - var refresh = UI.Refresh.None; + var refresh = false; var lastsyncdate = DateTime.UtcNow.AddHours(-1); var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime); _error = ""; @@ -116,7 +116,7 @@ // the refresh parameter is used to refresh the client-side PageState if (querystring.ContainsKey("refresh")) { - refresh = UI.Refresh.Site; + refresh = true; } if (PageState != null) @@ -126,7 +126,7 @@ } // get user - if (PageState == null || refresh == UI.Refresh.Site || PageState.Alias.SiteId != SiteState.Alias.SiteId) + if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId) { var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); if (authState.User.Identity.IsAuthenticated) @@ -149,27 +149,27 @@ if (sync.SyncEvents.Any()) { // reload client application if server was restarted or site runtime/rendermode was modified - if (PageState != null && sync.SyncEvents.Exists(item => (item.TenantId == -1 || item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId) && item.Reload)) + if (PageState != null && sync.SyncEvents.Exists(item => (item.Action == SyncEventActions.Reload))) { NavigationManager.NavigateTo(_absoluteUri, true); return; } - // when a site has changed the state needs to be refreshed + // when site information has changed the PageState needs to be refreshed if (sync.SyncEvents.Exists(item => item.EntityName == EntityNames.Site && item.EntityId == SiteState.Alias.SiteId)) { - refresh = UI.Refresh.Site; + refresh = true; } - // when a user changed the site needs to be refreshed as the list of pages/modules may have changed + // when user information has changed the PageState needs to be refreshed as the list of pages/modules may have changed if (user != null && sync.SyncEvents.Exists(item => item.EntityName == EntityNames.User && item.EntityId == user.UserId)) { - refresh = UI.Refresh.Site; + refresh = true; } } - if (PageState == null || refresh == UI.Refresh.Site || PageState.Alias.SiteId != SiteState.Alias.SiteId) + if (PageState == null || refresh || PageState.Alias.SiteId != SiteState.Alias.SiteId) { site = await SiteService.GetSiteAsync(SiteState.Alias.SiteId); - refresh = UI.Refresh.Site; + refresh = true; } else { @@ -178,7 +178,7 @@ if (site != null) { - if (PageState == null || refresh == UI.Refresh.Site || PageState.Page.Path != route.PagePath) + if (PageState == null || refresh || PageState.Page.Path != route.PagePath) { page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase)); editmode = false; diff --git a/Oqtane.Server/Controllers/AliasController.cs b/Oqtane.Server/Controllers/AliasController.cs index c87176e5..adaf3945 100644 --- a/Oqtane.Server/Controllers/AliasController.cs +++ b/Oqtane.Server/Controllers/AliasController.cs @@ -17,13 +17,15 @@ namespace Oqtane.Controllers { private readonly IAliasRepository _aliases; private readonly ITenantRepository _tenants; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public AliasController(IAliasRepository aliases, ITenantRepository tenants, ILogManager logger, ITenantManager tenantManager) + public AliasController(IAliasRepository aliases, ITenantRepository tenants, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _aliases = aliases; _tenants = tenants; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -57,6 +59,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { alias = _aliases.AddAlias(alias); + _syncManager.AddSyncEvent(alias.TenantId, EntityNames.Alias, alias.AliasId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Alias Added {Alias}", alias); } else @@ -76,6 +79,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && _aliases.GetAlias(alias.AliasId, false) != null) { alias = _aliases.UpdateAlias(alias); + _syncManager.AddSyncEvent(alias.TenantId, EntityNames.Alias, alias.AliasId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Alias Updated {Alias}", alias); } else @@ -96,6 +100,7 @@ namespace Oqtane.Controllers if (alias != null) { _aliases.DeleteAlias(id); + _syncManager.AddSyncEvent(alias.TenantId, EntityNames.Alias, alias.AliasId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Alias Deleted {AliasId}", id); var aliases = _aliases.GetAliases(); diff --git a/Oqtane.Server/Controllers/FileController.cs b/Oqtane.Server/Controllers/FileController.cs index 9f95cd70..5594b168 100644 --- a/Oqtane.Server/Controllers/FileController.cs +++ b/Oqtane.Server/Controllers/FileController.cs @@ -32,15 +32,17 @@ namespace Oqtane.Controllers private readonly IFileRepository _files; private readonly IFolderRepository _folders; private readonly IUserPermissions _userPermissions; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager) + public FileController(IWebHostEnvironment environment, IFileRepository files, IFolderRepository folders, IUserPermissions userPermissions, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _environment = environment; _files = files; _folders = folders; _userPermissions = userPermissions; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -148,6 +150,7 @@ namespace Oqtane.Controllers file.Extension = Path.GetExtension(file.Name).ToLower().Replace(".", ""); file = _files.UpdateFile(file); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.File, file.FileId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "File Updated {File}", file); } else @@ -168,8 +171,6 @@ namespace Oqtane.Controllers Models.File file = _files.GetFile(id); if (file != null && file.Folder.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Folder, file.Folder.FolderId, PermissionNames.Edit)) { - _files.DeleteFile(id); - string filepath = _files.GetFilePath(file); if (System.IO.File.Exists(filepath)) { @@ -180,6 +181,8 @@ namespace Oqtane.Controllers } } + _files.DeleteFile(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.File, file.FileId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "File Deleted {File}", file); } else @@ -251,6 +254,7 @@ namespace Oqtane.Controllers if (file != null) { file = _files.AddFile(file); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.File, file.FileId, SyncEventActions.Create); } } catch (Exception ex) @@ -324,7 +328,8 @@ namespace Oqtane.Controllers var file = CreateFile(upload, FolderId, Path.Combine(folderPath, upload)); if (file != null) { - _files.AddFile(file); + file = _files.AddFile(file); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.File, file.FileId, SyncEventActions.Create); } } } diff --git a/Oqtane.Server/Controllers/FolderController.cs b/Oqtane.Server/Controllers/FolderController.cs index cb2c0cf0..d15f89f3 100644 --- a/Oqtane.Server/Controllers/FolderController.cs +++ b/Oqtane.Server/Controllers/FolderController.cs @@ -20,13 +20,15 @@ namespace Oqtane.Controllers { private readonly IFolderRepository _folders; private readonly IUserPermissions _userPermissions; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public FolderController(IFolderRepository folders, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager) + public FolderController(IFolderRepository folders, IUserPermissions userPermissions, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _folders = folders; _userPermissions = userPermissions; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -124,6 +126,7 @@ namespace Oqtane.Controllers } folder.Path = folder.Path + "/"; folder = _folders.AddFolder(folder); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Folder, folder.FolderId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Folder Added {Folder}", folder); } else @@ -172,6 +175,7 @@ namespace Oqtane.Controllers } folder = _folders.UpdateFolder(folder); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Folder, folder.FolderId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Folder Updated {Folder}", folder); } else @@ -205,6 +209,7 @@ namespace Oqtane.Controllers { folder.Order = order; _folders.UpdateFolder(folder); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Folder, folder.FolderId, SyncEventActions.Update); } order += 2; } @@ -230,6 +235,7 @@ namespace Oqtane.Controllers Directory.Delete(_folders.GetFolderPath(folder)); } _folders.DeleteFolder(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Folder, folder.FolderId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Folder Deleted {FolderId}", id); } else diff --git a/Oqtane.Server/Controllers/LanguageController.cs b/Oqtane.Server/Controllers/LanguageController.cs index 0a9a9cc8..678b3f6d 100644 --- a/Oqtane.Server/Controllers/LanguageController.cs +++ b/Oqtane.Server/Controllers/LanguageController.cs @@ -102,7 +102,8 @@ namespace Oqtane.Controllers if (ModelState.IsValid && language.SiteId == _alias.SiteId) { language = _languages.AddLanguage(language); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Language, language.LanguageId, SyncEventActions.Create); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Language Added {Language}", language); } else @@ -122,7 +123,8 @@ namespace Oqtane.Controllers if (language != null && language.SiteId == _alias.SiteId) { _languages.DeleteLanguage(id); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Language, language.LanguageId, SyncEventActions.Delete); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Language Deleted {LanguageId}", id); } else diff --git a/Oqtane.Server/Controllers/ModuleController.cs b/Oqtane.Server/Controllers/ModuleController.cs index 60d23951..1ba4e8ce 100644 --- a/Oqtane.Server/Controllers/ModuleController.cs +++ b/Oqtane.Server/Controllers/ModuleController.cs @@ -124,7 +124,8 @@ namespace Oqtane.Controllers if (ModelState.IsValid && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, module.PageId, PermissionNames.Edit)) { module = _modules.AddModule(module); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Module, module.ModuleId, SyncEventActions.Create); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Module Added {Module}", module); } else @@ -174,7 +175,8 @@ namespace Oqtane.Controllers } } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Module, module.ModuleId, SyncEventActions.Update); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Updated {Module}", module); } else @@ -195,7 +197,8 @@ namespace Oqtane.Controllers if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Module, module.ModuleId, PermissionNames.Edit)) { _modules.DeleteModule(id); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Module, module.ModuleId, SyncEventActions.Delete); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Deleted {ModuleId}", id); } else diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs index d7cbd623..fae9a6a0 100644 --- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs +++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs @@ -29,10 +29,11 @@ namespace Oqtane.Controllers private readonly IWebHostEnvironment _environment; private readonly IServiceProvider _serviceProvider; private readonly ITenantManager _tenantManager; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ITenantManager tenantManager, ILogManager logger) + public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger) { _moduleDefinitions = moduleDefinitions; _tenants = tenants; @@ -42,6 +43,7 @@ namespace Oqtane.Controllers _environment = environment; _serviceProvider = serviceProvider; _tenantManager = tenantManager; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -145,6 +147,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && moduleDefinition.SiteId == _alias.SiteId && _moduleDefinitions.GetModuleDefinition(moduleDefinition.ModuleDefinitionId, moduleDefinition.SiteId) != null) { _moduleDefinitions.UpdateModuleDefinition(moduleDefinition); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduleDefinition.ModuleDefinitionId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Module Definition Updated {ModuleDefinition}", moduleDefinition); } else @@ -227,6 +230,7 @@ namespace Oqtane.Controllers // remove module definition _moduleDefinitions.DeleteModuleDefinition(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name); } else diff --git a/Oqtane.Server/Controllers/NotificationController.cs b/Oqtane.Server/Controllers/NotificationController.cs index c4c22f87..dfdba5f1 100644 --- a/Oqtane.Server/Controllers/NotificationController.cs +++ b/Oqtane.Server/Controllers/NotificationController.cs @@ -8,6 +8,7 @@ using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Security; using System.Net; +using System.Reflection.Metadata; namespace Oqtane.Controllers { @@ -16,13 +17,15 @@ namespace Oqtane.Controllers { private readonly INotificationRepository _notifications; private readonly IUserPermissions _userPermissions; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public NotificationController(INotificationRepository notifications, IUserPermissions userPermissions, ILogManager logger, ITenantManager tenantManager) + public NotificationController(INotificationRepository notifications, IUserPermissions userPermissions, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _notifications = notifications; _userPermissions = userPermissions; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -83,6 +86,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && notification.SiteId == _alias.SiteId && IsAuthorized(notification.FromUserId)) { notification = _notifications.AddNotification(notification); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Notification, notification.NotificationId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Notification Added {NotificationId}", notification.NotificationId); } else @@ -102,6 +106,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && notification.SiteId == _alias.SiteId && _notifications.GetNotification(notification.NotificationId, false) != null && IsAuthorized(notification.FromUserId)) { notification = _notifications.UpdateNotification(notification); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Notification, notification.NotificationId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Notification Updated {NotificationId}", notification.NotificationId); } else @@ -122,6 +127,7 @@ namespace Oqtane.Controllers if (notification != null && notification.SiteId == _alias.SiteId && (IsAuthorized(notification.FromUserId) || IsAuthorized(notification.ToUserId))) { _notifications.DeleteNotification(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Notification, notification.NotificationId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Notification Deleted {NotificationId}", id); } else diff --git a/Oqtane.Server/Controllers/PageController.cs b/Oqtane.Server/Controllers/PageController.cs index 5112924f..92cf36b6 100644 --- a/Oqtane.Server/Controllers/PageController.cs +++ b/Oqtane.Server/Controllers/PageController.cs @@ -143,7 +143,8 @@ namespace Oqtane.Controllers if (_userPermissions.IsAuthorized(User,PermissionNames.Edit, permissions)) { page = _pages.AddPage(page); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Create); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Page Added {Page}", page); if (!page.Path.StartsWith("admin/")) @@ -200,7 +201,8 @@ namespace Oqtane.Controllers page.IsPersonalizable = false; page.UserId = int.Parse(userid); page = _pages.AddPage(page); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Create); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId, SyncEventActions.Refresh); // copy modules List pagemodules = _pageModules.GetPageModules(page.SiteId).ToList(); @@ -313,7 +315,8 @@ namespace Oqtane.Controllers } } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Update); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Updated {Page}", page); } else @@ -353,10 +356,12 @@ namespace Oqtane.Controllers { page.Order = order; _pages.UpdatePage(page); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Update); } order += 2; } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, siteid); + + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, siteid, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Order Updated {SiteId} {PageId} {ParentId}", siteid, pageid, parentid); } else @@ -375,7 +380,8 @@ namespace Oqtane.Controllers if (page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, page.PageId, PermissionNames.Edit)) { _pages.DeletePage(page.PageId); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Page, page.PageId, SyncEventActions.Delete); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, page.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Page Deleted {PageId}", page.PageId); } else diff --git a/Oqtane.Server/Controllers/PageModuleController.cs b/Oqtane.Server/Controllers/PageModuleController.cs index 9b396d0d..619b7d77 100644 --- a/Oqtane.Server/Controllers/PageModuleController.cs +++ b/Oqtane.Server/Controllers/PageModuleController.cs @@ -9,6 +9,7 @@ using Oqtane.Infrastructure; using Oqtane.Repository; using Oqtane.Security; using System.Net; +using Microsoft.AspNetCore.Mvc.RazorPages; namespace Oqtane.Controllers { @@ -75,7 +76,8 @@ namespace Oqtane.Controllers if (ModelState.IsValid && page != null && page.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit)) { pageModule = _pageModules.AddPageModule(pageModule); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.PageModule, pageModule.PageModuleId, SyncEventActions.Create); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Page Module Added {PageModule}", pageModule); } else @@ -96,7 +98,8 @@ namespace Oqtane.Controllers if (ModelState.IsValid && page != null && page.SiteId == _alias.SiteId && _pageModules.GetPageModule(pageModule.PageModuleId, false) != null && _userPermissions.IsAuthorized(User, EntityNames.Page, pageModule.PageId, PermissionNames.Edit)) { pageModule = _pageModules.UpdatePageModule(pageModule); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.PageModule, pageModule.PageModuleId, SyncEventActions.Update); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Module Updated {PageModule}", pageModule); } else @@ -124,10 +127,11 @@ namespace Oqtane.Controllers { pagemodule.Order = order; _pageModules.UpdatePageModule(pagemodule); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.PageModule, pagemodule.PageModuleId, SyncEventActions.Update); } order += 2; } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Page Module Order Updated {PageId} {Pane}", pageid, pane); } else @@ -146,7 +150,8 @@ namespace Oqtane.Controllers if (pagemodule != null && pagemodule.Module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, EntityNames.Page, pagemodule.PageId, PermissionNames.Edit)) { _pageModules.DeletePageModule(id); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.PageModule, pagemodule.PageModuleId, SyncEventActions.Delete); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Page Module Deleted {PageModuleId}", id); } else diff --git a/Oqtane.Server/Controllers/ProfileController.cs b/Oqtane.Server/Controllers/ProfileController.cs index 9793b1c6..60becc5f 100644 --- a/Oqtane.Server/Controllers/ProfileController.cs +++ b/Oqtane.Server/Controllers/ProfileController.cs @@ -14,12 +14,14 @@ namespace Oqtane.Controllers public class ProfileController : Controller { private readonly IProfileRepository _profiles; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public ProfileController(IProfileRepository profiles, ILogManager logger, ITenantManager tenantManager) + public ProfileController(IProfileRepository profiles, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _profiles = profiles; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -66,6 +68,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && profile.SiteId == _alias.SiteId) { profile = _profiles.AddProfile(profile); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Profile, profile.ProfileId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Profile Added {Profile}", profile); } else @@ -85,6 +88,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && profile.SiteId == _alias.SiteId && _profiles.GetProfile(profile.ProfileId, false) != null) { profile = _profiles.UpdateProfile(profile); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Profile, profile.ProfileId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Profile Updated {Profile}", profile); } else @@ -105,6 +109,7 @@ namespace Oqtane.Controllers if (profile != null && profile.SiteId == _alias.SiteId) { _profiles.DeleteProfile(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Profile, profile.ProfileId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Profile Deleted {ProfileId}", id); } else diff --git a/Oqtane.Server/Controllers/RoleController.cs b/Oqtane.Server/Controllers/RoleController.cs index b79723ae..b5779500 100644 --- a/Oqtane.Server/Controllers/RoleController.cs +++ b/Oqtane.Server/Controllers/RoleController.cs @@ -14,12 +14,14 @@ namespace Oqtane.Controllers public class RoleController : Controller { private readonly IRoleRepository _roles; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public RoleController(IRoleRepository roles, ILogManager logger, ITenantManager tenantManager) + public RoleController(IRoleRepository roles, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _roles = roles; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -72,6 +74,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && role.SiteId == _alias.SiteId) { role = _roles.AddRole(role); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Role, role.RoleId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Role Added {Role}", role); } else @@ -91,6 +94,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && role.SiteId == _alias.SiteId && _roles.GetRole(role.RoleId, false) != null) { role = _roles.UpdateRole(role); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Role, role.RoleId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Role Updated {Role}", role); } else @@ -111,6 +115,7 @@ namespace Oqtane.Controllers if (role != null && !role.IsSystem && role.SiteId == _alias.SiteId) { _roles.DeleteRole(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Role, role.RoleId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Role Deleted {RoleId}", id); } else diff --git a/Oqtane.Server/Controllers/SettingController.cs b/Oqtane.Server/Controllers/SettingController.cs index 6fb6a443..092c232e 100644 --- a/Oqtane.Server/Controllers/SettingController.cs +++ b/Oqtane.Server/Controllers/SettingController.cs @@ -98,7 +98,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && IsAuthorized(setting.EntityName, setting.EntityId, PermissionNames.Edit)) { setting = _settings.AddSetting(setting); - AddSyncEvent(setting.EntityName); + AddSyncEvent(setting.EntityName, setting.SettingId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "Setting Added {Setting}", setting); } else @@ -117,7 +117,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && IsAuthorized(setting.EntityName, setting.EntityId, PermissionNames.Edit)) { setting = _settings.UpdateSetting(setting); - AddSyncEvent(setting.EntityName); + AddSyncEvent(setting.EntityName, setting.SettingId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "Setting Updated {Setting}", setting); } else @@ -137,7 +137,7 @@ namespace Oqtane.Controllers if (IsAuthorized(setting.EntityName, setting.EntityId, PermissionNames.Edit)) { _settings.DeleteSetting(setting.EntityName, id); - AddSyncEvent(setting.EntityName); + AddSyncEvent(setting.EntityName, setting.SettingId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Setting Deleted {Setting}", setting); } else @@ -277,14 +277,16 @@ namespace Oqtane.Controllers return filter; } - private void AddSyncEvent(string EntityName) + private void AddSyncEvent(string EntityName, int SettingId, string Action) { + _syncManager.AddSyncEvent(_alias.TenantId, EntityName + "Setting", SettingId, Action); + switch (EntityName) { case EntityNames.Module: case EntityNames.Page: case EntityNames.Site: - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, _alias.SiteId, SyncEventActions.Refresh); break; } } diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index a2b7f2b7..eb3d6ed1 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -160,6 +160,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid) { site = _sites.AddSite(site); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Create); _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Create, "Site Added {Site}", site); } else @@ -180,12 +181,13 @@ namespace Oqtane.Controllers if (ModelState.IsValid && site.SiteId == _alias.SiteId && site.TenantId == _alias.TenantId && current != null) { site = _sites.UpdateSite(site); - bool reload = false; + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Update); + string action = SyncEventActions.Refresh; if (current.Runtime != site.Runtime || current.RenderMode != site.RenderMode) { - reload = true; + action = SyncEventActions.Reload; } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, reload); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, action); _logger.Log(site.SiteId, LogLevel.Information, this, LogFunction.Update, "Site Updated {Site}", site); } else @@ -206,6 +208,7 @@ namespace Oqtane.Controllers if (site != null && site.SiteId == _alias.SiteId) { _sites.DeleteSite(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.Site, site.SiteId, SyncEventActions.Delete); _logger.Log(id, LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id); } else diff --git a/Oqtane.Server/Controllers/TenantController.cs b/Oqtane.Server/Controllers/TenantController.cs index 1b01d0f1..d3567fb1 100644 --- a/Oqtane.Server/Controllers/TenantController.cs +++ b/Oqtane.Server/Controllers/TenantController.cs @@ -2,9 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using Oqtane.Models; using System.Collections.Generic; -using Oqtane.Enums; using Oqtane.Shared; -using Oqtane.Infrastructure; using Oqtane.Repository; namespace Oqtane.Controllers @@ -13,12 +11,10 @@ namespace Oqtane.Controllers public class TenantController : Controller { private readonly ITenantRepository _tenants; - private readonly ILogManager _logger; - public TenantController(ITenantRepository tenants, ILogManager logger) + public TenantController(ITenantRepository tenants) { _tenants = tenants; - _logger = logger; } // GET: api/ diff --git a/Oqtane.Server/Controllers/UrlMappingController.cs b/Oqtane.Server/Controllers/UrlMappingController.cs index 9e8c745c..ddfd2ddb 100644 --- a/Oqtane.Server/Controllers/UrlMappingController.cs +++ b/Oqtane.Server/Controllers/UrlMappingController.cs @@ -14,12 +14,14 @@ namespace Oqtane.Controllers public class UrlMappingController : Controller { private readonly IUrlMappingRepository _urlMappings; + private readonly ISyncManager _syncManager; private readonly ILogManager _logger; private readonly Alias _alias; - public UrlMappingController(IUrlMappingRepository urlMappings, ILogManager logger, ITenantManager tenantManager) + public UrlMappingController(IUrlMappingRepository urlMappings, ISyncManager syncManager, ILogManager logger, ITenantManager tenantManager) { _urlMappings = urlMappings; + _syncManager = syncManager; _logger = logger; _alias = tenantManager.GetAlias(); } @@ -85,6 +87,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && urlMapping.SiteId == _alias.SiteId) { urlMapping = _urlMappings.AddUrlMapping(urlMapping); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UrlMapping, urlMapping.UrlMappingId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "UrlMapping Added {UrlMapping}", urlMapping); } else @@ -104,6 +107,7 @@ namespace Oqtane.Controllers if (ModelState.IsValid && urlMapping.SiteId == _alias.SiteId && _urlMappings.GetUrlMapping(urlMapping.UrlMappingId, false) != null) { urlMapping = _urlMappings.UpdateUrlMapping(urlMapping); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UrlMapping, urlMapping.UrlMappingId, SyncEventActions.Update); _logger.Log(LogLevel.Information, this, LogFunction.Update, "UrlMapping Updated {UrlMapping}", urlMapping); } else @@ -124,6 +128,7 @@ namespace Oqtane.Controllers if (urlMapping != null && urlMapping.SiteId == _alias.SiteId) { _urlMappings.DeleteUrlMapping(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UrlMapping, urlMapping.UrlMappingId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "UrlMapping Deleted {UrlMappingId}", id); } else diff --git a/Oqtane.Server/Controllers/UserController.cs b/Oqtane.Server/Controllers/UserController.cs index 4a2870e1..0cfdc502 100644 --- a/Oqtane.Server/Controllers/UserController.cs +++ b/Oqtane.Server/Controllers/UserController.cs @@ -23,7 +23,6 @@ namespace Oqtane.Controllers public class UserController : Controller { private readonly IUserRepository _users; - private readonly IRoleRepository _roles; private readonly IUserRoleRepository _userRoles; private readonly UserManager _identityUserManager; private readonly SignInManager _identitySignInManager; @@ -35,10 +34,9 @@ namespace Oqtane.Controllers private readonly IJwtManager _jwtManager; private readonly ILogManager _logger; - public UserController(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager identityUserManager, SignInManager identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ISiteRepository sites, IJwtManager jwtManager, ILogManager logger) + public UserController(IUserRepository users, IUserRoleRepository userRoles, UserManager identityUserManager, SignInManager identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ISiteRepository sites, IJwtManager jwtManager, ILogManager logger) { _users = users; - _roles = roles; _userRoles = userRoles; _identityUserManager = identityUserManager; _identitySignInManager = identitySignInManager; @@ -196,6 +194,7 @@ namespace Oqtane.Controllers user.LastLoginOn = null; user.LastIPAddress = ""; newUser = _users.AddUser(user); + _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, newUser.UserId, SyncEventActions.Create); } else { @@ -255,7 +254,8 @@ namespace Oqtane.Controllers await _identityUserManager.UpdateAsync(identityuser); } user = _users.UpdateUser(user); - _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId); + _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Update); + _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Refresh); user.Password = ""; // remove sensitive information _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user); } @@ -310,6 +310,7 @@ namespace Oqtane.Controllers { // delete user _users.DeleteUser(user.UserId); + _syncManager.AddSyncEvent(_tenantManager.GetAlias().TenantId, EntityNames.User, user.UserId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Deleted {UserId}", user.UserId); } else diff --git a/Oqtane.Server/Controllers/UserRoleController.cs b/Oqtane.Server/Controllers/UserRoleController.cs index 7624e7ad..05101732 100644 --- a/Oqtane.Server/Controllers/UserRoleController.cs +++ b/Oqtane.Server/Controllers/UserRoleController.cs @@ -122,9 +122,10 @@ namespace Oqtane.Controllers if (ModelState.IsValid && role != null && SiteValid(role.SiteId) && RoleValid(role.Name)) { userRole = _userRoles.AddUserRole(userRole); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userRole.UserRoleId, SyncEventActions.Create); _logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userRole); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId, SyncEventActions.Refresh); } else { @@ -144,7 +145,8 @@ namespace Oqtane.Controllers if (ModelState.IsValid && role != null && SiteValid(role.SiteId) && RoleValid(role.Name) && _userRoles.GetUserRole(userRole.UserRoleId, false) != null) { userRole = _userRoles.UpdateUserRole(userRole); - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userRole.UserRoleId, SyncEventActions.Update); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userRole.UserId, SyncEventActions.Refresh); _logger.Log(LogLevel.Information, this, LogFunction.Update, "User Role Updated {UserRole}", userRole); } else @@ -165,6 +167,7 @@ namespace Oqtane.Controllers if (userrole != null && SiteValid(userrole.Role.SiteId) && RoleValid(userrole.Role.Name)) { _userRoles.DeleteUserRole(id); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.UserRole, userrole.UserRoleId, SyncEventActions.Delete); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "User Role Deleted {UserRole}", userrole); if (userrole.Role.Name == RoleNames.Host) @@ -178,7 +181,7 @@ namespace Oqtane.Controllers _logger.Log(LogLevel.Information, this, LogFunction.Create, "User Role Added {UserRole}", userrole); } - _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userrole.UserId); + _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.User, userrole.UserId, SyncEventActions.Refresh); } else { diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index f21f53c9..ab6987f2 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -280,7 +280,7 @@ namespace Microsoft.Extensions.DependencyInjection var serviceTypes = assembly.GetTypes(hostedServiceType); foreach (var serviceType in serviceTypes) { - if (serviceType.IsSubclassOf(typeof(HostedServiceBase))) + if (!services.Any(item => item.ServiceType == serviceType)) { services.AddSingleton(hostedServiceType, serviceType); } diff --git a/Oqtane.Server/Infrastructure/CacheInvalidationService.cs b/Oqtane.Server/Infrastructure/CacheInvalidationService.cs new file mode 100644 index 00000000..bae2d4f4 --- /dev/null +++ b/Oqtane.Server/Infrastructure/CacheInvalidationService.cs @@ -0,0 +1,45 @@ +using System.Threading.Tasks; +using System.Threading; +using Microsoft.Extensions.Hosting; +using Oqtane.Models; +using Microsoft.Extensions.Caching.Memory; +using Oqtane.Shared; + +namespace Oqtane.Infrastructure +{ + public class EventJob : IHostedService + { + private readonly ISyncManager _syncManager; + private readonly IMemoryCache _cache; + + public EventJob(ISyncManager syncManager, IMemoryCache cache) + { + _syncManager = syncManager; + _cache = cache; + } + + void EntityChanged(object sender, SyncEvent e) + { + if (e.EntityName == "Site" && e.Action == SyncEventActions.Refresh) + { + _cache.Remove($"site:{e.TenantId}:{e.EntityId}"); + } + } + + public Task StartAsync(CancellationToken cancellationToken) + { + _syncManager.EntityChanged += EntityChanged; + + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + public void Dispose() + { + _syncManager.EntityChanged -= EntityChanged; + } + } +} diff --git a/Oqtane.Server/Infrastructure/Interfaces/ISyncManager.cs b/Oqtane.Server/Infrastructure/Interfaces/ISyncManager.cs index b21d70af..82ec7d26 100644 --- a/Oqtane.Server/Infrastructure/Interfaces/ISyncManager.cs +++ b/Oqtane.Server/Infrastructure/Interfaces/ISyncManager.cs @@ -6,8 +6,8 @@ namespace Oqtane.Infrastructure { public interface ISyncManager { + event EventHandler EntityChanged; List GetSyncEvents(int tenantId, DateTime lastSyncDate); - void AddSyncEvent(int tenantId, string entityName, int entityId); - void AddSyncEvent(int tenantId, string entityName, int entityId, bool reload); + void AddSyncEvent(int tenantId, string entityName, int entityId, string action); } } diff --git a/Oqtane.Server/Infrastructure/SyncManager.cs b/Oqtane.Server/Infrastructure/SyncManager.cs index b5ac1dc5..c6a15dfe 100644 --- a/Oqtane.Server/Infrastructure/SyncManager.cs +++ b/Oqtane.Server/Infrastructure/SyncManager.cs @@ -1,21 +1,19 @@ -using Microsoft.Extensions.Caching.Memory; using Oqtane.Models; using Oqtane.Shared; using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace Oqtane.Infrastructure { public class SyncManager : ISyncManager { - private readonly IMemoryCache _cache; private List SyncEvents { get; set; } - public SyncManager(IMemoryCache cache) + public event EventHandler EntityChanged; + + public SyncManager() { - _cache = cache; SyncEvents = new List(); } @@ -24,20 +22,22 @@ namespace Oqtane.Infrastructure return SyncEvents.Where(item => (item.TenantId == tenantId || item.TenantId == -1) && item.ModifiedOn >= lastSyncDate).ToList(); } - public void AddSyncEvent(int tenantId, string entityName, int entityId) + public void AddSyncEvent(int tenantId, string entityName, int entityId, string action) { - AddSyncEvent(tenantId, entityName, entityId, false); - } + var syncevent = new SyncEvent { TenantId = tenantId, EntityName = entityName, EntityId = entityId, Action = action, ModifiedOn = DateTime.UtcNow }; - public void AddSyncEvent(int tenantId, string entityName, int entityId, bool reload) - { - SyncEvents.Add(new SyncEvent { TenantId = tenantId, EntityName = entityName, EntityId = entityId, Reload = reload, ModifiedOn = DateTime.UtcNow }); - if (entityName == EntityNames.Site) -{ - _cache.Remove($"site:{tenantId}:{entityId}"); + // client actions for PageState management + if (action == SyncEventActions.Refresh || action == SyncEventActions.Reload) + { + // trim sync events + SyncEvents.RemoveAll(item => item.ModifiedOn < DateTime.UtcNow.AddHours(-1)); + + // add sync event + SyncEvents.Add(syncevent); } - // trim sync events - SyncEvents.RemoveAll(item => item.ModifiedOn < DateTime.UtcNow.AddHours(-1)); + + // raise event + EntityChanged?.Invoke(this, syncevent); } } } diff --git a/Oqtane.Server/Startup.cs b/Oqtane.Server/Startup.cs index 309f0c09..7b349ec4 100644 --- a/Oqtane.Server/Startup.cs +++ b/Oqtane.Server/Startup.cs @@ -191,7 +191,7 @@ namespace Oqtane }); // create a global sync event to identify server application startup - sync.AddSyncEvent(-1, "Application", -1, true); + sync.AddSyncEvent(-1, EntityNames.Host, -1, SyncEventActions.Reload); } } } diff --git a/Oqtane.Shared/Models/Sync.cs b/Oqtane.Shared/Models/Sync.cs index 6e58185f..f99c0ffd 100644 --- a/Oqtane.Shared/Models/Sync.cs +++ b/Oqtane.Shared/Models/Sync.cs @@ -9,12 +9,12 @@ namespace Oqtane.Models public List SyncEvents { get; set; } } - public class SyncEvent + public class SyncEvent : EventArgs { public int TenantId { get; set; } public string EntityName { get; set; } public int EntityId { get; set; } - public bool Reload { get; set; } + public string Action { get; set; } public DateTime ModifiedOn { get; set; } } } diff --git a/Oqtane.Shared/Shared/EntityNames.cs b/Oqtane.Shared/Shared/EntityNames.cs index 2a31e76d..1e480c3b 100644 --- a/Oqtane.Shared/Shared/EntityNames.cs +++ b/Oqtane.Shared/Shared/EntityNames.cs @@ -2,15 +2,25 @@ namespace Oqtane.Shared { public class EntityNames { + public const string Alias = "Alias"; + public const string File = "File"; + public const string Folder = "Folder"; + public const string Job = "Job"; + public const string Language = "Language"; public const string Module = "Module"; public const string ModuleDefinition = "ModuleDefinition"; - public const string PageModule = "PageModule"; - public const string Tenant = "Tenant"; - public const string Site = "Site"; + public const string Notification = "Notification"; public const string Page = "Page"; - public const string Folder = "Folder"; + public const string PageModule = "PageModule"; + public const string Profile = "Profile"; + public const string Role = "Role"; + public const string Setting = "Setting"; + public const string Site = "Site"; + public const string Tenant = "Tenant"; + public const string UrlMapping = "UrlMapping"; public const string User = "User"; + public const string UserRole = "UserRole"; public const string Visitor = "Visitor"; - public const string Host = "Host"; + public const string Host = "Host"; // a conceptual entity } } diff --git a/Oqtane.Shared/Shared/SyncEventActions.cs b/Oqtane.Shared/Shared/SyncEventActions.cs new file mode 100644 index 00000000..c3f9973b --- /dev/null +++ b/Oqtane.Shared/Shared/SyncEventActions.cs @@ -0,0 +1,12 @@ +namespace Oqtane.Shared { + public class SyncEventActions { + // client actions for PageState management + public const string Refresh = "Refresh"; + public const string Reload = "Reload"; + + // server actions for raising Events + public const string Create = "Create"; + public const string Update = "Update"; + public const string Delete = "Delete"; + } +}