Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

automate the 2.1.0 upgrade #1406

Merged
merged 1 commit into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Oqtane.Client/Installer/Installer.razor
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -174,7 +174,6 @@
var config = new InstallConfig
{
DatabaseType = database.DBType,
DatabasePackage = database.Package,
ConnectionString = connectionString,
Aliases = uri.Authority,
HostEmail = _hostEmail,
Expand Down
3 changes: 1 addition & 2 deletions Oqtane.Client/Modules/Admin/Sites/Add.razor
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion Oqtane.Client/Services/DatabaseService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public DatabaseService(HttpClient http, SiteState siteState) : base(http)
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();
}
}
}
2 changes: 0 additions & 2 deletions Oqtane.Server/Extensions/DbContextOptionsBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -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
Expand Down
102 changes: 102 additions & 0 deletions Oqtane.Server/Infrastructure/ConfigManager.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
84 changes: 31 additions & 53 deletions Oqtane.Server/Infrastructure/DatabaseManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
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
Expand All @@ -32,18 +31,23 @@ public class DatabaseManager : IDatabaseManager
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;
Expand Down Expand Up @@ -97,7 +101,6 @@ public Installation Install(InstallConfig install)
if (string.IsNullOrEmpty(install.DatabaseType))
{
install.DatabaseType = Constants.DefaultDBType;
install.DatabasePackage = Constants.DefaultDBType.Substring(Constants.DefaultDBType.IndexOf(",") + 2);
InstallDatabase(install);
UpdateDatabaseType(install.DatabaseType);
}
Expand All @@ -106,7 +109,6 @@ public Installation Install(InstallConfig install)
// 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);
}
}
Expand Down Expand Up @@ -220,7 +222,7 @@ private Installation InstallDatabase(InstallConfig install)
// 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);
Expand All @@ -237,7 +239,7 @@ private Installation InstallDatabase(InstallConfig install)

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);

Expand Down Expand Up @@ -644,25 +646,6 @@ private Installation CreateSite(InstallConfig install)
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();
Expand All @@ -687,10 +670,7 @@ private InstallationContext GetInstallationContext()

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)
Expand All @@ -700,39 +680,18 @@ private string NormalizeConnectionString(string connectionString)
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)
Expand All @@ -744,5 +703,24 @@ public void UpgradeSqlServer(ISqlRepository sql, string connectionString, string

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);
}
}
}
}
15 changes: 15 additions & 0 deletions Oqtane.Server/Infrastructure/Interfaces/IConfigManager.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}
8 changes: 5 additions & 3 deletions Oqtane.Server/Infrastructure/UpgradeManager.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion Oqtane.Server/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void ConfigureServices(IServiceCollection services)
// 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 =>
{
Expand Down Expand Up @@ -176,6 +176,7 @@ public void ConfigureServices(IServiceCollection services)
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);
Expand Down
Loading