Updated the Installation of Oqtane to use Migrations
This commit is contained in:
@ -6,11 +6,8 @@ using Oqtane.Shared;
|
|||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using System.Data.SqlClient;
|
|
||||||
using System.Data;
|
|
||||||
using System.Dynamic;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
using System;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
|
||||||
namespace Oqtane.Controllers
|
namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
|
BIN
Oqtane.Server/Data/Oqtane.db
Normal file
BIN
Oqtane.Server/Data/Oqtane.db
Normal file
Binary file not shown.
@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using DbUp;
|
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
@ -18,6 +15,11 @@ using Oqtane.Shared;
|
|||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using File = System.IO.File;
|
using File = System.IO.File;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable ConvertToUsingDeclaration
|
||||||
|
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
||||||
|
// ReSharper disable UseIndexFromEndExpression
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
public class DatabaseManager : IDatabaseManager
|
public class DatabaseManager : IDatabaseManager
|
||||||
@ -166,7 +168,7 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
//create data directory if does not exist
|
//create data directory if does not exist
|
||||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
||||||
if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory);
|
if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory ?? String.Empty);
|
||||||
|
|
||||||
var connectionString = NormalizeConnectionString(install.ConnectionString);
|
var connectionString = NormalizeConnectionString(install.ConnectionString);
|
||||||
using (var dbc = new DbContext(new DbContextOptionsBuilder().UseOqtaneDatabase(connectionString).Options))
|
using (var dbc = new DbContext(new DbContextOptionsBuilder().UseOqtaneDatabase(connectionString).Options))
|
||||||
@ -195,26 +197,20 @@ namespace Oqtane.Infrastructure
|
|||||||
|
|
||||||
if (install.TenantName == TenantNames.Master)
|
if (install.TenantName == TenantNames.Master)
|
||||||
{
|
{
|
||||||
MigrateScriptNamingConvention("Master", install.ConnectionString);
|
try
|
||||||
|
|
||||||
var upgradeConfig = DeployChanges
|
|
||||||
.To
|
|
||||||
.SqlDatabase(NormalizeConnectionString(install.ConnectionString))
|
|
||||||
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains("Master.") && s.EndsWith(".sql",StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
var upgrade = upgradeConfig.Build();
|
|
||||||
if (upgrade.IsUpgradeRequired())
|
|
||||||
{
|
{
|
||||||
var upgradeResult = upgrade.PerformUpgrade();
|
var dbConfig = new DbConfig(null, null) {ConnectionString = install.ConnectionString};
|
||||||
result.Success = upgradeResult.Successful;
|
|
||||||
if (!result.Success)
|
using (var masterDbContext = new MasterDBContext(new DbContextOptions<MasterDBContext>(), dbConfig))
|
||||||
{
|
{
|
||||||
result.Message = upgradeResult.Error.Message;
|
// Push latest model into database
|
||||||
|
masterDbContext.Database.Migrate();
|
||||||
|
result.Success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
result.Success = true;
|
result.Message = ex.Message;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
@ -251,10 +247,14 @@ namespace Oqtane.Infrastructure
|
|||||||
tenant = db.Tenant.FirstOrDefault(item => item.Name == install.TenantName);
|
tenant = db.Tenant.FirstOrDefault(item => item.Name == install.TenantName);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string aliasname in install.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
foreach (var aliasName in install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
var alias = new Alias { Name = aliasname, TenantId = tenant.TenantId, SiteId = -1, CreatedBy = "", CreatedOn = DateTime.UtcNow, ModifiedBy = "", ModifiedOn = DateTime.UtcNow };
|
if (tenant != null)
|
||||||
db.Alias.Add(alias);
|
{
|
||||||
|
var alias = new Alias { Name = aliasName, TenantId = tenant.TenantId, SiteId = -1, CreatedBy = "", CreatedOn = DateTime.UtcNow, ModifiedBy = "", ModifiedOn = DateTime.UtcNow };
|
||||||
|
db.Alias.Add(alias);
|
||||||
|
}
|
||||||
|
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
}
|
}
|
||||||
_cache.Remove("aliases");
|
_cache.Remove("aliases");
|
||||||
@ -270,7 +270,7 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
var result = new Installation { Success = false, Message = string.Empty };
|
var result = new Installation { Success = false, Message = string.Empty };
|
||||||
|
|
||||||
string[] versions = Constants.ReleaseVersions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
var versions = Constants.ReleaseVersions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
@ -280,29 +280,28 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
foreach (var tenant in db.Tenant.ToList())
|
foreach (var tenant in db.Tenant.ToList())
|
||||||
{
|
{
|
||||||
MigrateScriptNamingConvention("Tenant", tenant.DBConnectionString);
|
try
|
||||||
|
|
||||||
var upgradeConfig = DeployChanges.To.SqlDatabase(NormalizeConnectionString(tenant.DBConnectionString))
|
|
||||||
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s.Contains("Tenant.") && s.EndsWith(".sql", StringComparison.OrdinalIgnoreCase));
|
|
||||||
|
|
||||||
var upgrade = upgradeConfig.Build();
|
|
||||||
if (upgrade.IsUpgradeRequired())
|
|
||||||
{
|
{
|
||||||
var upgradeResult = upgrade.PerformUpgrade();
|
var dbConfig = new DbConfig(null, null) {ConnectionString = install.ConnectionString};
|
||||||
result.Success = upgradeResult.Successful;
|
using (var tenantDbContext = new TenantDBContext(dbConfig, null))
|
||||||
if (!result.Success)
|
|
||||||
{
|
{
|
||||||
result.Message = upgradeResult.Error.Message;
|
// Push latest model into database
|
||||||
|
tenantDbContext.Database.Migrate();
|
||||||
|
result.Success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
result.Message = ex.Message;
|
||||||
|
}
|
||||||
|
|
||||||
// execute any version specific upgrade logic
|
// execute any version specific upgrade logic
|
||||||
string version = tenant.Version;
|
var version = tenant.Version;
|
||||||
int index = Array.FindIndex(versions, item => item == version);
|
var index = Array.FindIndex(versions, item => item == version);
|
||||||
if (index != (versions.Length - 1))
|
if (index != (versions.Length - 1))
|
||||||
{
|
{
|
||||||
if (index == -1) index = 0;
|
if (index == -1) index = 0;
|
||||||
for (int i = index; i < versions.Length; i++)
|
for (var i = index; i < versions.Length; i++)
|
||||||
{
|
{
|
||||||
upgrades.Upgrade(tenant, versions[i]);
|
upgrades.Upgrade(tenant, versions[i]);
|
||||||
}
|
}
|
||||||
@ -328,53 +327,61 @@ namespace Oqtane.Infrastructure
|
|||||||
|
|
||||||
using (var scope = _serviceScopeFactory.CreateScope())
|
using (var scope = _serviceScopeFactory.CreateScope())
|
||||||
{
|
{
|
||||||
var moduledefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
|
var moduleDefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
|
||||||
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
||||||
foreach (var moduledefinition in moduledefinitions.GetModuleDefinitions())
|
foreach (var moduleDefinition in moduleDefinitions.GetModuleDefinitions())
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(moduledefinition.ReleaseVersions) && !string.IsNullOrEmpty(moduledefinition.ServerManagerType))
|
if (!string.IsNullOrEmpty(moduleDefinition.ReleaseVersions) && !string.IsNullOrEmpty(moduleDefinition.ServerManagerType))
|
||||||
{
|
{
|
||||||
Type moduletype = Type.GetType(moduledefinition.ServerManagerType);
|
var moduleType = Type.GetType(moduleDefinition.ServerManagerType);
|
||||||
if (moduletype != null)
|
if (moduleType != null)
|
||||||
{
|
{
|
||||||
string[] versions = moduledefinition.ReleaseVersions.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
var versions = moduleDefinition.ReleaseVersions.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey))))
|
using (var db = new InstallationContext(NormalizeConnectionString(_config.GetConnectionString(SettingKeys.ConnectionStringKey))))
|
||||||
{
|
{
|
||||||
foreach (var tenant in db.Tenant.ToList())
|
foreach (var tenant in db.Tenant.ToList())
|
||||||
{
|
{
|
||||||
int index = Array.FindIndex(versions, item => item == moduledefinition.Version);
|
if (moduleType.GetInterface("IMigratable") != null)
|
||||||
if (tenant.Name == install.TenantName && install.TenantName != TenantNames.Master)
|
|
||||||
{
|
{
|
||||||
index = -1;
|
var moduleObject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduleType) as IMigratable;
|
||||||
|
moduleObject.Migrate(tenant, MigrationType.Up);
|
||||||
}
|
}
|
||||||
if (index != (versions.Length - 1))
|
else
|
||||||
{
|
{
|
||||||
if (index == -1) index = 0;
|
var index = Array.FindIndex(versions, item => item == moduleDefinition.Version);
|
||||||
for (int i = index; i < versions.Length; i++)
|
if (tenant.Name == install.TenantName && install.TenantName != TenantNames.Master)
|
||||||
{
|
{
|
||||||
try
|
index = -1;
|
||||||
|
}
|
||||||
|
if (index != (versions.Length - 1))
|
||||||
|
{
|
||||||
|
if (index == -1) index = 0;
|
||||||
|
for (var i = index; i < versions.Length; i++)
|
||||||
{
|
{
|
||||||
if (moduletype.GetInterface("IInstallable") != null)
|
try
|
||||||
{
|
{
|
||||||
var moduleobject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduletype);
|
if (moduleType.GetInterface("IInstallable") != null)
|
||||||
((IInstallable)moduleobject).Install(tenant, versions[i]);
|
{
|
||||||
|
var moduleObject = ActivatorUtilities.CreateInstance(scope.ServiceProvider, moduleType);
|
||||||
|
((IInstallable)moduleObject).Install(tenant, versions[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sql.ExecuteScript(tenant, moduleType.Assembly, Utilities.GetTypeName(moduleDefinition.ModuleDefinitionName) + "." + versions[i] + ".sql");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
sql.ExecuteScript(tenant, moduletype.Assembly, Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + "." + versions[i] + ".sql");
|
result.Message = "An Error Occurred Installing " + moduleDefinition.Name + " Version " + versions[i] + " - " + ex.Message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
result.Message = "An Error Occurred Installing " + moduledefinition.Name + " Version " + versions[i] + " - " + ex.Message.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(result.Message) && moduledefinition.Version != versions[versions.Length - 1])
|
if (string.IsNullOrEmpty(result.Message) && moduleDefinition.Version != versions[versions.Length - 1])
|
||||||
{
|
{
|
||||||
moduledefinition.Version = versions[versions.Length - 1];
|
moduleDefinition.Version = versions[versions.Length - 1];
|
||||||
db.Entry(moduledefinition).State = EntityState.Modified;
|
db.Entry(moduleDefinition).State = EntityState.Modified;
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,8 +408,8 @@ namespace Oqtane.Infrastructure
|
|||||||
{
|
{
|
||||||
// use the SiteState to set the Alias explicitly so the tenant can be resolved
|
// use the SiteState to set the Alias explicitly so the tenant can be resolved
|
||||||
var aliases = scope.ServiceProvider.GetRequiredService<IAliasRepository>();
|
var aliases = scope.ServiceProvider.GetRequiredService<IAliasRepository>();
|
||||||
string firstalias = install.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
var firstAlias = install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||||
var alias = aliases.GetAliases().FirstOrDefault(item => item.Name == firstalias);
|
var alias = aliases.GetAliases().FirstOrDefault(item => item.Name == firstAlias);
|
||||||
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
||||||
siteState.Alias = alias;
|
siteState.Alias = alias;
|
||||||
|
|
||||||
@ -413,82 +420,88 @@ namespace Oqtane.Infrastructure
|
|||||||
var tenants = scope.ServiceProvider.GetRequiredService<ITenantRepository>();
|
var tenants = scope.ServiceProvider.GetRequiredService<ITenantRepository>();
|
||||||
var users = scope.ServiceProvider.GetRequiredService<IUserRepository>();
|
var users = scope.ServiceProvider.GetRequiredService<IUserRepository>();
|
||||||
var roles = scope.ServiceProvider.GetRequiredService<IRoleRepository>();
|
var roles = scope.ServiceProvider.GetRequiredService<IRoleRepository>();
|
||||||
var userroles = scope.ServiceProvider.GetRequiredService<IUserRoleRepository>();
|
var userRoles = scope.ServiceProvider.GetRequiredService<IUserRoleRepository>();
|
||||||
var folders = scope.ServiceProvider.GetRequiredService<IFolderRepository>();
|
var folders = scope.ServiceProvider.GetRequiredService<IFolderRepository>();
|
||||||
var log = scope.ServiceProvider.GetRequiredService<ILogManager>();
|
var log = scope.ServiceProvider.GetRequiredService<ILogManager>();
|
||||||
var identityUserManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
|
var identityUserManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
|
||||||
|
|
||||||
var tenant = tenants.GetTenants().FirstOrDefault(item => item.Name == install.TenantName);
|
var tenant = tenants.GetTenants().FirstOrDefault(item => item.Name == install.TenantName);
|
||||||
|
|
||||||
site = new Site
|
if (tenant != null)
|
||||||
{
|
{
|
||||||
TenantId = tenant.TenantId,
|
site = new Site
|
||||||
Name = install.SiteName,
|
|
||||||
LogoFileId = null,
|
|
||||||
DefaultThemeType = install.DefaultTheme,
|
|
||||||
DefaultLayoutType = install.DefaultLayout,
|
|
||||||
DefaultContainerType = install.DefaultContainer,
|
|
||||||
SiteTemplateType = install.SiteTemplate
|
|
||||||
};
|
|
||||||
site = sites.AddSite(site);
|
|
||||||
|
|
||||||
IdentityUser identityUser = identityUserManager.FindByNameAsync(UserNames.Host).GetAwaiter().GetResult();
|
|
||||||
if (identityUser == null)
|
|
||||||
{
|
|
||||||
identityUser = new IdentityUser { UserName = UserNames.Host, Email = install.HostEmail, EmailConfirmed = true };
|
|
||||||
var create = identityUserManager.CreateAsync(identityUser, install.HostPassword).GetAwaiter().GetResult();
|
|
||||||
if (create.Succeeded)
|
|
||||||
{
|
{
|
||||||
var user = new User
|
TenantId = tenant.TenantId,
|
||||||
{
|
Name = install.SiteName,
|
||||||
SiteId = site.SiteId,
|
LogoFileId = null,
|
||||||
Username = UserNames.Host,
|
DefaultThemeType = install.DefaultTheme,
|
||||||
Password = install.HostPassword,
|
DefaultLayoutType = install.DefaultLayout,
|
||||||
Email = install.HostEmail,
|
DefaultContainerType = install.DefaultContainer,
|
||||||
DisplayName = install.HostName,
|
SiteTemplateType = install.SiteTemplate
|
||||||
LastIPAddress = "",
|
};
|
||||||
LastLoginOn = null
|
site = sites.AddSite(site);
|
||||||
};
|
|
||||||
|
|
||||||
user = users.AddUser(user);
|
var identityUser = identityUserManager.FindByNameAsync(UserNames.Host).GetAwaiter().GetResult();
|
||||||
var hostRoleId = roles.GetRoles(user.SiteId, true).FirstOrDefault(item => item.Name == RoleNames.Host)?.RoleId ?? 0;
|
if (identityUser == null)
|
||||||
var userRole = new UserRole { UserId = user.UserId, RoleId = hostRoleId, EffectiveDate = null, ExpiryDate = null };
|
{
|
||||||
userroles.AddUserRole(userRole);
|
identityUser = new IdentityUser {UserName = UserNames.Host, Email = install.HostEmail, EmailConfirmed = true};
|
||||||
|
var create = identityUserManager.CreateAsync(identityUser, install.HostPassword).GetAwaiter().GetResult();
|
||||||
// add user folder
|
if (create.Succeeded)
|
||||||
var folder = folders.GetFolder(user.SiteId, Utilities.PathCombine("Users", Path.DirectorySeparatorChar.ToString()));
|
|
||||||
if (folder != null)
|
|
||||||
{
|
{
|
||||||
folders.AddFolder(new Folder
|
var user = new User
|
||||||
{
|
{
|
||||||
SiteId = folder.SiteId,
|
SiteId = site.SiteId,
|
||||||
ParentId = folder.FolderId,
|
Username = UserNames.Host,
|
||||||
Name = "My Folder",
|
Password = install.HostPassword,
|
||||||
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
Email = install.HostEmail,
|
||||||
Order = 1,
|
DisplayName = install.HostName,
|
||||||
IsSystem = true,
|
LastIPAddress = "",
|
||||||
Permissions = new List<Permission>
|
LastLoginOn = null
|
||||||
|
};
|
||||||
|
|
||||||
|
user = users.AddUser(user);
|
||||||
|
var hostRoleId = roles.GetRoles(user.SiteId, true).FirstOrDefault(item => item.Name == RoleNames.Host)?.RoleId ?? 0;
|
||||||
|
var userRole = new UserRole {UserId = user.UserId, RoleId = hostRoleId, EffectiveDate = null, ExpiryDate = null};
|
||||||
|
userRoles.AddUserRole(userRole);
|
||||||
|
|
||||||
|
// add user folder
|
||||||
|
var folder = folders.GetFolder(user.SiteId, Utilities.PathCombine("Users", Path.DirectorySeparatorChar.ToString()));
|
||||||
|
if (folder != null)
|
||||||
|
{
|
||||||
|
folders.AddFolder(new Folder
|
||||||
{
|
{
|
||||||
new Permission(PermissionNames.Browse, user.UserId, true),
|
SiteId = folder.SiteId,
|
||||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
ParentId = folder.FolderId,
|
||||||
new Permission(PermissionNames.Edit, user.UserId, true),
|
Name = "My Folder",
|
||||||
}.EncodePermissions(),
|
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
||||||
});
|
Order = 1,
|
||||||
|
IsSystem = true,
|
||||||
|
Permissions = new List<Permission>
|
||||||
|
{
|
||||||
|
new Permission(PermissionNames.Browse, user.UserId, true),
|
||||||
|
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||||
|
new Permission(PermissionNames.Edit, user.UserId, true),
|
||||||
|
}.EncodePermissions(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var aliasName in install.Aliases.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
alias = aliases.GetAliases().FirstOrDefault(item => item.Name == aliasName);
|
||||||
|
if (alias != null)
|
||||||
|
{
|
||||||
|
alias.SiteId = site.SiteId;
|
||||||
|
aliases.UpdateAlias(alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tenant.Version = Constants.Version;
|
||||||
|
tenants.UpdateTenant(tenant);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string aliasname in install.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
if (site != null) log.Log(site.SiteId, LogLevel.Trace, this, LogFunction.Create, "Site Created {Site}", site);
|
||||||
{
|
|
||||||
alias = aliases.GetAliases().FirstOrDefault(item => item.Name == aliasname);
|
|
||||||
alias.SiteId = site.SiteId;
|
|
||||||
aliases.UpdateAlias(alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
tenant.Version = Constants.Version;
|
|
||||||
tenants.UpdateTenant(tenant);
|
|
||||||
|
|
||||||
log.Log(site.SiteId, LogLevel.Trace, this, LogFunction.Create, "Site Created {Site}", site);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,7 +521,7 @@ namespace Oqtane.Infrastructure
|
|||||||
private string DenormalizeConnectionString(string connectionString)
|
private string DenormalizeConnectionString(string connectionString)
|
||||||
{
|
{
|
||||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
||||||
connectionString = connectionString.Replace(dataDirectory, "|DataDirectory|");
|
connectionString = connectionString.Replace(dataDirectory ?? String.Empty, "|DataDirectory|");
|
||||||
return connectionString;
|
return connectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,18 +580,5 @@ namespace Oqtane.Infrastructure
|
|||||||
if (string.IsNullOrEmpty(value)) value = defaultValue;
|
if (string.IsNullOrEmpty(value)) value = defaultValue;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MigrateScriptNamingConvention(string scriptType, string connectionString)
|
|
||||||
{
|
|
||||||
// migrate to new naming convention for scripts
|
|
||||||
var migrateConfig = DeployChanges.To.SqlDatabase(NormalizeConnectionString(connectionString))
|
|
||||||
.WithScriptsEmbeddedInAssembly(Assembly.GetExecutingAssembly(), s => s == scriptType + ".00.00.00.00.sql");
|
|
||||||
var migrate = migrateConfig.Build();
|
|
||||||
if (migrate.IsUpgradeRequired())
|
|
||||||
{
|
|
||||||
migrate.PerformUpgrade();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
using Oqtane.Models;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Oqtane.Enums;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
public interface IInstallable
|
public interface IInstallable
|
||||||
{
|
{
|
||||||
bool Install(Tenant tenant, string version);
|
bool Install(Tenant tenant, string version);
|
||||||
|
|
||||||
bool Uninstall(Tenant tenant);
|
bool Uninstall(Tenant tenant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
Oqtane.Server/Infrastructure/Interfaces/IMigratable.cs
Normal file
10
Oqtane.Server/Infrastructure/Interfaces/IMigratable.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using Oqtane.Enums;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public interface IMigratable
|
||||||
|
{
|
||||||
|
bool Migrate(Tenant tenant, MigrationType migrationType);
|
||||||
|
}
|
||||||
|
}
|
@ -1,40 +1,64 @@
|
|||||||
using Oqtane.Infrastructure;
|
using System;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Modules.HtmlText.Models;
|
using Oqtane.Modules.HtmlText.Models;
|
||||||
using Oqtane.Modules.HtmlText.Repository;
|
using Oqtane.Modules.HtmlText.Repository;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Enums;
|
||||||
|
// ReSharper disable ConvertToUsingDeclaration
|
||||||
|
|
||||||
namespace Oqtane.Modules.HtmlText.Manager
|
namespace Oqtane.Modules.HtmlText.Manager
|
||||||
{
|
{
|
||||||
public class HtmlTextManager : IInstallable, IPortable
|
public class HtmlTextManager : IMigratable, IPortable
|
||||||
{
|
{
|
||||||
private IHtmlTextRepository _htmlTexts;
|
private readonly IHtmlTextRepository _htmlText;
|
||||||
private ISqlRepository _sql;
|
private readonly ISqlRepository _sql;
|
||||||
|
|
||||||
public HtmlTextManager(IHtmlTextRepository htmltexts, ISqlRepository sql)
|
public HtmlTextManager(IHtmlTextRepository htmlText, ISqlRepository sql)
|
||||||
{
|
{
|
||||||
_htmlTexts = htmltexts;
|
_htmlText = htmlText;
|
||||||
_sql = sql;
|
_sql = sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Install(Tenant tenant, string version)
|
public bool Migrate(Tenant tenant, MigrationType migrationType)
|
||||||
{
|
{
|
||||||
return _sql.ExecuteScript(tenant, GetType().Assembly, "HtmlText." + version + ".sql");
|
var result = true;
|
||||||
}
|
|
||||||
|
|
||||||
public bool Uninstall(Tenant tenant)
|
var dbConfig = new DbConfig(null, null) {ConnectionString = tenant.DBConnectionString};
|
||||||
{
|
using (var db = new HtmlTextContext(dbConfig, null))
|
||||||
return _sql.ExecuteScript(tenant, GetType().Assembly, "HtmlText.Uninstall.sql");
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var migrator = db.GetService<IMigrator>();
|
||||||
|
if (migrationType == MigrationType.Down)
|
||||||
|
{
|
||||||
|
migrator.Migrate(Migration.InitialDatabase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
migrator.Migrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ExportModule(Module module)
|
public string ExportModule(Module module)
|
||||||
{
|
{
|
||||||
string content = "";
|
string content = "";
|
||||||
HtmlTextInfo htmltext = _htmlTexts.GetHtmlText(module.ModuleId);
|
var htmlText = _htmlText.GetHtmlText(module.ModuleId);
|
||||||
if (htmltext != null)
|
if (htmlText != null)
|
||||||
{
|
{
|
||||||
content = WebUtility.HtmlEncode(htmltext.Content);
|
content = WebUtility.HtmlEncode(htmlText.Content);
|
||||||
}
|
}
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
@ -42,18 +66,18 @@ namespace Oqtane.Modules.HtmlText.Manager
|
|||||||
public void ImportModule(Module module, string content, string version)
|
public void ImportModule(Module module, string content, string version)
|
||||||
{
|
{
|
||||||
content = WebUtility.HtmlDecode(content);
|
content = WebUtility.HtmlDecode(content);
|
||||||
HtmlTextInfo htmltext = _htmlTexts.GetHtmlText(module.ModuleId);
|
var htmlText = _htmlText.GetHtmlText(module.ModuleId);
|
||||||
if (htmltext != null)
|
if (htmlText != null)
|
||||||
{
|
{
|
||||||
htmltext.Content = content;
|
htmlText.Content = content;
|
||||||
_htmlTexts.UpdateHtmlText(htmltext);
|
_htmlText.UpdateHtmlText(htmlText);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
htmltext = new HtmlTextInfo();
|
htmlText = new HtmlTextInfo();
|
||||||
htmltext.ModuleId = module.ModuleId;
|
htmlText.ModuleId = module.ModuleId;
|
||||||
htmltext.Content = content;
|
htmlText.Content = content;
|
||||||
_htmlTexts.AddHtmlText(htmltext);
|
_htmlText.AddHtmlText(htmlText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Modules.HtmlText.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Modules.HtmlText.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.HtmlText.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(HtmlTextContext))]
|
||||||
|
[Migration("HtmlText.01.00.00.00")]
|
||||||
|
public class InitializeModule : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
//Create HtmlText table
|
||||||
|
var entityBuilder = new HtmlTextEntityBuilder(migrationBuilder);
|
||||||
|
entityBuilder.Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
//Drop HtmlText table
|
||||||
|
var entityBuilder = new HtmlTextEntityBuilder(migrationBuilder);
|
||||||
|
entityBuilder.Drop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||||
|
using Oqtane.Migrations;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Migrations.Extensions;
|
||||||
|
|
||||||
|
// ReSharper disable MemberCanBePrivate.Global
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
|
namespace Oqtane.Modules.HtmlText.Migrations.EntityBuilders
|
||||||
|
{
|
||||||
|
public class HtmlTextEntityBuilder : AuditableBaseEntityBuilder<HtmlTextEntityBuilder>
|
||||||
|
{
|
||||||
|
private const string _entityTableName = "HtmlText";
|
||||||
|
private readonly PrimaryKey<HtmlTextEntityBuilder> _primaryKey = new("PK_HtmlText", x => x.HtmlTextId);
|
||||||
|
private readonly ForeignKey<HtmlTextEntityBuilder> _moduleForeignKey = new("FK_HtmlText_Module", x => x.ModuleId, "Module", "ModuleId", ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
public HtmlTextEntityBuilder(MigrationBuilder migrationBuilder) : base(migrationBuilder)
|
||||||
|
{
|
||||||
|
EntityTableName = _entityTableName;
|
||||||
|
PrimaryKey = _primaryKey;
|
||||||
|
ForeignKeys.Add(_moduleForeignKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override HtmlTextEntityBuilder BuildTable(ColumnsBuilder table)
|
||||||
|
{
|
||||||
|
HtmlTextId = table.AddAutoIncrementColumn("HtmlTextId");
|
||||||
|
ModuleId = table.AddIntegerColumn("ModuleId");
|
||||||
|
Content = table.AddMaxStringColumn("Content");
|
||||||
|
|
||||||
|
AddAuditableColumns(table);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> HtmlTextId { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> ModuleId { get; set; }
|
||||||
|
|
||||||
|
public OperationBuilder<AddColumnOperation> Content { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,7 @@ namespace Oqtane.Modules.HtmlText.Repository
|
|||||||
{
|
{
|
||||||
public virtual DbSet<HtmlTextInfo> HtmlText { get; set; }
|
public virtual DbSet<HtmlTextInfo> HtmlText { get; set; }
|
||||||
|
|
||||||
public HtmlTextContext(ITenantResolver tenantResolver, IHttpContextAccessor accessor, IConfiguration configuration) : base(tenantResolver, accessor, configuration)
|
public HtmlTextContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver)
|
||||||
{
|
{
|
||||||
// ContextBase handles multi-tenant database connections
|
// ContextBase handles multi-tenant database connections
|
||||||
}
|
}
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
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
|
|
@ -1,2 +0,0 @@
|
|||||||
DROP TABLE [dbo].[HtmlText]
|
|
||||||
GO
|
|
@ -20,6 +20,9 @@
|
|||||||
<Compile Remove="wwwroot\Modules\Templates\**" />
|
<Compile Remove="wwwroot\Modules\Templates\**" />
|
||||||
<Content Remove="wwwroot\Modules\Templates\**" />
|
<Content Remove="wwwroot\Modules\Templates\**" />
|
||||||
<EmbeddedResource Remove="wwwroot\Modules\Templates\**" />
|
<EmbeddedResource Remove="wwwroot\Modules\Templates\**" />
|
||||||
|
<Compile Remove="bin\**" />
|
||||||
|
<EmbeddedResource Remove="bin\**" />
|
||||||
|
<Content Remove="bin\**" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Scripts\Master.00.00.00.00.sql" />
|
<EmbeddedResource Include="Scripts\Master.00.00.00.00.sql" />
|
||||||
@ -36,14 +39,12 @@
|
|||||||
<EmbeddedResource Include="Scripts\Tenant.02.00.01.01.sql" />
|
<EmbeddedResource Include="Scripts\Tenant.02.00.01.01.sql" />
|
||||||
<EmbeddedResource Include="Scripts\Tenant.02.00.01.02.sql" />
|
<EmbeddedResource Include="Scripts\Tenant.02.00.01.02.sql" />
|
||||||
<EmbeddedResource Include="Scripts\Tenant.02.00.01.03.sql" />
|
<EmbeddedResource Include="Scripts\Tenant.02.00.01.03.sql" />
|
||||||
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.1.0.0.sql" />
|
|
||||||
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.Uninstall.sql" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="dbup" Version="4.4.0" />
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="5.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="5.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="2.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.4">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
@ -67,6 +68,9 @@
|
|||||||
<UpgradeFiles Include="$(ProjectDir)bin\Release\net5.0\Oqtane.Upgrade.runtimeconfig.json" />
|
<UpgradeFiles Include="$(ProjectDir)bin\Release\net5.0\Oqtane.Upgrade.runtimeconfig.json" />
|
||||||
<TemplateFiles Include="$(ProjectDir)wwwroot\Modules\Templates\**\*.*" />
|
<TemplateFiles Include="$(ProjectDir)wwwroot\Modules\Templates\**\*.*" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="bin\**" />
|
||||||
|
</ItemGroup>
|
||||||
<Target Name="AddPayloadsFolder" AfterTargets="Publish">
|
<Target Name="AddPayloadsFolder" AfterTargets="Publish">
|
||||||
<Copy SourceFiles="@(UpgradeFiles)" DestinationFiles="@(UpgradeFiles->'$(PublishDir)%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
<Copy SourceFiles="@(UpgradeFiles)" DestinationFiles="@(UpgradeFiles->'$(PublishDir)%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||||
<Copy SourceFiles="@(TemplateFiles)" DestinationFiles="@(TemplateFiles->'$(PublishDir)wwwroot\Modules\Templates\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
<Copy SourceFiles="@(TemplateFiles)" DestinationFiles="@(TemplateFiles->'$(PublishDir)wwwroot\Modules\Templates\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
|
||||||
|
@ -7,48 +7,56 @@ using Microsoft.EntityFrameworkCore;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class DBContextBase : IdentityUserContext<IdentityUser>
|
public class DBContextBase : IdentityUserContext<IdentityUser>
|
||||||
{
|
{
|
||||||
private ITenantResolver _tenantResolver;
|
private readonly IDbConfig _dbConfig;
|
||||||
private IHttpContextAccessor _accessor;
|
private readonly ITenantResolver _tenantResolver;
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
|
|
||||||
public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor accessor, IConfiguration configuration)
|
public DBContextBase(IDbConfig dbConfig, ITenantResolver tenantResolver)
|
||||||
{
|
{
|
||||||
|
_dbConfig = dbConfig;
|
||||||
_tenantResolver = tenantResolver;
|
_tenantResolver = tenantResolver;
|
||||||
_accessor = accessor;
|
|
||||||
_configuration = configuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
var tenant = _tenantResolver.GetTenant();
|
var connectionString = _dbConfig.ConnectionString;
|
||||||
if (tenant != null)
|
|
||||||
|
if (string.IsNullOrEmpty(connectionString) && _tenantResolver != null)
|
||||||
|
{
|
||||||
|
var tenant = _tenantResolver.GetTenant();
|
||||||
|
var configuration = _dbConfig.Configuration;
|
||||||
|
|
||||||
|
if (tenant != null)
|
||||||
|
{
|
||||||
|
connectionString = tenant.DBConnectionString
|
||||||
|
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(configuration.GetConnectionString("DefaultConnection")))
|
||||||
|
{
|
||||||
|
connectionString = configuration.GetConnectionString("DefaultConnection")
|
||||||
|
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(connectionString))
|
||||||
{
|
{
|
||||||
var connectionString = tenant.DBConnectionString
|
|
||||||
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
|
||||||
optionsBuilder.UseOqtaneDatabase(connectionString);
|
optionsBuilder.UseOqtaneDatabase(connectionString);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!String.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection")))
|
|
||||||
{
|
|
||||||
var connectionString = _configuration.GetConnectionString("DefaultConnection")
|
|
||||||
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
|
||||||
|
|
||||||
optionsBuilder.UseOqtaneDatabase(connectionString);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
base.OnConfiguring(optionsBuilder);
|
base.OnConfiguring(optionsBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int SaveChanges()
|
public override int SaveChanges()
|
||||||
{
|
{
|
||||||
DbContextUtils.SaveChanges(this, _accessor);
|
DbContextUtils.SaveChanges(this, _dbConfig.Accessor);
|
||||||
|
|
||||||
return base.SaveChanges();
|
return base.SaveChanges();
|
||||||
}
|
}
|
||||||
|
20
Oqtane.Server/Repository/Context/DbConfig.cs
Normal file
20
Oqtane.Server/Repository/Context/DbConfig.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Oqtane.Repository
|
||||||
|
{
|
||||||
|
public class DbConfig : IDbConfig
|
||||||
|
{
|
||||||
|
public DbConfig(IHttpContextAccessor accessor, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
Accessor = accessor;
|
||||||
|
Configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IHttpContextAccessor Accessor { get; }
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@ using Oqtane.Models;
|
|||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class DbContextUtils
|
public static class DbContextUtils
|
||||||
{
|
{
|
||||||
public static void SaveChanges(DbContext context, IHttpContextAccessor accessor)
|
public static void SaveChanges(DbContext context, IHttpContextAccessor accessor)
|
||||||
{
|
{
|
||||||
|
@ -22,5 +22,8 @@ namespace Oqtane.Repository
|
|||||||
public virtual DbSet<Tenant> Tenant { get; set; }
|
public virtual DbSet<Tenant> Tenant { get; set; }
|
||||||
public virtual DbSet<ModuleDefinition> ModuleDefinition { get; set; }
|
public virtual DbSet<ModuleDefinition> ModuleDefinition { get; set; }
|
||||||
public virtual DbSet<Job> Job { get; set; }
|
public virtual DbSet<Job> Job { get; set; }
|
||||||
|
public virtual DbSet<JobLog> JobLog { get; set; }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,42 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
|
|
||||||
|
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
||||||
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
// ReSharper disable CheckNamespace
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class MasterDBContext : DbContext
|
public class MasterDBContext : DbContext
|
||||||
{
|
{
|
||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IDbConfig _dbConfig;
|
||||||
private readonly IConfiguration _configuration;
|
|
||||||
|
|
||||||
public MasterDBContext(DbContextOptions<MasterDBContext> options, IHttpContextAccessor accessor, IConfiguration configuration) : base(options)
|
public MasterDBContext(DbContextOptions<MasterDBContext> options, IDbConfig dbConfig) : base(options)
|
||||||
{
|
{
|
||||||
_accessor = accessor;
|
_dbConfig = dbConfig;
|
||||||
_configuration = configuration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrEmpty(_configuration.GetConnectionString("DefaultConnection")))
|
var connectionString = _dbConfig.ConnectionString;
|
||||||
{
|
var configuration = _dbConfig.Configuration;
|
||||||
var connectionString = _configuration.GetConnectionString("DefaultConnection")
|
|
||||||
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
|
||||||
|
|
||||||
|
if(string.IsNullOrEmpty(connectionString) && configuration != null)
|
||||||
|
{
|
||||||
|
if (!String.IsNullOrEmpty(configuration.GetConnectionString("DefaultConnection")))
|
||||||
|
{
|
||||||
|
connectionString = configuration.GetConnectionString("DefaultConnection")
|
||||||
|
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(connectionString))
|
||||||
|
{
|
||||||
optionsBuilder.UseOqtaneDatabase(connectionString);
|
optionsBuilder.UseOqtaneDatabase(connectionString);
|
||||||
}
|
}
|
||||||
base.OnConfiguring(optionsBuilder);
|
base.OnConfiguring(optionsBuilder);
|
||||||
@ -39,7 +50,7 @@ namespace Oqtane.Repository
|
|||||||
|
|
||||||
public override int SaveChanges()
|
public override int SaveChanges()
|
||||||
{
|
{
|
||||||
DbContextUtils.SaveChanges(this, _accessor);
|
DbContextUtils.SaveChanges(this, _dbConfig.Accessor);
|
||||||
|
|
||||||
return base.SaveChanges();
|
return base.SaveChanges();
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace Oqtane.Repository
|
|||||||
|
|
||||||
public virtual DbSet<Language> Language { get; set; }
|
public virtual DbSet<Language> Language { get; set; }
|
||||||
|
|
||||||
public TenantDBContext(ITenantResolver tenantResolver, IHttpContextAccessor accessor, IConfiguration configuration) : base(tenantResolver, accessor, configuration)
|
public TenantDBContext(IDbConfig dbConfig, ITenantResolver tenantResolver) : base(dbConfig, tenantResolver)
|
||||||
{
|
{
|
||||||
// DBContextBase handles multi-tenant database connections
|
// DBContextBase handles multi-tenant database connections
|
||||||
}
|
}
|
||||||
|
14
Oqtane.Server/Repository/Interfaces/IDbConfig.cs
Normal file
14
Oqtane.Server/Repository/Interfaces/IDbConfig.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Oqtane.Repository
|
||||||
|
{
|
||||||
|
public interface IDbConfig
|
||||||
|
{
|
||||||
|
public IHttpContextAccessor Accessor { get; }
|
||||||
|
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
using System.Data.SqlClient;
|
using System.Reflection;
|
||||||
using System.Reflection;
|
using Microsoft.Data.SqlClient;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.SqlClient;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Microsoft.Data.SqlClient;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
@ -59,8 +59,8 @@ namespace Oqtane.Repository
|
|||||||
|
|
||||||
public int ExecuteNonQuery(Tenant tenant, string query)
|
public int ExecuteNonQuery(Tenant tenant, string query)
|
||||||
{
|
{
|
||||||
SqlConnection conn = new SqlConnection(FormatConnectionString(tenant.DBConnectionString));
|
var conn = new SqlConnection(FormatConnectionString(tenant.DBConnectionString));
|
||||||
SqlCommand cmd = conn.CreateCommand();
|
var cmd = conn.CreateCommand();
|
||||||
using (conn)
|
using (conn)
|
||||||
{
|
{
|
||||||
PrepareCommand(conn, cmd, query);
|
PrepareCommand(conn, cmd, query);
|
||||||
|
@ -130,6 +130,7 @@ namespace Oqtane
|
|||||||
|
|
||||||
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||||
|
|
||||||
|
services.AddScoped<IDbConfig, DbConfig>();
|
||||||
services.AddDbContext<MasterDBContext>(options => { });
|
services.AddDbContext<MasterDBContext>(options => { });
|
||||||
services.AddDbContext<TenantDBContext>(options => { });
|
services.AddDbContext<TenantDBContext>(options => { });
|
||||||
|
|
||||||
@ -211,7 +212,7 @@ namespace Oqtane
|
|||||||
services.AddTransient<IUpgradeManager, UpgradeManager>();
|
services.AddTransient<IUpgradeManager, UpgradeManager>();
|
||||||
services.AddTransient<ILanguageRepository, LanguageRepository>();
|
services.AddTransient<ILanguageRepository, LanguageRepository>();
|
||||||
|
|
||||||
// load the external assemblies into the app domain, install services
|
// load the external assemblies into the app domain, install services
|
||||||
services.AddOqtane(_runtime, _supportedCultures);
|
services.AddOqtane(_runtime, _supportedCultures);
|
||||||
|
|
||||||
services.AddMvc()
|
services.AddMvc()
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"Database": {
|
||||||
|
"DatabaseType": "",
|
||||||
|
"DatabaseEngineVersion": ""
|
||||||
|
},
|
||||||
"ConnectionStrings": {
|
"ConnectionStrings": {
|
||||||
"DefaultConnection": ""
|
"DefaultConnection": "Data Source=.;Initial Catalog=Oqtane-Migrations;Integrated Security=SSPI;"
|
||||||
},
|
},
|
||||||
"Runtime": "Server",
|
"Runtime": "Server",
|
||||||
"Installation": {
|
"Installation": {
|
||||||
|
1
Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.css
Normal file
1
Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.css
Normal file
@ -0,0 +1 @@
|
|||||||
|
/* Module Custom Styles */
|
1
Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.js
Normal file
1
Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/Module.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
/* Module Script */
|
1
Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/assets.json
Normal file
1
Oqtane.Server/wwwroot/Modules/Oqtane.Blogs/assets.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
["\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Client.Oqtane.pdb","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Server.Oqtane.pdb","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.dll","\\bin\\Debug\\net5.0\\Oqtane.Blogs.Shared.Oqtane.pdb","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.css","\\wwwroot\\Modules\\Oqtane.Blogs\\Module.js"]
|
8
Oqtane.Shared/Enums/MigrationType.cs
Normal file
8
Oqtane.Shared/Enums/MigrationType.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Oqtane.Enums
|
||||||
|
{
|
||||||
|
public enum MigrationType
|
||||||
|
{
|
||||||
|
Up,
|
||||||
|
Down
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user