Merge pull request #2834 from sbwalker/dev

ability to specify if a module definition is enabled for a site
This commit is contained in:
Shaun Walker 2023-05-24 09:40:20 -04:00 committed by GitHub
commit f7c49588fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 129 additions and 57 deletions

View File

@ -33,6 +33,15 @@
<input id="categories" class="form-control" @bind="@_categories" maxlength="200" required /> <input id="categories" class="form-control" @bind="@_categories" maxlength="200" required />
</div> </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> </div>
</form> </form>
<Section Name="Information" ResourceKey="Information"> <Section Name="Information" ResourceKey="Information">
@ -199,6 +208,7 @@
private string _name; private string _name;
private string _description = ""; private string _description = "";
private string _categories; private string _categories;
private string _isenabled;
private string _moduledefinitionname = ""; private string _moduledefinitionname = "";
private string _version; private string _version;
private string _packagename = ""; private string _packagename = "";
@ -234,6 +244,7 @@
_name = moduleDefinition.Name; _name = moduleDefinition.Name;
_description = moduleDefinition.Description; _description = moduleDefinition.Description;
_categories = moduleDefinition.Categories; _categories = moduleDefinition.Categories;
_isenabled = moduleDefinition.IsEnabled.ToString();
_moduledefinitionname = moduleDefinition.ModuleDefinitionName; _moduledefinitionname = moduleDefinition.ModuleDefinitionName;
_version = moduleDefinition.Version; _version = moduleDefinition.Version;
_packagename = moduleDefinition.PackageName; _packagename = moduleDefinition.PackageName;
@ -297,6 +308,7 @@
{ {
moduledefinition.Categories = _categories; moduledefinition.Categories = _categories;
} }
moduledefinition.IsEnabled = (_isenabled == null ? true : Boolean.Parse(_isenabled));
moduledefinition.PermissionList = _permissionGrid.GetPermissionList(); moduledefinition.PermissionList = _permissionGrid.GetPermissionList();
await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition); await ModuleDefinitionService.UpdateModuleDefinitionAsync(moduledefinition);
await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition); await logger.LogInformation("ModuleDefinition Saved {ModuleDefinition}", moduledefinition);

View File

@ -43,6 +43,7 @@ else
<th style="width: 1px;">&nbsp;</th> <th style="width: 1px;">&nbsp;</th>
<th>@SharedLocalizer["Name"]</th> <th>@SharedLocalizer["Name"]</th>
<th>@SharedLocalizer["Version"]</th> <th>@SharedLocalizer["Version"]</th>
<th>@Localizer["Enabled"]</th>
<th>@Localizer["InUse"]</th> <th>@Localizer["InUse"]</th>
<th>@SharedLocalizer["Expires"]</th> <th>@SharedLocalizer["Expires"]</th>
<th style="width: 1px;">&nbsp;</th> <th style="width: 1px;">&nbsp;</th>
@ -57,6 +58,16 @@ else
</td> </td>
<td>@context.Name</td> <td>@context.Name</td>
<td>@context.Version</td> <td>@context.Version</td>
<td>
@if (context.IsEnabled)
{
<span>@SharedLocalizer["Yes"]</span>
}
else
{
<span>@SharedLocalizer["No"]</span>
}
</td>
<td> <td>
@if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null) @if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null)
{ {

View File

@ -219,4 +219,10 @@
<data name="Message.DuplicateName" xml:space="preserve"> <data name="Message.DuplicateName" xml:space="preserve">
<value>A Module With The Name Specified Already Exists</value> <value>A Module With The Name Specified Already Exists</value>
</data> </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> </root>

View File

@ -145,7 +145,7 @@
<value>Delete Module</value> <value>Delete Module</value>
</data> </data>
<data name="InUse" xml:space="preserve"> <data name="InUse" xml:space="preserve">
<value>In Use</value> <value>In Use?</value>
</data> </data>
<data name="EditModule.Text" xml:space="preserve"> <data name="EditModule.Text" xml:space="preserve">
<value>Edit</value> <value>Edit</value>
@ -153,4 +153,7 @@
<data name="Modules" xml:space="preserve"> <data name="Modules" xml:space="preserve">
<value>Modules</value> <value>Modules</value>
</data> </data>
<data name="Enabled" xml:space="preserve">
<value>Enabled?</value>
</data>
</root> </root>

View File

@ -144,7 +144,7 @@
} }
@foreach (var moduledefinition in _moduleDefinitions) @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())) if (moduledefinition.Runtimes == "" || moduledefinition.Runtimes.Contains(PageState.Runtime.ToString()))
{ {

View File

@ -255,9 +255,8 @@ namespace Oqtane.Controllers
_modules.DeleteModule(moduleToRemove.ModuleId); _modules.DeleteModule(moduleToRemove.ModuleId);
} }
// remove module definition // remove module definition
_moduleDefinitions.DeleteModuleDefinition(id); _moduleDefinitions.DeleteModuleDefinition(id, siteid);
_syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, SyncEventActions.Delete); _syncManager.AddSyncEvent(_alias.TenantId, EntityNames.ModuleDefinition, moduledefinition.ModuleDefinitionId, SyncEventActions.Delete);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name); _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name);
} }

View File

@ -9,7 +9,7 @@ namespace Oqtane.Repository
IEnumerable<ModuleDefinition> GetModuleDefinitions(int siteId); IEnumerable<ModuleDefinition> GetModuleDefinitions(int siteId);
ModuleDefinition GetModuleDefinition(int moduleDefinitionId, int siteId); ModuleDefinition GetModuleDefinition(int moduleDefinitionId, int siteId);
void UpdateModuleDefinition(ModuleDefinition moduleDefinition); void UpdateModuleDefinition(ModuleDefinition moduleDefinition);
void DeleteModuleDefinition(int moduleDefinitionId); void DeleteModuleDefinition(int moduleDefinitionId, int siteId);
ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition); ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition);
} }
} }

View File

@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection; using System.Reflection;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Caching.Memory;
using Oqtane.Infrastructure;
using Oqtane.Models; using Oqtane.Models;
using Oqtane.Modules; using Oqtane.Modules;
using Oqtane.Shared; using Oqtane.Shared;
@ -17,13 +18,16 @@ namespace Oqtane.Repository
private MasterDBContext _db; private MasterDBContext _db;
private readonly IMemoryCache _cache; private readonly IMemoryCache _cache;
private readonly IPermissionRepository _permissions; private readonly IPermissionRepository _permissions;
private readonly ITenantManager _tenants;
private readonly ISettingRepository _settings; 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; _db = context;
_cache = cache; _cache = cache;
_permissions = permissions; _permissions = permissions;
_tenants = tenants;
_settings = settings; _settings = settings;
} }
@ -48,16 +52,29 @@ namespace Oqtane.Repository
_db.Entry(moduleDefinition).State = EntityState.Modified; _db.Entry(moduleDefinition).State = EntityState.Modified;
_db.SaveChanges(); _db.SaveChanges();
_permissions.UpdatePermissions(moduleDefinition.SiteId, EntityNames.ModuleDefinition, moduleDefinition.ModuleDefinitionId, moduleDefinition.PermissionList); _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);
} }
public void DeleteModuleDefinition(int moduleDefinitionId) _cache.Remove($"moduledefinitions:{moduleDefinition.SiteId}");
}
public void DeleteModuleDefinition(int moduleDefinitionId,int siteId)
{ {
ModuleDefinition moduleDefinition = _db.ModuleDefinition.Find(moduleDefinitionId); ModuleDefinition moduleDefinition = _db.ModuleDefinition.Find(moduleDefinitionId);
_settings.DeleteSettings(EntityNames.ModuleDefinition, moduleDefinitionId); _settings.DeleteSettings(EntityNames.ModuleDefinition, moduleDefinitionId);
_db.ModuleDefinition.Remove(moduleDefinition); _db.ModuleDefinition.Remove(moduleDefinition);
_db.SaveChanges(); _db.SaveChanges();
_cache.Remove("moduledefinitions"); _cache.Remove($"moduledefinitions:{siteId}");
} }
public ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition) public ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition)
@ -80,6 +97,7 @@ namespace Oqtane.Repository
ModuleDefinition.ControlTypeTemplate = moduleDefinition.ControlTypeTemplate; ModuleDefinition.ControlTypeTemplate = moduleDefinition.ControlTypeTemplate;
ModuleDefinition.IsPortable = moduleDefinition.IsPortable; ModuleDefinition.IsPortable = moduleDefinition.IsPortable;
ModuleDefinition.Resources = moduleDefinition.Resources; ModuleDefinition.Resources = moduleDefinition.Resources;
ModuleDefinition.IsEnabled = moduleDefinition.IsEnabled;
} }
return ModuleDefinition; return ModuleDefinition;
@ -91,63 +109,21 @@ namespace Oqtane.Repository
List<ModuleDefinition> moduleDefinitions; List<ModuleDefinition> moduleDefinitions;
if (siteId != -1) if (siteId != -1)
{ {
moduleDefinitions = _cache.GetOrCreate("moduledefinitions", entry => moduleDefinitions = _cache.GetOrCreate($"moduledefinitions:{siteId}", entry =>
{ {
entry.SlidingExpiration = TimeSpan.FromMinutes(30); 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 else // called during startup
{ {
if (permissions.Any(item => item.EntityId == moduledefinition.ModuleDefinitionId)) return ProcessModuleDefinitions(-1);
{
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
{
moduleDefinitions = LoadModuleDefinitions();
} }
return moduleDefinitions; return moduleDefinitions;
} }
private List<ModuleDefinition> LoadModuleDefinitions() private List<ModuleDefinition> ProcessModuleDefinitions(int siteId)
{ {
// get module assemblies // get module assemblies
List<ModuleDefinition> moduleDefinitions = LoadModuleDefinitionsFromAssemblies(); List<ModuleDefinition> moduleDefinitions = LoadModuleDefinitionsFromAssemblies();
@ -197,6 +173,65 @@ namespace Oqtane.Repository
_db.SaveChanges(); _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; return moduleDefinitions;
} }

View File

@ -110,10 +110,16 @@ namespace Oqtane.Models
[NotMapped] [NotMapped]
public List<Resource> Resources { get; set; } // added in 4.0.0 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 // internal properties
[NotMapped] [NotMapped]
public int SiteId { get; set; } public int SiteId { get; set; }
[NotMapped]
public bool IsEnabled { get; set; }
[NotMapped] [NotMapped]
public string ControlTypeTemplate { get; set; } public string ControlTypeTemplate { get; set; }