Updated the Installation of Oqtane to use Migrations
This commit is contained in:
@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using DbUp;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
@ -18,6 +15,11 @@ using Oqtane.Shared;
|
||||
using Oqtane.Enums;
|
||||
using File = System.IO.File;
|
||||
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable ConvertToUsingDeclaration
|
||||
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
||||
// ReSharper disable UseIndexFromEndExpression
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class DatabaseManager : IDatabaseManager
|
||||
@ -166,7 +168,7 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
//create data directory if does not exist
|
||||
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);
|
||||
using (var dbc = new DbContext(new DbContextOptionsBuilder().UseOqtaneDatabase(connectionString).Options))
|
||||
@ -195,26 +197,20 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
if (install.TenantName == TenantNames.Master)
|
||||
{
|
||||
MigrateScriptNamingConvention("Master", install.ConnectionString);
|
||||
|
||||
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())
|
||||
try
|
||||
{
|
||||
var upgradeResult = upgrade.PerformUpgrade();
|
||||
result.Success = upgradeResult.Successful;
|
||||
if (!result.Success)
|
||||
var dbConfig = new DbConfig(null, null) {ConnectionString = install.ConnectionString};
|
||||
|
||||
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)
|
||||
@ -251,10 +247,14 @@ namespace Oqtane.Infrastructure
|
||||
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 };
|
||||
db.Alias.Add(alias);
|
||||
if (tenant != null)
|
||||
{
|
||||
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();
|
||||
}
|
||||
_cache.Remove("aliases");
|
||||
@ -270,7 +270,7 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
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())
|
||||
{
|
||||
@ -280,29 +280,28 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
foreach (var tenant in db.Tenant.ToList())
|
||||
{
|
||||
MigrateScriptNamingConvention("Tenant", tenant.DBConnectionString);
|
||||
|
||||
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())
|
||||
try
|
||||
{
|
||||
var upgradeResult = upgrade.PerformUpgrade();
|
||||
result.Success = upgradeResult.Successful;
|
||||
if (!result.Success)
|
||||
var dbConfig = new DbConfig(null, null) {ConnectionString = install.ConnectionString};
|
||||
using (var tenantDbContext = new TenantDBContext(dbConfig, null))
|
||||
{
|
||||
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
|
||||
string version = tenant.Version;
|
||||
int index = Array.FindIndex(versions, item => item == version);
|
||||
var version = tenant.Version;
|
||||
var index = Array.FindIndex(versions, item => item == version);
|
||||
if (index != (versions.Length - 1))
|
||||
{
|
||||
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]);
|
||||
}
|
||||
@ -328,53 +327,61 @@ namespace Oqtane.Infrastructure
|
||||
|
||||
using (var scope = _serviceScopeFactory.CreateScope())
|
||||
{
|
||||
var moduledefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
|
||||
var moduleDefinitions = scope.ServiceProvider.GetRequiredService<IModuleDefinitionRepository>();
|
||||
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);
|
||||
if (moduletype != null)
|
||||
var moduleType = Type.GetType(moduleDefinition.ServerManagerType);
|
||||
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))))
|
||||
{
|
||||
foreach (var tenant in db.Tenant.ToList())
|
||||
{
|
||||
int index = Array.FindIndex(versions, item => item == moduledefinition.Version);
|
||||
if (tenant.Name == install.TenantName && install.TenantName != TenantNames.Master)
|
||||
if (moduleType.GetInterface("IMigratable") != null)
|
||||
{
|
||||
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;
|
||||
for (int i = index; i < versions.Length; i++)
|
||||
var index = Array.FindIndex(versions, item => item == moduleDefinition.Version);
|
||||
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);
|
||||
((IInstallable)moduleobject).Install(tenant, versions[i]);
|
||||
if (moduleType.GetInterface("IInstallable") != null)
|
||||
{
|
||||
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];
|
||||
db.Entry(moduledefinition).State = EntityState.Modified;
|
||||
moduleDefinition.Version = versions[versions.Length - 1];
|
||||
db.Entry(moduleDefinition).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
@ -401,8 +408,8 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
// use the SiteState to set the Alias explicitly so the tenant can be resolved
|
||||
var aliases = scope.ServiceProvider.GetRequiredService<IAliasRepository>();
|
||||
string firstalias = install.Aliases.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||
var alias = aliases.GetAliases().FirstOrDefault(item => item.Name == firstalias);
|
||||
var firstAlias = install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0];
|
||||
var alias = aliases.GetAliases().FirstOrDefault(item => item.Name == firstAlias);
|
||||
var siteState = scope.ServiceProvider.GetRequiredService<SiteState>();
|
||||
siteState.Alias = alias;
|
||||
|
||||
@ -413,82 +420,88 @@ namespace Oqtane.Infrastructure
|
||||
var tenants = scope.ServiceProvider.GetRequiredService<ITenantRepository>();
|
||||
var users = scope.ServiceProvider.GetRequiredService<IUserRepository>();
|
||||
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 log = scope.ServiceProvider.GetRequiredService<ILogManager>();
|
||||
var identityUserManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
|
||||
|
||||
var tenant = tenants.GetTenants().FirstOrDefault(item => item.Name == install.TenantName);
|
||||
|
||||
site = new Site
|
||||
if (tenant != null)
|
||||
{
|
||||
TenantId = tenant.TenantId,
|
||||
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)
|
||||
site = new Site
|
||||
{
|
||||
var user = new User
|
||||
{
|
||||
SiteId = site.SiteId,
|
||||
Username = UserNames.Host,
|
||||
Password = install.HostPassword,
|
||||
Email = install.HostEmail,
|
||||
DisplayName = install.HostName,
|
||||
LastIPAddress = "",
|
||||
LastLoginOn = null
|
||||
};
|
||||
TenantId = tenant.TenantId,
|
||||
Name = install.SiteName,
|
||||
LogoFileId = null,
|
||||
DefaultThemeType = install.DefaultTheme,
|
||||
DefaultLayoutType = install.DefaultLayout,
|
||||
DefaultContainerType = install.DefaultContainer,
|
||||
SiteTemplateType = install.SiteTemplate
|
||||
};
|
||||
site = sites.AddSite(site);
|
||||
|
||||
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)
|
||||
var 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)
|
||||
{
|
||||
folders.AddFolder(new Folder
|
||||
var user = new User
|
||||
{
|
||||
SiteId = folder.SiteId,
|
||||
ParentId = folder.FolderId,
|
||||
Name = "My Folder",
|
||||
Path = Utilities.PathCombine(folder.Path, user.UserId.ToString(), Path.DirectorySeparatorChar.ToString()),
|
||||
Order = 1,
|
||||
IsSystem = true,
|
||||
Permissions = new List<Permission>
|
||||
SiteId = site.SiteId,
|
||||
Username = UserNames.Host,
|
||||
Password = install.HostPassword,
|
||||
Email = install.HostEmail,
|
||||
DisplayName = install.HostName,
|
||||
LastIPAddress = "",
|
||||
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),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, user.UserId, true),
|
||||
}.EncodePermissions(),
|
||||
});
|
||||
SiteId = folder.SiteId,
|
||||
ParentId = folder.FolderId,
|
||||
Name = "My Folder",
|
||||
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))
|
||||
{
|
||||
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);
|
||||
if (site != null) 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)
|
||||
{
|
||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
||||
connectionString = connectionString.Replace(dataDirectory, "|DataDirectory|");
|
||||
connectionString = connectionString.Replace(dataDirectory ?? String.Empty, "|DataDirectory|");
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
@ -567,18 +580,5 @@ namespace Oqtane.Infrastructure
|
||||
if (string.IsNullOrEmpty(value)) value = defaultValue;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user