Merge pull request #2834 from sbwalker/dev
ability to specify if a module definition is enabled for a site
This commit is contained in:
		| @ -33,7 +33,16 @@ | ||||
| 							<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required /> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</div> | ||||
|                     <div class="row mb-1 align-items-center"> | ||||
|                         <Label Class="col-sm-3" For="isenabled" HelpText="Is module enabled for this site?" ResourceKey="IsEnabled">Enabled? </Label> | ||||
|                         <div class="col-sm-9"> | ||||
|                             <select id="isenabled" class="form-select" @bind="@_isenabled" required> | ||||
|                                 <option value="True">@SharedLocalizer["Yes"]</option> | ||||
|                                 <option value="False">@SharedLocalizer["No"]</option> | ||||
|                             </select> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
| 			</form> | ||||
| 			<Section Name="Information" ResourceKey="Information"> | ||||
| 				<div class="container"> | ||||
| @ -199,6 +208,7 @@ | ||||
|     private string _name; | ||||
|     private string _description = ""; | ||||
|     private string _categories; | ||||
|     private string _isenabled; | ||||
|     private string _moduledefinitionname = ""; | ||||
|     private string _version; | ||||
|     private string _packagename = ""; | ||||
| @ -234,6 +244,7 @@ | ||||
|                 _name = moduleDefinition.Name; | ||||
|                 _description = moduleDefinition.Description; | ||||
|                 _categories = moduleDefinition.Categories; | ||||
|                 _isenabled = moduleDefinition.IsEnabled.ToString(); | ||||
|                 _moduledefinitionname = moduleDefinition.ModuleDefinitionName; | ||||
|                 _version = moduleDefinition.Version; | ||||
|                 _packagename = moduleDefinition.PackageName; | ||||
| @ -297,6 +308,7 @@ | ||||
|                     { | ||||
|                         moduledefinition.Categories = _categories; | ||||
|                     } | ||||
|                     moduledefinition.IsEnabled = (_isenabled == null ? true : Boolean.Parse(_isenabled)); | ||||
|                     moduledefinition.PermissionList = _permissionGrid.GetPermissionList(); | ||||
|                     await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition); | ||||
|                     await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition); | ||||
|  | ||||
| @ -43,6 +43,7 @@ else | ||||
|             <th style="width: 1px;"> </th> | ||||
|             <th>@SharedLocalizer["Name"]</th> | ||||
|             <th>@SharedLocalizer["Version"]</th> | ||||
|             <th>@Localizer["Enabled"]</th> | ||||
|             <th>@Localizer["InUse"]</th> | ||||
|             <th>@SharedLocalizer["Expires"]</th> | ||||
|             <th style="width: 1px;"> </th> | ||||
| @ -57,6 +58,16 @@ else | ||||
|             </td> | ||||
|             <td>@context.Name</td> | ||||
|             <td>@context.Version</td> | ||||
|             <td> | ||||
|                @if (context.IsEnabled) | ||||
|                { | ||||
|                    <span>@SharedLocalizer["Yes"]</span> | ||||
|                } | ||||
|                else | ||||
|                { | ||||
|                    <span>@SharedLocalizer["No"]</span> | ||||
|                } | ||||
|             </td> | ||||
|             <td> | ||||
| 				@if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null) | ||||
|                 { | ||||
|  | ||||
| @ -219,4 +219,10 @@ | ||||
|   <data name="Message.DuplicateName" xml:space="preserve"> | ||||
|     <value>A Module With The Name Specified Already Exists</value> | ||||
|   </data> | ||||
|   <data name="IsEnabled.HelpText" xml:space="preserve"> | ||||
|     <value>Is module enabled for this site?</value> | ||||
|   </data> | ||||
|   <data name="IsEnabled.Text" xml:space="preserve"> | ||||
|     <value>Enabled?</value> | ||||
|   </data> | ||||
| </root> | ||||
| @ -145,7 +145,7 @@ | ||||
|     <value>Delete Module</value> | ||||
|   </data> | ||||
|   <data name="InUse" xml:space="preserve"> | ||||
|     <value>In Use</value> | ||||
|     <value>In Use?</value> | ||||
|   </data> | ||||
|   <data name="EditModule.Text" xml:space="preserve"> | ||||
|     <value>Edit</value> | ||||
| @ -153,4 +153,7 @@ | ||||
|   <data name="Modules" xml:space="preserve"> | ||||
|     <value>Modules</value> | ||||
|   </data> | ||||
|   <data name="Enabled" xml:space="preserve"> | ||||
|     <value>Enabled?</value> | ||||
|   </data> | ||||
| </root> | ||||
| @ -144,7 +144,7 @@ | ||||
| 										} | ||||
| 										@foreach (var moduledefinition in _moduleDefinitions) | ||||
| 										{ | ||||
| 											if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.PermissionList)) | ||||
| 											if (moduledefinition.IsEnabled && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Utilize, moduledefinition.PermissionList)) | ||||
| 											{ | ||||
| 												if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString())) | ||||
| 												{ | ||||
|  | ||||
| @ -255,9 +255,8 @@ namespace Oqtane.Controllers | ||||
|                     _modules.DeleteModule(moduleToRemove.ModuleId); | ||||
|                 } | ||||
|  | ||||
|  | ||||
|                 // remove module definition | ||||
|                 _moduleDefinitions.DeleteModuleDefinition(id); | ||||
|                 _moduleDefinitions.DeleteModuleDefinition(id, siteid); | ||||
|                 _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, SyncEventActions.Delete); | ||||
|                 _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name); | ||||
|             } | ||||
|  | ||||
| @ -9,7 +9,7 @@ namespace Oqtane.Repository | ||||
|         IEnumerable<ModuleDefinition> GetModuleDefinitions(int siteId); | ||||
|         ModuleDefinition GetModuleDefinition(int moduleDefinitionId, int siteId); | ||||
|         void UpdateModuleDefinition(ModuleDefinition moduleDefinition); | ||||
|         void DeleteModuleDefinition(int moduleDefinitionId); | ||||
|         void DeleteModuleDefinition(int moduleDefinitionId, int siteId); | ||||
|         ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -6,6 +6,7 @@ using System.Linq; | ||||
| using System.Reflection; | ||||
| using Microsoft.EntityFrameworkCore; | ||||
| using Microsoft.Extensions.Caching.Memory; | ||||
| using Oqtane.Infrastructure; | ||||
| using Oqtane.Models; | ||||
| using Oqtane.Modules; | ||||
| using Oqtane.Shared; | ||||
| @ -17,13 +18,16 @@ namespace Oqtane.Repository | ||||
|         private MasterDBContext _db; | ||||
|         private readonly IMemoryCache _cache; | ||||
|         private readonly IPermissionRepository _permissions; | ||||
|         private readonly ITenantManager _tenants; | ||||
|         private readonly ISettingRepository _settings; | ||||
|         private readonly string settingprefix = "SiteEnabled:"; | ||||
|  | ||||
|         public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ISettingRepository settings) | ||||
|         public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ITenantManager tenants, ISettingRepository settings) | ||||
|         { | ||||
|             _db = context; | ||||
|             _cache = cache; | ||||
|             _permissions = permissions; | ||||
|             _tenants = tenants; | ||||
|             _settings = settings; | ||||
|         } | ||||
|  | ||||
| @ -48,16 +52,29 @@ namespace Oqtane.Repository | ||||
|             _db.Entry(moduleDefinition).State = EntityState.Modified; | ||||
|             _db.SaveChanges(); | ||||
|             _permissions.UpdatePermissions(moduleDefinition.SiteId, EntityNames.ModuleDefinition, moduleDefinition.ModuleDefinitionId, moduleDefinition.PermissionList); | ||||
|             _cache.Remove("moduledefinitions"); | ||||
|  | ||||
|             var settingname = $"{settingprefix}{_tenants.GetAlias().SiteKey}"; | ||||
|             var setting = _settings.GetSetting(EntityNames.ModuleDefinition, moduleDefinition.ModuleDefinitionId, settingname); | ||||
|             if (setting == null) | ||||
|             { | ||||
|                 _settings.AddSetting(new Setting { EntityName = EntityNames.ModuleDefinition, EntityId = moduleDefinition.ModuleDefinitionId, SettingName = settingname, SettingValue = moduleDefinition.IsEnabled.ToString(), IsPrivate = true }); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 setting.SettingValue = moduleDefinition.IsEnabled.ToString(); | ||||
|                 _settings.UpdateSetting(setting); | ||||
|             } | ||||
|  | ||||
|             _cache.Remove($"moduledefinitions:{moduleDefinition.SiteId}"); | ||||
|         } | ||||
|  | ||||
|         public void DeleteModuleDefinition(int moduleDefinitionId) | ||||
|         public void DeleteModuleDefinition(int moduleDefinitionId,int siteId) | ||||
|         { | ||||
|             ModuleDefinition moduleDefinition = _db.ModuleDefinition.Find(moduleDefinitionId); | ||||
|             _settings.DeleteSettings(EntityNames.ModuleDefinition, moduleDefinitionId); | ||||
|             _db.ModuleDefinition.Remove(moduleDefinition); | ||||
|             _db.SaveChanges(); | ||||
|             _cache.Remove("moduledefinitions"); | ||||
|             _cache.Remove($"moduledefinitions:{siteId}"); | ||||
|         } | ||||
|  | ||||
|         public ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition) | ||||
| @ -80,6 +97,7 @@ namespace Oqtane.Repository | ||||
|                 ModuleDefinition.ControlTypeTemplate = moduleDefinition.ControlTypeTemplate; | ||||
|                 ModuleDefinition.IsPortable = moduleDefinition.IsPortable; | ||||
|                 ModuleDefinition.Resources = moduleDefinition.Resources; | ||||
|                 ModuleDefinition.IsEnabled = moduleDefinition.IsEnabled; | ||||
|             } | ||||
|  | ||||
|             return ModuleDefinition; | ||||
| @ -91,63 +109,21 @@ namespace Oqtane.Repository | ||||
|             List<ModuleDefinition> moduleDefinitions; | ||||
|             if (siteId != -1) | ||||
|             { | ||||
|                 moduleDefinitions = _cache.GetOrCreate("moduledefinitions", entry => | ||||
|                 moduleDefinitions = _cache.GetOrCreate($"moduledefinitions:{siteId}", entry => | ||||
|                 { | ||||
|                     entry.SlidingExpiration = TimeSpan.FromMinutes(30); | ||||
|                     return LoadModuleDefinitions(); | ||||
|                     return ProcessModuleDefinitions(siteId); | ||||
|                 }); | ||||
|  | ||||
|                 // get all module definition permissions for site | ||||
|                 List<Permission> permissions = _permissions.GetPermissions(siteId, EntityNames.ModuleDefinition).ToList(); | ||||
|  | ||||
|                 // populate module definition permissions | ||||
|                 foreach (ModuleDefinition moduledefinition in moduleDefinitions) | ||||
|                 { | ||||
|                     moduledefinition.SiteId = siteId; | ||||
|                     if (permissions.Count == 0) | ||||
|                     { | ||||
|                         // no module definition permissions exist for this site | ||||
|                         moduledefinition.PermissionList = ClonePermissions(siteId, moduledefinition.PermissionList); | ||||
|                         _permissions.UpdatePermissions(siteId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, moduledefinition.PermissionList); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         if (permissions.Any(item => item.EntityId == moduledefinition.ModuleDefinitionId)) | ||||
|                         { | ||||
|                             moduledefinition.PermissionList = permissions.Where(item => item.EntityId == moduledefinition.ModuleDefinitionId).ToList(); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             // permissions for module definition do not exist for this site | ||||
|                             moduledefinition.PermissionList = ClonePermissions(siteId, moduledefinition.PermissionList); | ||||
|                             _permissions.UpdatePermissions(siteId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, moduledefinition.PermissionList); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // clean up any orphaned permissions | ||||
|                 var ids = new HashSet<int>(moduleDefinitions.Select(item => item.ModuleDefinitionId)); | ||||
|                 foreach (var permission in permissions.Where(item => !ids.Contains(item.EntityId))) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         _permissions.DeletePermission(permission.PermissionId); | ||||
|                     } | ||||
|                     catch | ||||
|                     { | ||||
|                         // multi-threading can cause a race condition to occur | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             else // called during startup | ||||
|             { | ||||
|                 moduleDefinitions = LoadModuleDefinitions(); | ||||
|                 return ProcessModuleDefinitions(-1); | ||||
|             } | ||||
|  | ||||
|             return moduleDefinitions; | ||||
|         } | ||||
|  | ||||
|         private List<ModuleDefinition> LoadModuleDefinitions() | ||||
|         private List<ModuleDefinition> ProcessModuleDefinitions(int siteId) | ||||
|         { | ||||
|             // get module assemblies  | ||||
|             List<ModuleDefinition> moduleDefinitions = LoadModuleDefinitionsFromAssemblies(); | ||||
| @ -197,6 +173,65 @@ namespace Oqtane.Repository | ||||
|                 _db.SaveChanges(); | ||||
|             } | ||||
|  | ||||
|             if (siteId != -1) | ||||
|             { | ||||
|                 // get all module definition permissions for site | ||||
|                 List<Permission> permissions = _permissions.GetPermissions(siteId, EntityNames.ModuleDefinition).ToList(); | ||||
|  | ||||
|                 // get settings for site | ||||
|                 var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList(); | ||||
|  | ||||
|                 // populate module definition permissions | ||||
|                 foreach (ModuleDefinition moduledefinition in moduleDefinitions) | ||||
|                 { | ||||
|                     moduledefinition.SiteId = siteId; | ||||
|  | ||||
|                     var setting = settings.FirstOrDefault(item => item.EntityId == moduledefinition.ModuleDefinitionId && item.SettingName == $"{settingprefix}{_tenants.GetAlias().SiteKey}"); | ||||
|                     if (setting != null) | ||||
|                     { | ||||
|                        moduledefinition.IsEnabled = bool.Parse(setting.SettingValue); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         moduledefinition.IsEnabled = moduledefinition.IsAutoEnabled; | ||||
|                     } | ||||
|  | ||||
|                     if (permissions.Count == 0) | ||||
|                     { | ||||
|                         // no module definition permissions exist for this site | ||||
|                         moduledefinition.PermissionList = ClonePermissions(siteId, moduledefinition.PermissionList); | ||||
|                         _permissions.UpdatePermissions(siteId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, moduledefinition.PermissionList); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         if (permissions.Any(item => item.EntityId == moduledefinition.ModuleDefinitionId)) | ||||
|                         { | ||||
|                             moduledefinition.PermissionList = permissions.Where(item => item.EntityId == moduledefinition.ModuleDefinitionId).ToList(); | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             // permissions for module definition do not exist for this site | ||||
|                             moduledefinition.PermissionList = ClonePermissions(siteId, moduledefinition.PermissionList); | ||||
|                             _permissions.UpdatePermissions(siteId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, moduledefinition.PermissionList); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 // clean up any orphaned permissions | ||||
|                 var ids = new HashSet<int>(moduleDefinitions.Select(item => item.ModuleDefinitionId)); | ||||
|                 foreach (var permission in permissions.Where(item => !ids.Contains(item.EntityId))) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         _permissions.DeletePermission(permission.PermissionId); | ||||
|                     } | ||||
|                     catch | ||||
|                     { | ||||
|                         // multi-threading can cause a race condition to occur | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             return moduleDefinitions; | ||||
|         } | ||||
|  | ||||
|  | ||||
| @ -110,10 +110,16 @@ namespace Oqtane.Models | ||||
|         [NotMapped] | ||||
|         public List<Resource> Resources { get; set; } // added in 4.0.0 | ||||
|  | ||||
|         [NotMapped] | ||||
|         public bool IsAutoEnabled { get; set; } = true; // added in 4.0.0 | ||||
|  | ||||
|         // internal properties | ||||
|         [NotMapped] | ||||
|         public int SiteId { get; set; } | ||||
|  | ||||
|         [NotMapped] | ||||
|         public bool IsEnabled { get; set; } | ||||
|  | ||||
|         [NotMapped] | ||||
|         public string ControlTypeTemplate { get; set; } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Shaun Walker
					Shaun Walker