diff --git a/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor b/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor
index d4ac4947..8e19125f 100644
--- a/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor
+++ b/Oqtane.Client/Modules/Admin/SystemInfo/Index.razor
@@ -52,6 +52,7 @@
+Access Framework API
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
diff --git a/Oqtane.Client/Modules/HtmlText/ModuleInfo.cs b/Oqtane.Client/Modules/HtmlText/ModuleInfo.cs
index 48b674d5..4be90a8b 100644
--- a/Oqtane.Client/Modules/HtmlText/ModuleInfo.cs
+++ b/Oqtane.Client/Modules/HtmlText/ModuleInfo.cs
@@ -9,7 +9,8 @@ namespace Oqtane.Modules.HtmlText
Name = "HtmlText",
Description = "Renders HTML or Text Content",
Version = "1.0.0",
- ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server"
+ ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
+ ReleaseVersions = "1.0.0"
};
}
}
diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs
index b197e62d..74ff43b9 100644
--- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs
+++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs
@@ -12,7 +12,7 @@ using Oqtane.Infrastructure;
using Oqtane.Repository;
using Oqtane.Security;
using System;
-using System.Runtime.InteropServices.ComTypes;
+using Microsoft.Extensions.DependencyInjection;
// ReSharper disable StringIndexOfIsCultureSpecific.1
namespace Oqtane.Controllers
@@ -25,21 +25,17 @@ namespace Oqtane.Controllers
private readonly IUserPermissions _userPermissions;
private readonly IInstallationManager _installationManager;
private readonly IWebHostEnvironment _environment;
- private readonly ITenantResolver _resolver;
- private readonly ITenantRepository _tenants;
- private readonly ISqlRepository _sql;
+ private readonly IServiceProvider _serviceProvider;
private readonly ILogManager _logger;
- public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, ITenantResolver resolver, ITenantRepository tenants, ISqlRepository sql, ILogManager logger)
+ public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, IServiceProvider serviceProvider, ILogManager logger)
{
_moduleDefinitions = moduleDefinitions;
_modules = modules;
_userPermissions = userPermissions;
_installationManager = installationManager;
_environment = environment;
- _resolver = resolver;
- _tenants = tenants;
- _sql = sql;
+ _serviceProvider = serviceProvider;
_logger = logger;
}
@@ -100,57 +96,40 @@ namespace Oqtane.Controllers
[Authorize(Roles = Constants.HostRole)]
public void Delete(int id, int siteid)
{
- List moduledefinitions = _moduleDefinitions.GetModuleDefinitions(siteid).ToList();
- ModuleDefinition moduledefinition = moduledefinitions.Where(item => item.ModuleDefinitionId == id).FirstOrDefault();
+ ModuleDefinition moduledefinition = _moduleDefinitions.GetModuleDefinition(id, siteid);
if (moduledefinition != null)
{
- // server assembly name should follow client naming convention
- string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName).Replace(".Client",".Server");
-
- string uninstallScript = "";
- Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.GetName().Name == assemblyname);
- if (assembly != null)
+ if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType))
{
- Stream resourceStream = assembly.GetManifestResourceStream(assemblyname + ".Scripts.Uninstall.sql");
- if (resourceStream != null)
+ Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
+ if (moduletype != null && moduletype.GetInterface("IInstallable") != null)
{
- using (var reader = new StreamReader(resourceStream))
- {
- uninstallScript = reader.ReadToEnd();
- }
+ var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
+ ((IInstallable)moduleobject).Uninstall();
}
}
- foreach (Tenant tenant in _tenants.GetTenants())
- {
- // uninstall module database schema
- if (!string.IsNullOrEmpty(uninstallScript))
- {
- _sql.ExecuteScript(tenant, uninstallScript);
- _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Uninstall Script Executed For {AssemblyName}", assemblyname);
- }
- // clean up module schema versions
- _sql.ExecuteNonQuery(tenant, "DELETE FROM [dbo].[SchemaVersions] WHERE ScriptName LIKE '" + assemblyname + "%'");
- _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Schema Versions Removed For {AssemblyName}", assemblyname);
- }
-
// format root assembly name
- assemblyname = assemblyname.Replace(".Server", "");
-
- // clean up module static resource folder
- string folder = Path.Combine(_environment.WebRootPath, "Modules\\" + assemblyname);
- if (Directory.Exists(folder))
+ string assemblyname = Utilities.GetAssemblyName(moduledefinition.ModuleDefinitionName);
+ if (assemblyname != "Oqtane.Client")
{
- Directory.Delete(folder, true);
- _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {AssemblynName}", assemblyname);
- }
+ assemblyname = assemblyname.Replace(".Client", "");
- // remove module assembly 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);
+ // clean up module static resource folder
+ string folder = Path.Combine(_environment.WebRootPath, "Modules\\" + assemblyname);
+ if (Directory.Exists(folder))
+ {
+ Directory.Delete(folder, true);
+ _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {AssemblynName}", assemblyname);
+ }
+
+ // remove module assembly 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);
+ }
}
// remove module definition
@@ -247,12 +226,6 @@ namespace Oqtane.Controllers
text = text.Replace("[File]", Path.GetFileName(filePath));
text = text.Replace("[FrameworkVersion]", Constants.Version);
System.IO.File.WriteAllText(filePath, text);
-
- if (Path.GetExtension(filePath).ToLower() == ".sql" && !filePath.ToLower().Contains("uninstall"))
- {
- // execute installation script in curent tenant
- _sql.ExecuteScript(_resolver.GetTenant(), text);
- }
}
DirectoryInfo[] folders = current.GetDirectories();
diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs
index 76e91390..f283e075 100644
--- a/Oqtane.Server/Infrastructure/DatabaseManager.cs
+++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs
@@ -184,7 +184,7 @@ namespace Oqtane.Infrastructure
.SqlDatabase(connectionString)
.WithVariable("ConnectionString", connectionString)
.WithVariable("Alias", alias)
- .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => master || !s.Contains("Master."));
+ .WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains("Master."));
var dbUpgrade = dbUpgradeConfig.Build();
if (!dbUpgrade.IsUpgradeRequired())
diff --git a/Oqtane.Server/Infrastructure/Interfaces/IInstallable.cs b/Oqtane.Server/Infrastructure/Interfaces/IInstallable.cs
new file mode 100644
index 00000000..c71de4f6
--- /dev/null
+++ b/Oqtane.Server/Infrastructure/Interfaces/IInstallable.cs
@@ -0,0 +1,8 @@
+namespace Oqtane.Infrastructure
+{
+ public interface IInstallable
+ {
+ bool Install(string version);
+ bool Uninstall();
+ }
+}
diff --git a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs
index f37ac523..4d38e250 100644
--- a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs
+++ b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs
@@ -1,17 +1,31 @@
-using Oqtane.Models;
+using Oqtane.Infrastructure;
+using Oqtane.Models;
+using Oqtane.Repository;
using Oqtane.Modules.HtmlText.Models;
using Oqtane.Modules.HtmlText.Repository;
using System.Net;
namespace Oqtane.Modules.HtmlText.Manager
{
- public class HtmlTextManager : IPortable
+ public class HtmlTextManager : IInstallable, IPortable
{
private IHtmlTextRepository _htmlTexts;
+ private ISqlRepository _sql;
- public HtmlTextManager(IHtmlTextRepository htmltexts)
+ public HtmlTextManager(IHtmlTextRepository htmltexts, ISqlRepository sql)
{
_htmlTexts = htmltexts;
+ _sql = sql;
+ }
+
+ public bool Install(string version)
+ {
+ return _sql.ExecuteEmbeddedScript(GetType().Assembly, "HtmlText." + version + ".sql");
+ }
+
+ public bool Uninstall()
+ {
+ return _sql.ExecuteEmbeddedScript(GetType().Assembly, "HtmlText.Uninstall.sql");
}
public string ExportModule(Module module)
diff --git a/Oqtane.Server/Modules/HtmlText/Scripts/HtmlText.1.0.0.sql b/Oqtane.Server/Modules/HtmlText/Scripts/HtmlText.1.0.0.sql
new file mode 100644
index 00000000..5c54eae2
--- /dev/null
+++ b/Oqtane.Server/Modules/HtmlText/Scripts/HtmlText.1.0.0.sql
@@ -0,0 +1,19 @@
+CREATE TABLE [dbo].[HtmlText](
+ [HtmlTextId] [int] IDENTITY(1,1) NOT NULL,
+ [ModuleId] [int] NOT NULL,
+ [Content] [nvarchar](max) NOT NULL,
+ [CreatedBy] [nvarchar](256) NOT NULL,
+ [CreatedOn] [datetime] NOT NULL,
+ [ModifiedBy] [nvarchar](256) NOT NULL,
+ [ModifiedOn] [datetime] NOT NULL,
+ CONSTRAINT [PK_HtmlText] PRIMARY KEY CLUSTERED
+ (
+ [HtmlTextId] ASC
+ )
+)
+GO
+
+ALTER TABLE [dbo].[HtmlText] WITH CHECK ADD CONSTRAINT [FK_HtmlText_Module] FOREIGN KEY([ModuleId])
+REFERENCES [dbo].[Module] ([ModuleId])
+ON DELETE CASCADE
+GO
diff --git a/Oqtane.Server/Modules/HtmlText/Scripts/HtmlText.Uninstall.sql b/Oqtane.Server/Modules/HtmlText/Scripts/HtmlText.Uninstall.sql
new file mode 100644
index 00000000..b0831b67
--- /dev/null
+++ b/Oqtane.Server/Modules/HtmlText/Scripts/HtmlText.Uninstall.sql
@@ -0,0 +1,2 @@
+DROP TABLE [dbo].[HtmlText]
+GO
diff --git a/Oqtane.Server/Oqtane.Server.csproj b/Oqtane.Server/Oqtane.Server.csproj
index fd6d457d..63634523 100644
--- a/Oqtane.Server/Oqtane.Server.csproj
+++ b/Oqtane.Server/Oqtane.Server.csproj
@@ -18,6 +18,13 @@
+
+
+
+
+
+
+
diff --git a/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs b/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs
index 29dfe8ba..037e9416 100644
--- a/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs
+++ b/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs
@@ -1,10 +1,12 @@
using System.Data.SqlClient;
+using System.Reflection;
using Oqtane.Models;
namespace Oqtane.Repository
{
public interface ISqlRepository
{
+ bool ExecuteEmbeddedScript(Assembly assembly, string script);
void ExecuteScript(Tenant tenant, string script);
int ExecuteNonQuery(Tenant tenant, string query);
SqlDataReader ExecuteReader(Tenant tenant, string query);
diff --git a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
index 4803ba9e..5bc8ee64 100644
--- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
+++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
@@ -188,18 +188,15 @@ namespace Oqtane.Repository
{
Name = moduleType.Substring(moduleType.LastIndexOf(".") + 1),
Description = "Manage " + moduleType.Substring(moduleType.LastIndexOf(".") + 1),
- Categories = ((qualifiedModuleType.StartsWith("Oqtane.Modules.Admin.")) ? "Admin" : ""),
- Version = "1.0.0"
+ Categories = ((qualifiedModuleType.StartsWith("Oqtane.Modules.Admin.")) ? "Admin" : "")
};
}
// set internal properties
moduledefinition.ModuleDefinitionName = qualifiedModuleType;
+ moduledefinition.Version = ""; // will be populated from database
moduledefinition.ControlTypeTemplate = moduleType + "." + Constants.ActionToken + ", " + typename[1];
moduledefinition.AssemblyName = assembly.FullName.Split(",")[0];
- if (assembly.FullName.StartsWith("Oqtane.Client"))
- {
- moduledefinition.Version = Constants.Version;
- }
+
if (string.IsNullOrEmpty(moduledefinition.Categories))
{
moduledefinition.Categories = "Common";
diff --git a/Oqtane.Server/Repository/ModuleRepository.cs b/Oqtane.Server/Repository/ModuleRepository.cs
index 7d88f0a1..1ec27d3f 100644
--- a/Oqtane.Server/Repository/ModuleRepository.cs
+++ b/Oqtane.Server/Repository/ModuleRepository.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs
index f85294df..5861aa04 100644
--- a/Oqtane.Server/Repository/SiteRepository.cs
+++ b/Oqtane.Server/Repository/SiteRepository.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
@@ -20,7 +19,6 @@ namespace Oqtane.Repository
private readonly IRoleRepository _roleRepository;
private readonly IProfileRepository _profileRepository;
private readonly IFolderRepository _folderRepository;
- private readonly IFileRepository _fileRepository;
private readonly IPageRepository _pageRepository;
private readonly IModuleRepository _moduleRepository;
private readonly IPageModuleRepository _pageModuleRepository;
@@ -30,15 +28,14 @@ namespace Oqtane.Repository
private readonly IConfigurationRoot _config;
- public SiteRepository(TenantDBContext context, IRoleRepository roleRepository, IProfileRepository profileRepository, IFolderRepository folderRepository, IFileRepository fileRepository, IPageRepository pageRepository,
- IModuleRepository moduleRepository, IPageModuleRepository pageModuleRepository, IModuleDefinitionRepository moduleDefinitionRepository, IPermissionRepository permissionRepository, IServiceProvider serviceProvider,
+ public SiteRepository(TenantDBContext context, IRoleRepository roleRepository, IProfileRepository profileRepository, IFolderRepository folderRepository, IPageRepository pageRepository,
+ IModuleRepository moduleRepository, IPageModuleRepository pageModuleRepository, IModuleDefinitionRepository moduleDefinitionRepository, IServiceProvider serviceProvider,
IConfigurationRoot config)
{
_db = context;
_roleRepository = roleRepository;
_profileRepository = profileRepository;
_folderRepository = folderRepository;
- _fileRepository = fileRepository;
_pageRepository = pageRepository;
_moduleRepository = moduleRepository;
_pageModuleRepository = pageModuleRepository;
@@ -787,7 +784,14 @@ namespace Oqtane.Repository
if (moduletype != null && moduletype.GetInterface("IPortable") != null)
{
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
- ((IPortable) moduleobject).ImportModule(module, pagetemplatemodule.Content, moduledefinition.Version);
+ try
+ {
+ ((IPortable)moduleobject).ImportModule(module, pagetemplatemodule.Content, moduledefinition.Version);
+ }
+ catch
+ {
+ // error in module import
+ }
}
}
diff --git a/Oqtane.Server/Repository/SqlRepository.cs b/Oqtane.Server/Repository/SqlRepository.cs
index f20b28e6..0e5c2f3c 100644
--- a/Oqtane.Server/Repository/SqlRepository.cs
+++ b/Oqtane.Server/Repository/SqlRepository.cs
@@ -1,12 +1,61 @@
using System;
using System.Data;
using System.Data.SqlClient;
+using System.IO;
+using System.Linq;
+using System.Reflection;
using Oqtane.Models;
namespace Oqtane.Repository
{
public class SqlRepository : ISqlRepository
{
+ private readonly ITenantRepository _tenants;
+
+ public SqlRepository(ITenantRepository tenants)
+ {
+ _tenants = tenants;
+ }
+
+ public bool ExecuteEmbeddedScript(Assembly assembly, string filename)
+ {
+ // script must be included as an Embedded Resource within an assembly
+ bool success = true;
+ string uninstallScript = "";
+
+ if (assembly != null)
+ {
+ string name = assembly.GetManifestResourceNames().FirstOrDefault(item => item.EndsWith("." + filename));
+ if (name != null)
+ {
+ Stream resourceStream = assembly.GetManifestResourceStream(name);
+ if (resourceStream != null)
+ {
+ using (var reader = new StreamReader(resourceStream))
+ {
+ uninstallScript = reader.ReadToEnd();
+ }
+ }
+ }
+ }
+
+ if (!string.IsNullOrEmpty(uninstallScript))
+ {
+ foreach (Tenant tenant in _tenants.GetTenants())
+ {
+ try
+ {
+ ExecuteScript(tenant, uninstallScript);
+ }
+ catch
+ {
+ success = false;
+ }
+ }
+ }
+
+ return success;
+ }
public void ExecuteScript(Tenant tenant, string script)
{
diff --git a/Oqtane.Shared/Models/ModuleDefinition.cs b/Oqtane.Shared/Models/ModuleDefinition.cs
index 82836f0c..504cc890 100644
--- a/Oqtane.Shared/Models/ModuleDefinition.cs
+++ b/Oqtane.Shared/Models/ModuleDefinition.cs
@@ -19,6 +19,7 @@ namespace Oqtane.Models
PermissionNames = "";
ServerManagerType = "";
ControlTypeRoutes = "";
+ ReleaseVersions = "";
Template = "";
}
@@ -34,8 +35,7 @@ namespace Oqtane.Models
public string ModifiedBy { get; set; }
public DateTime ModifiedOn { get; set; }
- [NotMapped]
- public int SiteId { get; set; }
+ // additional IModule properties
[NotMapped]
public string Owner { get; set; }
[NotMapped]
@@ -53,12 +53,18 @@ namespace Oqtane.Models
[NotMapped]
public string ControlTypeRoutes { get; set; }
[NotMapped]
- public string Template { get; set; }
+ public string ReleaseVersions { get; set; }
+
+ // internal properties
+ [NotMapped]
+ public int SiteId { get; set; }
[NotMapped]
public string ControlTypeTemplate { get; set; }
[NotMapped]
public string AssemblyName { get; set; }
[NotMapped]
public string Permissions { get; set; }
+ [NotMapped]
+ public string Template { get; set; }
}
}