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

ability to specify if a module definition is enabled for a site #2834

Merged
merged 1 commit into from
May 24, 2023
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
14 changes: 13 additions & 1 deletion Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down Expand Up @@ -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 = "";
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ else
<th style="width: 1px;">&nbsp;</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;">&nbsp;</th>
Expand All @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -145,12 +145,15 @@
<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>
</data>
<data name="Modules" xml:space="preserve">
<value>Modules</value>
</data>
<data name="Enabled" xml:space="preserve">
<value>Enabled?</value>
</data>
</root>
2 changes: 1 addition & 1 deletion Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
{
Expand Down
3 changes: 1 addition & 2 deletions Oqtane.Server/Controllers/ModuleDefinitionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,8 @@ public void Delete(int id, int siteid)
_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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public interface IModuleDefinitionRepository
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);
}
}
137 changes: 86 additions & 51 deletions Oqtane.Server/Repository/ModuleDefinitionRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Oqtane.Infrastructure;
using Oqtane.Models;
using Oqtane.Modules;
using Oqtane.Shared;
Expand All @@ -17,13 +18,16 @@ public class ModuleDefinitionRepository : IModuleDefinitionRepository
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;
}

Expand All @@ -48,16 +52,29 @@ public void UpdateModuleDefinition(ModuleDefinition moduleDefinition)
_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)
Expand All @@ -80,6 +97,7 @@ public ModuleDefinition FilterModuleDefinition(ModuleDefinition moduleDefinition
ModuleDefinition.ControlTypeTemplate = moduleDefinition.ControlTypeTemplate;
ModuleDefinition.IsPortable = moduleDefinition.IsPortable;
ModuleDefinition.Resources = moduleDefinition.Resources;
ModuleDefinition.IsEnabled = moduleDefinition.IsEnabled;
}

return ModuleDefinition;
Expand All @@ -91,63 +109,21 @@ public List<ModuleDefinition> LoadModuleDefinitions(int siteId)
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();
Expand Down Expand Up @@ -197,6 +173,65 @@ private List<ModuleDefinition> LoadModuleDefinitions()
_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;
}

Expand Down
6 changes: 6 additions & 0 deletions Oqtane.Shared/Models/ModuleDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,16 @@ public ModuleDefinition()
[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; }

Expand Down