diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/Scripts/01.00.00.sql b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/Scripts/01.00.00.sql
index 0e7266e6..7a1b99ea 100644
--- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/Scripts/01.00.00.sql
+++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/Scripts/01.00.00.sql
@@ -1,5 +1,5 @@
/*
-Create [Module] table
+Create [Owner][Module] table
*/
CREATE TABLE [dbo].[[Owner][Module]](
diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/Scripts/Uninstall.sql b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/Scripts/Uninstall.sql
new file mode 100644
index 00000000..47baecc9
--- /dev/null
+++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/External/Server/Scripts/Uninstall.sql
@@ -0,0 +1,6 @@
+/*
+Remove [Owner][Module] table
+*/
+
+DROP TABLE [dbo].[[Owner][Module]]
+GO
diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/01.00.00.sql b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/01.00.00.sql
index 0e7266e6..7a1b99ea 100644
--- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/01.00.00.sql
+++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/01.00.00.sql
@@ -1,5 +1,5 @@
/*
-Create [Module] table
+Create [Owner][Module] table
*/
CREATE TABLE [dbo].[[Owner][Module]](
diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/Tenant.01.00.00.sql b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/Tenant.01.00.00.sql
deleted file mode 100644
index f97f4daf..00000000
--- a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/Tenant.01.00.00.sql
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-Create [Module] table
-*/
-
-CREATE TABLE [dbo].[[Module]](
- [[Module]Id] [int] IDENTITY(1,1) NOT NULL,
- [ModuleId] [int] NOT NULL,
- [Name] [nvarchar](256) NOT NULL,
- [CreatedBy] [nvarchar](256) NOT NULL,
- [CreatedOn] [datetime] NOT NULL,
- [ModifiedBy] [nvarchar](256) NOT NULL,
- [ModifiedOn] [datetime] NOT NULL,
- CONSTRAINT [PK_[Module]] PRIMARY KEY CLUSTERED
- (
- [[Module]Id] ASC
- )
-)
-GO
-
-/*
-Create foreign key relationships
-*/
-ALTER TABLE [dbo].[[Module]] WITH CHECK ADD CONSTRAINT [FK_[Module]_Module] FOREIGN KEY([ModuleId])
-REFERENCES [dbo].Module ([ModuleId])
-ON DELETE CASCADE
-GO
\ No newline at end of file
diff --git a/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/Uninstall.sql b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/Uninstall.sql
new file mode 100644
index 00000000..47baecc9
--- /dev/null
+++ b/Oqtane.Client/Modules/Admin/ModuleCreator/Templates/Internal/Oqtane.Server/Modules/[Module]/Scripts/Uninstall.sql
@@ -0,0 +1,6 @@
+/*
+Remove [Owner][Module] table
+*/
+
+DROP TABLE [dbo].[[Owner][Module]]
+GO
diff --git a/Oqtane.Client/Themes/Controls/ControlPanel.razor b/Oqtane.Client/Themes/Controls/ControlPanel.razor
index 2a352fd9..f2cf43e7 100644
--- a/Oqtane.Client/Themes/Controls/ControlPanel.razor
+++ b/Oqtane.Client/Themes/Controls/ControlPanel.razor
@@ -10,7 +10,7 @@
@inject IPageModuleService PageModuleService
@inject ILogService logger
-@if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, PageState.Page.Permissions))
+@if (_moduleDefinitions != null && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, PageState.Page.Permissions))
{
@@ -231,17 +231,17 @@
{
ButtonClass = "btn-outline-primary";
}
-
+
if (string.IsNullOrEmpty(CardClass))
{
CardClass = "card bg-secondary mb-3";
}
-
+
if (string.IsNullOrEmpty(HeaderClass))
{
HeaderClass = "card-header text-white";
}
-
+
if (string.IsNullOrEmpty(BodyClass))
{
BodyClass = "card-body";
@@ -251,8 +251,22 @@
{
_pages?.Clear();
+ foreach (Page p in PageState.Pages)
+ {
+ if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, p.Permissions))
+ {
+ _pages.Add(p);
+ }
+ }
+
+ var panes = PageState.Page.Panes.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
+ _pane = panes.Count() == 1 ? panes.SingleOrDefault() : "";
+ var themes = await ThemeService.GetThemesAsync();
+ _containers = ThemeService.GetContainerTypes(themes);
+ _containerType = PageState.Site.DefaultContainerType;
+
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId);
-
+
foreach (ModuleDefinition moduledefinition in _allModuleDefinitions)
{
if (moduledefinition.Categories != "")
@@ -266,22 +280,8 @@
}
}
}
-
+
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories == "").ToList();
-
- foreach (Page p in PageState.Pages)
- {
- if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, p.Permissions))
- {
- _pages.Add(p);
- }
- }
-
- var panes = PageState.Page.Panes.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
- _pane = panes.Count() == 1 ? panes.SingleOrDefault() : "";
- var themes = await ThemeService.GetThemesAsync();
- _containers = ThemeService.GetContainerTypes(themes);
- _containerType = PageState.Site.DefaultContainerType;
}
}
@@ -296,7 +296,7 @@
{
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(category)).ToList();
}
-
+
_moduleDefinitionName = "-";
StateHasChanged();
}
@@ -305,7 +305,7 @@
{
_pageId = (string) e.Value;
_modules?.Clear();
-
+
if (_pageId != "-")
{
foreach (Module module in PageState.Modules.Where(item => item.PageId == int.Parse(_pageId) && !item.IsDeleted))
@@ -316,7 +316,7 @@
}
}
}
-
+
_moduleId = "-";
StateHasChanged();
}
@@ -355,7 +355,7 @@
pageModule.Title = _modules.FirstOrDefault(item => item.ModuleId == int.Parse(_moduleId))?.Title;
}
}
-
+
pageModule.Pane = _pane;
pageModule.Order = int.MaxValue;
pageModule.ContainerType = _containerType;
@@ -438,19 +438,19 @@
case "Admin":
// get admin dashboard moduleid
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule);
-
+
if (module != null)
{
NavigationManager.NavigateTo(EditUrl(PageState.Page.Path, module.ModuleId, "Index", ""));
}
-
+
break;
case "Add":
case "Edit":
string url = "";
// get page management moduleid
module = PageState.Modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule);
-
+
if (module != null)
{
switch (location)
@@ -463,12 +463,12 @@
break;
}
}
-
+
if (url != "")
{
NavigationManager.NavigateTo(url);
}
-
+
break;
}
}
@@ -482,7 +482,7 @@
private async Task DeletePage()
{
ConfirmDelete();
-
+
var page = PageState.Page;
try
{
diff --git a/Oqtane.Server/Controllers/ModuleDefinitionController.cs b/Oqtane.Server/Controllers/ModuleDefinitionController.cs
index 348673e1..21f8614d 100644
--- a/Oqtane.Server/Controllers/ModuleDefinitionController.cs
+++ b/Oqtane.Server/Controllers/ModuleDefinitionController.cs
@@ -26,10 +26,11 @@ namespace Oqtane.Controllers
private readonly IInstallationManager _installationManager;
private readonly IWebHostEnvironment _environment;
private readonly ITenantResolver _resolver;
+ private readonly ITenantRepository _tenants;
private readonly ISqlRepository _sql;
private readonly ILogManager _logger;
- public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, ITenantResolver resolver, ISqlRepository sql, ILogManager logger)
+ public ModuleDefinitionController(IModuleDefinitionRepository moduleDefinitions, IModuleRepository modules, IUserPermissions userPermissions, IInstallationManager installationManager, IWebHostEnvironment environment, ITenantResolver resolver, ITenantRepository tenants, ISqlRepository sql, ILogManager logger)
{
_moduleDefinitions = moduleDefinitions;
_modules = modules;
@@ -37,6 +38,7 @@ namespace Oqtane.Controllers
_installationManager = installationManager;
_environment = environment;
_resolver = resolver;
+ _tenants = tenants;
_sql = sql;
_logger = logger;
}
@@ -102,23 +104,59 @@ namespace Oqtane.Controllers
ModuleDefinition moduledefinition = moduledefinitions.Where(item => item.ModuleDefinitionId == id).FirstOrDefault();
if (moduledefinition != null)
{
+ if (!string.IsNullOrEmpty(moduledefinition.ServerAssemblyName))
+ {
+ string uninstallScript = "";
+ Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().SingleOrDefault(a => a.GetName().Name == moduledefinition.ServerAssemblyName);
+ if (assembly != null)
+ {
+ Stream resourceStream = assembly.GetManifestResourceStream(moduledefinition.ServerAssemblyName + ".Scripts.Uninstall.sql");
+ if (resourceStream != null)
+ {
+ using (var reader = new StreamReader(resourceStream))
+ {
+ uninstallScript = reader.ReadToEnd();
+ }
+ }
+ }
+
+ 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 {ServerAssemblyName}", moduledefinition.ServerAssemblyName);
+ }
+ // clean up module schema versions
+ _sql.ExecuteNonQuery(tenant, "DELETE FROM [dbo].[SchemaVersions] WHERE ScriptName LIKE '" + moduledefinition.ServerAssemblyName + "%'");
+ _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Schema Versions Removed For {ServerAssemblyName}", moduledefinition.ServerAssemblyName);
+ }
+ }
+
string moduledefinitionname = moduledefinition.ModuleDefinitionName.Substring(0, moduledefinition.ModuleDefinitionName.IndexOf(","));
+ // clean up module static resource folder
string folder = Path.Combine(_environment.WebRootPath, "Modules\\" + moduledefinitionname);
if (Directory.Exists(folder))
{
Directory.Delete(folder, true);
+ _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Static Resources Removed For {ModuleDefinitionName}", moduledefinitionname);
}
+ // remove module assembly from /bin
string binfolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
- foreach (string file in Directory.EnumerateFiles(binfolder, moduledefinitionname + "*.dll"))
+ foreach (string file in Directory.EnumerateFiles(binfolder, moduledefinitionname + "*.*"))
{
System.IO.File.Delete(file);
+ _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assemblies Removed For {ModuleDefinitionName}", moduledefinitionname);
}
+ // remove module definition
_moduleDefinitions.DeleteModuleDefinition(id, siteid);
- _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Deleted {ModuleDefinitionId}", id);
+ _logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Definition Deleted {ModuleDefinitionName}", moduledefinition.Name);
+ // restart application
_installationManager.RestartApplication();
}
}
@@ -209,10 +247,7 @@ namespace Oqtane.Controllers
if (Path.GetExtension(filePath) == ".sql")
{
// execute script in curent tenant
- foreach (string query in text.Split("GO", StringSplitOptions.RemoveEmptyEntries))
- {
- _sql.ExecuteNonQuery(_resolver.GetTenant(), query);
- }
+ _sql.ExecuteScript(_resolver.GetTenant(), text);
}
}
diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs
index d058d2fe..dabe8c78 100644
--- a/Oqtane.Server/Infrastructure/DatabaseManager.cs
+++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs
@@ -11,7 +11,6 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
-using Oqtane.Controllers;
using Oqtane.Extensions;
using Oqtane.Models;
using Oqtane.Repository;
@@ -109,7 +108,7 @@ namespace Oqtane.Infrastructure
}
else
{
- Message = "Database is not avaiable";
+ Message = "Database is not available";
}
}
else
@@ -214,7 +213,7 @@ namespace Oqtane.Infrastructure
Console.WriteLine($"Migrating assembly {assembly.FullName}");
var dbUpgradeConfig = DeployChanges.To.SqlDatabase(connectionString)
- .WithScriptsEmbeddedInAssembly(assembly); // scripts must be included as Embedded Resources
+ .WithScriptsEmbeddedInAssembly(assembly, s => !s.ToLower().Contains("uninstall.sql")); // scripts must be included as Embedded Resources
var dbUpgrade = dbUpgradeConfig.Build();
if (dbUpgrade.IsUpgradeRequired())
{
@@ -368,8 +367,6 @@ namespace Oqtane.Infrastructure
return value;
}
-
-
private static void CreateHostUser(IFolderRepository folderRepository, IUserRoleRepository userRoleRepository, IRoleRepository roleRepository, IUserRepository userRepository, UserManager
identityUserManager, User user)
{
var identityUser = new IdentityUser {UserName = user.Username, Email = user.Email, EmailConfirmed = true};
@@ -427,7 +424,6 @@ namespace Oqtane.Infrastructure
}
}
-
public static bool TableExists(DbContext context, string tableName)
{
return TableExists(context, "dbo", tableName);
diff --git a/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs b/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs
index 4bd04e91..29dfe8ba 100644
--- a/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs
+++ b/Oqtane.Server/Repository/Interfaces/ISqlRepository.cs
@@ -5,6 +5,7 @@ namespace Oqtane.Repository
{
public interface ISqlRepository
{
+ 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 8d711245..0023c2e8 100644
--- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
+++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs
@@ -15,6 +15,7 @@ namespace Oqtane.Repository
private MasterDBContext _db;
private readonly IMemoryCache _cache;
private readonly IPermissionRepository _permissions;
+ private List _moduleDefinitions; // lazy load
public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions)
{
@@ -61,12 +62,12 @@ namespace Oqtane.Repository
private List LoadSiteModuleDefinitions(int siteId)
{
- // get module assemblies
- List moduleDefinitions = _cache.GetOrCreate("moduledefinitions", entry =>
+ if (_moduleDefinitions == null)
{
- entry.SlidingExpiration = TimeSpan.FromMinutes(30);
- return LoadModuleDefinitionsFromAssemblies();
- });
+ // get module assemblies
+ _moduleDefinitions = LoadModuleDefinitionsFromAssemblies();
+ }
+ List moduleDefinitions = _moduleDefinitions;
// get module definition permissions for site
List permissions = _permissions.GetPermissions(siteId, EntityNames.ModuleDefinition).ToList();
@@ -210,14 +211,5 @@ namespace Oqtane.Repository
return moduledefinitions;
}
- private string GetProperty(Dictionary properties, string key)
- {
- string value = "";
- if (properties.ContainsKey(key))
- {
- value = properties[key];
- }
- return value;
- }
}
}
diff --git a/Oqtane.Server/Repository/SqlRepository.cs b/Oqtane.Server/Repository/SqlRepository.cs
index 2952752e..f20b28e6 100644
--- a/Oqtane.Server/Repository/SqlRepository.cs
+++ b/Oqtane.Server/Repository/SqlRepository.cs
@@ -8,6 +8,15 @@ namespace Oqtane.Repository
public class SqlRepository : ISqlRepository
{
+ public void ExecuteScript(Tenant tenant, string script)
+ {
+ // execute script in curent tenant
+ foreach (string query in script.Split("GO", StringSplitOptions.RemoveEmptyEntries))
+ {
+ ExecuteNonQuery(tenant, query);
+ }
+ }
+
public int ExecuteNonQuery(Tenant tenant, string query)
{
SqlConnection conn = new SqlConnection(FormatConnectionString(tenant.DBConnectionString));
diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs
index 1fa7c813..943f42a8 100644
--- a/Oqtane.Server/Repository/ThemeRepository.cs
+++ b/Oqtane.Server/Repository/ThemeRepository.cs
@@ -9,7 +9,24 @@ namespace Oqtane.Repository
{
public class ThemeRepository : IThemeRepository
{
+ private List _themes; // lazy load
+
+ public IEnumerable GetThemes()
+ {
+ return LoadThemes();
+ }
+
private List LoadThemes()
+ {
+ if (_themes == null)
+ {
+ // get themes
+ _themes = LoadThemesFromAssemblies();
+ }
+ return _themes;
+ }
+
+ private List LoadThemesFromAssemblies()
{
List themes = new List();
@@ -103,20 +120,5 @@ namespace Oqtane.Repository
}
return themes;
}
-
- private string GetProperty(Dictionary properties, string key)
- {
- string value = "";
- if (properties.ContainsKey(key))
- {
- value = properties[key];
- }
- return value;
- }
-
- public IEnumerable GetThemes()
- {
- return LoadThemes();
- }
}
}