Merge pull request #1406 from sbwalker/dev

automate the 2.1.0 upgrade
This commit is contained in:
Shaun Walker 2021-05-27 16:15:02 -04:00 committed by GitHub
commit 6c8703356f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 160 additions and 75 deletions

View File

@ -31,7 +31,7 @@
{
foreach (var database in _databases)
{
<option value="@database.Name">@Localizer[@database.FriendlyName]</option>
<option value="@database.Name">@Localizer[@database.Name]</option>
}
}
</select>
@ -174,7 +174,6 @@
var config = new InstallConfig
{
DatabaseType = database.DBType,
DatabasePackage = database.Package,
ConnectionString = connectionString,
Aliases = uri.Authority,
HostEmail = _hostEmail,

View File

@ -130,7 +130,7 @@ else
<select id="databaseType" class="custom-select" value="@_databaseName" @onchange="(e => DatabaseChanged(e))">
@foreach (var database in _databases)
{
<option value="@database.Name">@Localizer[@database.FriendlyName]</option>
<option value="@database.Name">@Localizer[@database.Name]</option>
}
</select>
</td>
@ -305,7 +305,6 @@ else
{
config.TenantName = _tenantName;
config.DatabaseType = database.DBType;
config.DatabasePackage = database.Package;
config.ConnectionString = connectionString;
config.HostEmail = user.Email;
config.HostPassword = _hostpassword;

View File

@ -24,7 +24,7 @@ namespace Oqtane.Services
public async Task<List<Database>> GetDatabasesAsync()
{
List<Database> databases = await GetJsonAsync<List<Database>>(Apiurl);
return databases.OrderBy(item => item.FriendlyName).ToList();
return databases.OrderBy(item => item.Name).ToList();
}
}
}

View File

@ -1,8 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.EntityFrameworkCore;
using Oqtane.Databases.Interfaces;
using Oqtane.Interfaces;
// ReSharper disable ConvertToUsingDeclaration
namespace Oqtane.Extensions

View File

@ -0,0 +1,102 @@
using System;
using System.IO;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Oqtane.Infrastructure
{
public class ConfigManager : IConfigManager
{
private readonly IConfigurationRoot _config;
public ConfigManager(IConfigurationRoot config)
{
_config = config;
}
public IConfigurationSection GetSection(string key)
{
return _config.GetSection(key);
}
public string GetSetting(string sectionKey, string settingKey, string defaultValue)
{
var value = _config.GetSection(sectionKey).GetValue(settingKey, defaultValue);
if (string.IsNullOrEmpty(value)) value = defaultValue;
return value;
}
public void AddOrUpdateSetting<T>(string key, T value, bool reload)
{
AddOrUpdateSetting("appsettings.json", key, value, reload);
}
public void AddOrUpdateSetting<T>(string file, string key, T value, bool reload)
{
try
{
var path = Path.Combine(Directory.GetCurrentDirectory(), file);
dynamic jsonObj = JsonConvert.DeserializeObject(File.ReadAllText(path));
SetValueRecursively(key, jsonObj, value, "set");
File.WriteAllText(path, JsonConvert.SerializeObject(jsonObj, Formatting.Indented));
if (reload) Reload();
}
catch (Exception ex)
{
Console.WriteLine("Error modifying app settings {0}", ex);
}
}
public void RemoveSetting(string key, bool reload)
{
RemoveSetting("appsettings.json", key, reload);
}
public void RemoveSetting(string file, string key, bool reload)
{
try
{
var path = Path.Combine(Directory.GetCurrentDirectory(), file);
dynamic jsonObj = JsonConvert.DeserializeObject(File.ReadAllText(path));
SetValueRecursively(key, jsonObj, "", "remove");
File.WriteAllText(path, JsonConvert.SerializeObject(jsonObj, Formatting.Indented));
if (reload) Reload();
}
catch (Exception ex)
{
Console.WriteLine("Error modifying app settings {0}", ex);
}
}
private void SetValueRecursively<T>(string key, dynamic jsonObj, T value, string action)
{
var remainingSections = key.Split(":", 2);
var currentSection = remainingSections[0];
if (remainingSections.Length > 1)
{
var nextSection = remainingSections[1];
jsonObj[currentSection] ??= new JObject();
SetValueRecursively(nextSection, jsonObj[currentSection], value, action);
}
else
{
switch (action)
{
case "set":
jsonObj[currentSection] = value;
break;
case "remove":
jsonObj.Property(currentSection).Remove();
break;
}
}
}
public void Reload()
{
_config.Reload();
}
}
}

View File

@ -10,14 +10,13 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Oqtane.Databases.Interfaces;
using Oqtane.Extensions;
using Oqtane.Models;
using Oqtane.Repository;
using Oqtane.Shared;
using Oqtane.Enums;
using File = System.IO.File;
using Newtonsoft.Json;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable ConvertToUsingDeclaration
@ -32,18 +31,23 @@ namespace Oqtane.Infrastructure
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IWebHostEnvironment _environment;
private readonly IMemoryCache _cache;
private readonly IConfigManager _configManager;
public DatabaseManager(IConfigurationRoot config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache)
public DatabaseManager(IConfigurationRoot config, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IMemoryCache cache, IConfigManager configManager)
{
_config = config;
_serviceScopeFactory = serviceScopeFactory;
_environment = environment;
_cache = cache;
_configManager = configManager;
}
public Installation IsInstalled()
{
var result = new Installation { Success = false, Message = string.Empty };
ValidateConfiguration();
if (!string.IsNullOrEmpty(_config.GetConnectionString(SettingKeys.ConnectionStringKey)))
{
result.Success = true;
@ -97,7 +101,6 @@ namespace Oqtane.Infrastructure
if (string.IsNullOrEmpty(install.DatabaseType))
{
install.DatabaseType = Constants.DefaultDBType;
install.DatabasePackage = Constants.DefaultDBType.Substring(Constants.DefaultDBType.IndexOf(",") + 2);
InstallDatabase(install);
UpdateDatabaseType(install.DatabaseType);
}
@ -106,7 +109,6 @@ namespace Oqtane.Infrastructure
// if database type does not exist, install the associated Nuget package
if (Type.GetType(install.DatabaseType) == null)
{
install.DatabasePackage = install.DatabaseType.Substring(install.DatabaseType.IndexOf(",") + 2);
InstallDatabase(install);
}
}
@ -220,7 +222,7 @@ namespace Oqtane.Infrastructure
// iterate through Nuget packages in source folder
foreach (var package in packagesFolder.GetFiles("*.nupkg.bak"))
{
if (package.Name.StartsWith(install.DatabasePackage))
if (package.Name.StartsWith(Utilities.GetAssemblyName(install.DatabaseType)))
{
//rename file
var packageName = Path.Combine(package.DirectoryName, package.Name);
@ -237,7 +239,7 @@ namespace Oqtane.Infrastructure
var assemblyPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
var assembliesFolder = new DirectoryInfo(assemblyPath);
var assemblyFile = new FileInfo($"{assembliesFolder}/{install.DatabasePackage}.dll");
var assemblyFile = new FileInfo($"{assembliesFolder}/{Utilities.GetAssemblyName(install.DatabaseType)}.dll");
AssemblyLoadContext.Default.LoadOqtaneAssembly(assemblyFile);
@ -644,25 +646,6 @@ namespace Oqtane.Infrastructure
return result;
}
public void AddOrUpdateAppSetting<T>(string sectionPathKey, T value)
{
try
{
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "appsettings.json");
var json = File.ReadAllText(filePath);
dynamic jsonObj = JsonConvert.DeserializeObject(json);
SetValueRecursively(sectionPathKey, jsonObj, value);
string output = JsonConvert.SerializeObject(jsonObj, Formatting.Indented);
File.WriteAllText(filePath, output);
}
catch (Exception ex)
{
Console.WriteLine("Error writing app settings | {0}", ex);
}
}
private string DenormalizeConnectionString(string connectionString)
{
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
@ -687,10 +670,7 @@ namespace Oqtane.Infrastructure
private string GetInstallationConfig(string key, string defaultValue)
{
var value = _config.GetSection(SettingKeys.InstallationSection).GetValue(key, defaultValue);
// double fallback to default value - allow hold sample keys in config
if (string.IsNullOrEmpty(value)) value = defaultValue;
return value;
return _configManager.GetSetting(SettingKeys.InstallationSection, key, defaultValue);
}
private string NormalizeConnectionString(string connectionString)
@ -700,39 +680,18 @@ namespace Oqtane.Infrastructure
return connectionString;
}
private void SetValueRecursively<T>(string sectionPathKey, dynamic jsonObj, T value)
{
// split the string at the first ':' character
var remainingSections = sectionPathKey.Split(":", 2);
var currentSection = remainingSections[0];
if (remainingSections.Length > 1)
{
// continue with the process, moving down the tree
var nextSection = remainingSections[1];
SetValueRecursively(nextSection, jsonObj[currentSection], value);
}
else
{
// we've got to the end of the tree, set the value
jsonObj[currentSection] = value;
}
}
public void UpdateConnectionString(string connectionString)
{
connectionString = DenormalizeConnectionString(connectionString);
if (_config.GetConnectionString(SettingKeys.ConnectionStringKey) != connectionString)
{
AddOrUpdateAppSetting($"{SettingKeys.ConnectionStringsSection}:{SettingKeys.ConnectionStringKey}", connectionString);
_config.Reload();
_configManager.AddOrUpdateSetting($"{SettingKeys.ConnectionStringsSection}:{SettingKeys.ConnectionStringKey}", connectionString, true);
}
}
public void UpdateDatabaseType(string databaseType)
{
AddOrUpdateAppSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType);
_config.Reload();
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType, true);
}
public void UpgradeSqlServer(ISqlRepository sql, string connectionString, string databaseType, bool isMaster)
@ -744,5 +703,24 @@ namespace Oqtane.Infrastructure
sql.ExecuteNonQuery(connectionString, databaseType, query);
}
private void ValidateConfiguration()
{
if (_configManager.GetSetting(SettingKeys.DatabaseSection, SettingKeys.DatabaseTypeKey, "") == "")
{
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", Constants.DefaultDBType, true);
}
if (!_configManager.GetSection(SettingKeys.AvailableDatabasesSection).Exists())
{
string databases = "[";
databases += "{ \"Name\": \"LocalDB\", \"ControlType\": \"Oqtane.Installer.Controls.LocalDBConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
databases += "{ \"Name\": \"SQL Server\", \"ControlType\": \"Oqtane.Installer.Controls.SqlServerConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer\" },";
databases += "{ \"Name\": \"SQLite\", \"ControlType\": \"Oqtane.Installer.Controls.SqliteConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.Sqlite.SqliteDatabase, Oqtane.Database.Sqlite\" },";
databases += "{ \"Name\": \"MySQL\", \"ControlType\": \"Oqtane.Installer.Controls.MySQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.MySQL.SqlServerDatabase, Oqtane.Database.MySQL\" },";
databases += "{ \"Name\": \"PostgreSQL\", \"ControlType\": \"Oqtane.Installer.Controls.PostgreSQLConfig, Oqtane.Client\", \"DBTYpe\": \"Oqtane.Database.PostgreSQL.PostgreSQLDatabase, Oqtane.Database.PostgreSQL\" }";
databases += "]";
_configManager.AddOrUpdateSetting(SettingKeys.AvailableDatabasesSection, JsonConvert.DeserializeObject<dynamic>(databases), true);
}
}
}
}

View File

@ -0,0 +1,15 @@
using Microsoft.Extensions.Configuration;
namespace Oqtane.Infrastructure
{
public interface IConfigManager
{
public IConfigurationSection GetSection(string sectionKey);
public string GetSetting(string sectionKey, string settingKey, string defaultValue);
void AddOrUpdateSetting<T>(string key, T value, bool reload);
void AddOrUpdateSetting<T>(string file, string key, T value, bool reload);
void RemoveSetting(string key, bool reload);
void RemoveSetting(string file, string key, bool reload);
void Reload();
}
}

View File

@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Oqtane.Models;
using Oqtane.Repository;
using Oqtane.Shared;
@ -11,15 +13,15 @@ namespace Oqtane.Infrastructure
{
public class UpgradeManager : IUpgradeManager
{
private readonly IAliasRepository _aliases;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IWebHostEnvironment _environment;
private readonly IConfigManager _configManager;
public UpgradeManager(IAliasRepository aliases, IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment)
public UpgradeManager(IServiceScopeFactory serviceScopeFactory, IWebHostEnvironment environment, IConfigManager configManager)
{
_aliases = aliases;
_serviceScopeFactory = serviceScopeFactory;
_environment = environment;
_configManager = configManager;
}
public void Upgrade(Tenant tenant, string version)

View File

@ -58,7 +58,7 @@ namespace Oqtane
// Register localization services
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddOptions<List<Database>>().Bind(Configuration.GetSection("AvailableDatabases"));
services.AddOptions<List<Database>>().Bind(Configuration.GetSection(SettingKeys.AvailableDatabasesSection));
services.AddServerSideBlazor().AddCircuitOptions(options =>
{
@ -176,6 +176,7 @@ namespace Oqtane
services.AddSingleton<IInstallationManager, InstallationManager>();
services.AddSingleton<ISyncManager, SyncManager>();
services.AddSingleton<IDatabaseManager, DatabaseManager>();
services.AddSingleton<IConfigManager, ConfigManager>();
// install any modules or themes ( this needs to occur BEFORE the assemblies are loaded into the app domain )
InstallationManager.InstallPackages(_env.WebRootPath, _env.ContentRootPath);

View File

@ -5,11 +5,6 @@ namespace Oqtane.Models
/// </summary>
public class Database
{
/// <summary>
/// Friendly name for the Admin to identify the DB
/// </summary>
public string FriendlyName { get; set; }
/// <summary>
/// Name of the Database
/// </summary>
@ -24,10 +19,5 @@ namespace Oqtane.Models
/// Type of DB using the full namespace, like `Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer`
/// </summary>
public string DBType { get; set; }
/// <summary>
/// Software package responsible for using this DB - like `Oqtane.Database.MySQL`
/// </summary>
public string Package { get; set; }
}
}

View File

@ -5,7 +5,6 @@ namespace Oqtane.Shared
{
public string ConnectionString { get; set; }
public string DatabaseType { get; set; }
public string DatabasePackage { get; set; }
public string Aliases { get; set; }
public string TenantName { get; set; }
public bool IsNewTenant { get; set; }

View File

@ -16,5 +16,7 @@ namespace Oqtane.Shared
public const string DefaultThemeKey = "DefaultTheme";
public const string DefaultLayoutKey = "DefaultLayout";
public const string DefaultContainerKey = "DefaultContainer";
public const string AvailableDatabasesSection = "AvailableDatabases";
}
}