Merge pull request #478 from sbwalker/master

Allow modules to be installed/uninstalled with embedded scripts or IInstallable interface. Fix module uninstall issues.
This commit is contained in:
Shaun Walker 2020-05-14 11:53:33 -04:00 committed by GitHub
commit cba5865e81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 63 additions and 52 deletions

View File

@ -2,7 +2,7 @@
@using [Owner].[Module]s.Services
@using [Owner].[Module]s.Models
@namespace [Owner].[Module]s.Modules
@namespace [Owner].[Module]s
@inherits ModuleBase
@inject I[Module]Service [Module]Service
@inject NavigationManager NavigationManager

View File

@ -1,7 +1,7 @@
@using [Owner].[Module]s.Services
@using [Owner].[Module]s.Models
@namespace [Owner].[Module]s.Modules
@namespace [Owner].[Module]s
@inherits ModuleBase
@inject I[Module]Service [Module]Service
@inject NavigationManager NavigationManager

View File

@ -1,7 +1,7 @@
using Oqtane.Models;
using Oqtane.Modules;
namespace [Owner].[Module]s.Modules
namespace [Owner].[Module]s
{
public class ModuleInfo : IModule
{

View File

@ -1,4 +1,4 @@
@namespace [Owner].[Module]s.Modules
@namespace [Owner].[Module]s
@inherits ModuleBase
@inject ISettingService SettingService

View File

@ -15,4 +15,6 @@
@using Oqtane.Services
@using Oqtane.Shared
@using Oqtane.Themes
@using Oqtane.Themes.Controls
@using Oqtane.Themes.Controls
@using Oqtane.UI
@using Oqtane.Enums

View File

@ -2,7 +2,7 @@
@using [Owner].[Module]s.Services
@using [Owner].[Module]s.Models
@namespace [Owner].[Module]s.Modules
@namespace [Owner].[Module]s
@inherits ModuleBase
@inject I[Module]Service [Module]Service
@inject NavigationManager NavigationManager

View File

@ -1,7 +1,7 @@
@using [Owner].[Module]s.Services
@using [Owner].[Module]s.Models
@namespace [Owner].[Module]s.Modules
@namespace [Owner].[Module]s
@inherits ModuleBase
@inject I[Module]Service [Module]Service
@inject NavigationManager NavigationManager

View File

@ -1,7 +1,7 @@
using Oqtane.Models;
using Oqtane.Modules;
namespace [Owner].[Module]s.Modules
namespace [Owner].[Module]s
{
public class ModuleInfo : IModule
{

View File

@ -1,4 +1,4 @@
@namespace [Owner].[Module]s.Modules
@namespace [Owner].[Module]s
@inherits ModuleBase
@inject ISettingService SettingService

View File

@ -23,17 +23,19 @@ namespace Oqtane.Controllers
private readonly IModuleDefinitionRepository _moduleDefinitions;
private readonly IModuleRepository _modules;
private readonly ITenantRepository _tenants;
private readonly ISqlRepository _sql;
private readonly IUserPermissions _userPermissions;
private readonly IInstallationManager _installationManager;
private readonly IWebHostEnvironment _environment;
private readonly IServiceProvider _serviceProvider;
private readonly ILogManager _logger;
public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules,ITenantRepository tenants, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ILogManager logger)
public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules,ITenantRepository tenants, ISqlRepository sql, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ILogManager logger)
{
_moduleDefinitions = moduleDefinitions;
_modules = modules;
_tenants = tenants;
_sql = sql;
_userPermissions = userPermissions;
_installationManager = installationManager;
_environment = environment;
@ -99,57 +101,60 @@ namespace Oqtane.Controllers
public void Delete(int id, int siteid)
{
ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, siteid);
if (moduledefinition != null)
if (moduledefinition != null )
{
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType))
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType) && Utilities.GetAssemblyName(moduledefinition.ServerManagerType) != "Oqtane.Server")
{
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
if (moduletype != null && moduletype.GetInterface("IInstallable") != null)
foreach (Tenant tenant in _tenants.GetTenants())
{
foreach (Tenant tenant in _tenants.GetTenants())
try
{
try
if (moduletype.GetInterface("IInstallable") != null)
{
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
((IInstallable)moduleobject).Uninstall(tenant);
}
catch
else
{
// an error occurred executing the uninstall
_sql.ExecuteScript(tenant, moduletype.Assembly, Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + ".Uninstall.sql");
}
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "{ModuleDefinitionName} Uninstalled For Tenant {Tenant}", moduledefinition.ModuleDefinitionName, tenant.Name);
}
catch (Exception ex)
{
_logger.Log(LogLevel.Error, this, LogFunction.Delete, "Error Uninstalling {ModuleDefinitionName} For Tenant {Tenant} {Error}", moduledefinition.ModuleDefinitionName, tenant.Name, ex.Message);
}
}
}
// format root assembly name
string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName);
if (assemblyname != "Oqtane.Client")
{
assemblyname = assemblyname.Replace(".Client", "");
// clean up module static resource folder
string folder = Path.Combine(_environment.WebRootPath, Path.Combine("Modules",assemblyname));
string folder = Path.Combine(_environment.WebRootPath, Path.Combine("Modules", Utilities.GetTypeName(moduledefinition.ModuleDefinitionName)));
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {AssemblynName}", assemblyname);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {ModuleDefinitionName}", moduledefinition.ModuleDefinitionName);
}
// remove module assembly from /bin
// get root assembly name ( note that this only works if modules follow a specific naming convention for their assemblies )
string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName).ToLower();
assemblyname = assemblyname.Replace(".client", "").Replace(".oqtane", "");
// remove module assemblies from /bin
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
foreach (string file in Directory.EnumerateFiles(binfolder, assemblyname + "*.*"))
{
System.IO.File.Delete(file);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assembly Removed {Filename}", file);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assembly {Filename} Removed For {ModuleDefinitionName}", file, moduledefinition.ModuleDefinitionName);
}
// remove module definition
_moduleDefinitions.DeleteModuleDefinition(id, siteid);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition {ModuleDefinitionName} Deleted", moduledefinition.Name);
// restart application
_installationManager.RestartApplication();
}
// remove module definition
_moduleDefinitions.DeleteModuleDefinition(id, siteid);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition Deleted {ModuleDefinitionName}", moduledefinition.Name);
// restart application
_installationManager.RestartApplication();
}
}

View File

@ -54,22 +54,20 @@ namespace Oqtane.Controllers
{
List<Theme> themes = _themes.GetThemes().ToList();
Theme theme = themes.Where(item => item.ThemeName == themename).FirstOrDefault();
if (theme != null)
if (theme != null && Utilities.GetAssemblyName(theme.ThemeName) != "Oqtane.Client")
{
themename = theme.ThemeName.Substring(0, theme.ThemeName.IndexOf(","));
string folder = Path.Combine(_environment.WebRootPath, "Themes" , themename);
// clean up theme static resource folder
string folder = Path.Combine(_environment.WebRootPath, "Themes" , Utilities.GetTypeName(theme.ThemeName));
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Static Resources Removed For {ThemeName}", theme.ThemeName);
}
// remove theme assembly from /bin
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
foreach (string file in Directory.EnumerateFiles(binfolder, themename + "*.dll"))
{
System.IO.File.Delete(file);
}
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Deleted {ThemeName}", themename);
System.IO.File.Delete(Path.Combine(binfolder, Utilities.GetAssemblyName(theme.ThemeName) + ".dll"));
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Theme Assembly {Filename} Removed For {ThemeName}", Utilities.GetAssemblyName(theme.ThemeName) + ".dll", themename);
_installationManager.RestartApplication();
}

View File

@ -332,10 +332,13 @@ namespace Oqtane.Infrastructure
using (var scope = _serviceScopeFactory.CreateScope())
{
var moduledefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
foreach (var moduledefinition in moduledefinitions.GetModuleDefinitions())
{
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType) && !string.IsNullOrEmpty(moduledefinition.ReleaseVersions))
if (!string.IsNullOrEmpty(moduledefinition.ReleaseVersions) && !string.IsNullOrEmpty(moduledefinition.ServerManagerType))
{
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
string[] versions = moduledefinition.ReleaseVersions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey))))
{
@ -351,19 +354,22 @@ namespace Oqtane.Infrastructure
if (index == -1) index = 0;
for (int i = index; i < versions.Length; i++)
{
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
if (moduletype != null && moduletype.GetInterface("IInstallable") != null)
try
{
try
if (moduletype.GetInterface("IInstallable") != null)
{
var moduleobject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduletype);
((IInstallable)moduleobject).Install(tenant, versions[i]);
((IInstallable)moduleobject).Install(tenant, versions[i]);
}
catch (Exception ex)
else
{
result.Message = "An Error Occurred Installing " + moduledefinition.Name + " - " + ex.Message.ToString();
sql.ExecuteScript(tenant, moduletype.Assembly, Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + "." + versions[i] + ".sql");
}
}
catch (Exception ex)
{
result.Message = "An Error Occurred Installing " + moduledefinition.Name + " Version " + versions[i] + " - " + ex.Message.ToString();
}
}
}
}