fix #2567 - migrate tenant connection string details from database to appsettings.json
This commit is contained in:
parent
71dd00da0f
commit
f2df8e96db
|
@ -55,7 +55,7 @@
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">String:</Label>
|
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -267,16 +267,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="TenantInformation" Heading="Tenant Information" ResourceKey="TenantInformation">
|
<Section Name="TenantInformation" Heading="Database" ResourceKey="TenantInformation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="The tenant for the site" ResourceKey="Tenant">Tenant: </Label>
|
<Label Class="col-sm-3" For="tenant" HelpText="The name of the database used for the site" ResourceKey="Tenant">Database: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="database" HelpText="The database for the tenant" ResourceKey="Database">Database: </Label>
|
<Label Class="col-sm-3" For="database" HelpText="The type of database" ResourceKey="Database">Type: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="database" class="form-control" @bind="@_database" readonly />
|
<input id="database" class="form-control" @bind="@_database" readonly />
|
||||||
</div>
|
</div>
|
||||||
|
@ -284,10 +284,7 @@
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection information for the database" ResourceKey="ConnectionString">Connection: </Label>
|
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection information for the database" ResourceKey="ConnectionString">Connection: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<div class="input-group">
|
<input id="connectionstring" class="form-control" @bind="@_connectionstring" readonly />
|
||||||
<input id="connectionstring" type="@_connectionstringtype" class="form-control" @bind="@_connectionstring" readonly />
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleConnectionString">@_connectionstringtoggle</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -342,8 +339,6 @@
|
||||||
private string _tenant = string.Empty;
|
private string _tenant = string.Empty;
|
||||||
private string _database = string.Empty;
|
private string _database = string.Empty;
|
||||||
private string _connectionstring = string.Empty;
|
private string _connectionstring = string.Empty;
|
||||||
private string _connectionstringtype = "password";
|
|
||||||
private string _connectionstringtoggle = string.Empty;
|
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
private string _modifiedby;
|
private string _modifiedby;
|
||||||
|
@ -358,7 +353,6 @@
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
|
||||||
_themeList = await ThemeService.GetThemesAsync();
|
_themeList = await ThemeService.GetThemesAsync();
|
||||||
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
|
||||||
if (site != null)
|
if (site != null)
|
||||||
|
@ -466,20 +460,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleConnectionString()
|
|
||||||
{
|
|
||||||
if (_connectionstringtype == "password")
|
|
||||||
{
|
|
||||||
_connectionstringtype = "text";
|
|
||||||
_connectionstringtoggle = SharedLocalizer["HidePassword"];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_connectionstringtype = "password";
|
|
||||||
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SaveSite()
|
private async Task SaveSite()
|
||||||
{
|
{
|
||||||
validated = true;
|
validated = true;
|
||||||
|
|
|
@ -103,7 +103,7 @@ else
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="Select the tenant for the site" ResourceKey="Tenant">Tenant: </Label>
|
<Label Class="col-sm-3" For="tenant" HelpText="Select the database for the site" ResourceKey="Tenant">Database: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<select id="tenant" class="form-select" @onchange="(e => TenantChanged(e))" required>
|
<select id="tenant" class="form-select" @onchange="(e => TenantChanged(e))" required>
|
||||||
<option value="-"><@Localizer["Tenant.Select"]></option>
|
<option value="-"><@Localizer["Tenant.Select"]></option>
|
||||||
|
@ -121,13 +121,13 @@ else
|
||||||
<hr class="app-rule" />
|
<hr class="app-rule" />
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="name" HelpText="Enter the name for the tenant" ResourceKey="TenantName">Tenant Name: </Label>
|
<Label Class="col-sm-3" For="name" HelpText="Enter the name for the database" ResourceKey="TenantName">Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="name" class="form-control" @bind="@_tenantName" maxlength="100" required />
|
<input id="name" class="form-control" @bind="@_tenantName" maxlength="100" required />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="databaseType" HelpText="Select the database type for the tenant" ResourceKey="DatabaseType">Database Type: </Label>
|
<Label Class="col-sm-3" For="databaseType" HelpText="Select the database type" ResourceKey="DatabaseType">Type: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
@if (_databases != null)
|
@if (_databases != null)
|
||||||
{
|
{
|
||||||
|
@ -160,7 +160,7 @@ else
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">String:</Label>
|
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
<textarea id="connectionstring" class="form-control" @bind="@_connectionString" rows="3"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
@ -329,7 +329,7 @@ else
|
||||||
|
|
||||||
if (_tenantid == "+")
|
if (_tenantid == "+")
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(_tenantName) && _tenants.FirstOrDefault(item => item.Name == _tenantName) == null)
|
if (!string.IsNullOrEmpty(_tenantName) && !_tenants.Exists(item => item.Name == _tenantName))
|
||||||
{
|
{
|
||||||
// validate host credentials
|
// validate host credentials
|
||||||
var user = new User();
|
var user = new User();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@namespace Oqtane.Modules.Admin.Sql
|
@namespace Oqtane.Modules.Admin.Sql
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject ISystemService SystemService
|
||||||
@inject ITenantService TenantService
|
@inject ITenantService TenantService
|
||||||
@inject IDatabaseService DatabaseService
|
@inject IDatabaseService DatabaseService
|
||||||
@inject ISqlService SqlService
|
@inject ISqlService SqlService
|
||||||
|
@ -14,123 +15,284 @@
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="row mb-1 align-items-center">
|
<Label Class="col-sm-3" For="connection" HelpText="Select a database connection (from appsettings.json)" ResourceKey="Connection">Connection: </Label>
|
||||||
<Label Class="col-sm-3" For="tenant" HelpText="Select the tenant associated with the database server" ResourceKey="Tenant">Tenant: </Label>
|
<div class="col-sm-9">
|
||||||
<div class="col-sm-9">
|
<select id="tenant" class="form-select" value="@_connection" @onchange="(e => ConnectionChanged(e))">
|
||||||
<select id="tenant" class="form-select" value="@_tenantid" @onchange="(e => TenantChanged(e))">
|
<option value="-"><@Localizer["Connection.Select"]></option>
|
||||||
<option value="-1"><@Localizer["Tenant.Select"]></option>
|
<option value="+"><@Localizer["Connection.Add"]></option>
|
||||||
@foreach (Tenant tenant in _tenants)
|
@foreach (var connection in _connections)
|
||||||
{
|
{
|
||||||
<option value="@tenant.TenantId">@tenant.Name</option>
|
<option value="@connection.Key">@connection.Key</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@if (_tenantid != "-1")
|
@if (_connection == "+")
|
||||||
{
|
{
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="database" HelpText="The database for the tenant" ResourceKey="Database">Database: </Label>
|
<Label Class="col-sm-3" For="name" HelpText="Enter the name of the connection" ResourceKey="Name">Name: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<input id="database" class="form-control" @bind="@_database" readonly />
|
<input id="name" class="form-control" @bind="@_name" maxlength="100" required />
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection information for the database" ResourceKey="ConnectionString">Connection: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<div class="input-group">
|
|
||||||
<input id="connectionstring" type="@_connectionstringtype" class="form-control" @bind="@_connectionstring" readonly />
|
|
||||||
<button type="button" class="btn btn-secondary" @onclick="@ToggleConnectionString">@_connectionstringtoggle</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<Label Class="col-sm-3" For="sqlQuery" HelpText="Enter the SQL query for the database server" ResourceKey="SqlQuery">SQL Query: </Label>
|
<Label Class="col-sm-3" For="databasetype" HelpText="Select the database type" ResourceKey="DatabaseType">Type: </Label>
|
||||||
<div class="col-sm-9">
|
<div class="col-sm-9">
|
||||||
<textarea id="sqlQuery" class="form-control" @bind="@_sql" rows="3"></textarea>
|
@if (_databases != null)
|
||||||
</div>
|
{
|
||||||
</div>
|
<div class="input-group">
|
||||||
}
|
<select id="databasetype" class="form-select" value="@_databasetype" @onchange="(e => DatabaseTypeChanged(e))" required>
|
||||||
</div>
|
@foreach (var database in _databases)
|
||||||
<br />
|
{
|
||||||
<button type="button" class="btn btn-success" @onclick="Execute">@Localizer["Execute"]</button>
|
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||||
<br />
|
}
|
||||||
<br />
|
</select>
|
||||||
@if (_results != null)
|
@if (!_showConnectionString)
|
||||||
{
|
{
|
||||||
@if (_results.Count > 0)
|
<button type="button" class="btn btn-secondary" @onclick="ShowConnectionString">@Localizer["EnterConnectionString"]</button>
|
||||||
{
|
}
|
||||||
<Pager Class="table table-bordered" Items="@_results">
|
else
|
||||||
<Header>
|
{
|
||||||
@foreach (KeyValuePair<string, string> kvp in _results.First())
|
<button type="button" class="btn btn-secondary" @onclick="ShowConnectionString">@Localizer["EnterConnectionParameters"]</button>
|
||||||
{
|
}
|
||||||
<th>@kvp.Key</th>
|
</div>
|
||||||
}
|
}
|
||||||
</Header>
|
</div>
|
||||||
<Row>
|
</div>
|
||||||
@foreach (KeyValuePair<string, string> kvp in context)
|
@if (!_showConnectionString)
|
||||||
{
|
{
|
||||||
<td>@kvp.Value</td>
|
if (_databaseConfigType != null)
|
||||||
}
|
{
|
||||||
</Row>
|
@DatabaseConfigComponent
|
||||||
</Pager>
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@Localizer["Return.NoResult"]
|
<div class="row mb-1 align-items-center">
|
||||||
}
|
<Label Class="col-sm-3" For="connectionstring" HelpText="Enter a complete connection string including all parameters and delimiters" ResourceKey="ConnectionString">Settings:</Label>
|
||||||
<br />
|
<div class="col-sm-9">
|
||||||
<br />
|
<textarea id="connectionstring" class="form-control" @bind="@_connectionstring" rows="3"></textarea>
|
||||||
}
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="Add">@Localizer["Add"]</button>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@if (_connection != "-")
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="databasetype" HelpText="The database type" ResourceKey="DatabaseType">Type: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
@if (_databases != null)
|
||||||
|
{
|
||||||
|
<select id="databasetype" class="form-select" @bind="@_databasetype" required>
|
||||||
|
<option value="-"><@Localizer["Type.Select"]></option>
|
||||||
|
@foreach (var database in _databases)
|
||||||
|
{
|
||||||
|
<option value="@database.Name">@Localizer[@database.Name]</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (!string.IsNullOrEmpty(_tenant))
|
||||||
|
{
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="tenant" HelpText="The database using this connection" ResourceKey="Tenant">Database: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="connectionstring" HelpText="The connection string" ResourceKey="ConnectionString">Settings: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="connectionstring" type="@_connectionstringtype" class="form-control" @bind="@_connectionstring" readonly />
|
||||||
|
<button type="button" class="btn btn-secondary" @onclick="@ToggleConnectionString">@_connectionstringtoggle</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="sqlQuery" HelpText="Enter a valid SQL query for the database" ResourceKey="SqlQuery">SQL Query: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="sqlQuery" class="form-control" @bind="@_sql" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="Execute">@Localizer["Execute"]</button>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
@if (_results != null)
|
||||||
|
{
|
||||||
|
@if (_results.Count > 0)
|
||||||
|
{
|
||||||
|
<Pager Class="table table-bordered" Items="@_results">
|
||||||
|
<Header>
|
||||||
|
@foreach (KeyValuePair<string, string> kvp in _results.First())
|
||||||
|
{
|
||||||
|
<th>@kvp.Key</th>
|
||||||
|
}
|
||||||
|
</Header>
|
||||||
|
<Row>
|
||||||
|
@foreach (KeyValuePair<string, string> kvp in context)
|
||||||
|
{
|
||||||
|
<td>@kvp.Value</td>
|
||||||
|
}
|
||||||
|
</Row>
|
||||||
|
</Pager>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
@Localizer["Return.NoResult"]
|
||||||
|
}
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<br />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private List<Tenant> _tenants;
|
private string _connection = "-";
|
||||||
private string _tenantid = "-1";
|
private Dictionary<string, object> _connections;
|
||||||
private string _database = string.Empty;
|
private List<Tenant> _tenants;
|
||||||
|
private List<Database> _databases;
|
||||||
|
|
||||||
|
private string _name = string.Empty;
|
||||||
|
private string _databasetype = string.Empty;
|
||||||
|
private Type _databaseConfigType;
|
||||||
|
private object _databaseConfig;
|
||||||
|
private RenderFragment DatabaseConfigComponent { get; set; }
|
||||||
|
private bool _showConnectionString = false;
|
||||||
|
private string _tenant = string.Empty;
|
||||||
private string _connectionstring = string.Empty;
|
private string _connectionstring = string.Empty;
|
||||||
private string _connectionstringtype = "password";
|
private string _connectionstringtype = "password";
|
||||||
private string _connectionstringtoggle = string.Empty;
|
private string _connectionstringtoggle = string.Empty;
|
||||||
private string _sql = string.Empty;
|
private string _sql = string.Empty;
|
||||||
private List<Dictionary<string, string>> _results;
|
private List<Dictionary<string, string>> _results;
|
||||||
|
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_tenants = await TenantService.GetTenantsAsync();
|
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
||||||
|
_tenants = await TenantService.GetTenantsAsync();
|
||||||
|
_databases = await DatabaseService.GetDatabasesAsync();
|
||||||
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
|
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void TenantChanged(ChangeEventArgs e)
|
private async void ConnectionChanged(ChangeEventArgs e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_tenantid = (string)e.Value;
|
_connection = (string)e.Value;
|
||||||
var tenants = await TenantService.GetTenantsAsync();
|
if (_connection != "-" && _connection != "+")
|
||||||
var _databases = await DatabaseService.GetDatabasesAsync();
|
{
|
||||||
var tenant = tenants.Find(item => item.TenantId == int.Parse(_tenantid));
|
_connectionstring = _connections[_connection].ToString();
|
||||||
if (tenant != null)
|
_tenant = "";
|
||||||
{
|
_databasetype = "-";
|
||||||
_database = _databases.Find(item => item.DBType == tenant.DBType)?.Name;
|
var tenant = _tenants.FirstOrDefault(item => item.DBConnectionString == _connection);
|
||||||
_connectionstring = tenant.DBConnectionString;
|
if (tenant != null)
|
||||||
}
|
{
|
||||||
StateHasChanged();
|
_tenant = tenant.Name;
|
||||||
}
|
_databasetype = _databases.FirstOrDefault(item => item.DBType == tenant.DBType).Name;
|
||||||
catch (Exception ex)
|
}
|
||||||
{
|
}
|
||||||
await logger.LogError(ex, "Error Loading Tenant {TenantId} {Error}", _tenantid, ex.Message);
|
else
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
{
|
||||||
}
|
if (_databases.Exists(item => item.IsDefault))
|
||||||
}
|
{
|
||||||
|
_databasetype = _databases.Find(item => item.IsDefault).Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_databasetype = "LocalDB";
|
||||||
|
}
|
||||||
|
_showConnectionString = false;
|
||||||
|
LoadDatabaseConfigComponent();
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Loading Connection {Connection} {Error}", _connection, ex.Message);
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DatabaseTypeChanged(ChangeEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_databasetype = (string)eventArgs.Value;
|
||||||
|
_showConnectionString = false;
|
||||||
|
LoadDatabaseConfigComponent();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Error.Database.LoadConfig"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadDatabaseConfigComponent()
|
||||||
|
{
|
||||||
|
var database = _databases.SingleOrDefault(d => d.Name == _databasetype);
|
||||||
|
if (database != null)
|
||||||
|
{
|
||||||
|
_databaseConfigType = Type.GetType(database.ControlType);
|
||||||
|
DatabaseConfigComponent = builder =>
|
||||||
|
{
|
||||||
|
builder.OpenComponent(0, _databaseConfigType);
|
||||||
|
builder.AddComponentReferenceCapture(1, inst => { _databaseConfig = Convert.ChangeType(inst, _databaseConfigType); });
|
||||||
|
builder.CloseComponent();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowConnectionString()
|
||||||
|
{
|
||||||
|
if (_databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
|
{
|
||||||
|
_connectionstring = databaseConfigControl.GetConnectionString();
|
||||||
|
}
|
||||||
|
_showConnectionString = !_showConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Add()
|
||||||
|
{
|
||||||
|
var connectionstring = _connectionstring;
|
||||||
|
if (!_showConnectionString && _databaseConfig is IDatabaseConfigControl databaseConfigControl)
|
||||||
|
{
|
||||||
|
connectionstring = databaseConfigControl.GetConnectionString();
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(_name) && !string.IsNullOrEmpty(connectionstring))
|
||||||
|
{
|
||||||
|
var settings = new Dictionary<string, object>();
|
||||||
|
settings.Add($"{SettingKeys.ConnectionStringsSection}:{_name}", connectionstring);
|
||||||
|
await SystemService.UpdateSystemInfoAsync(settings);
|
||||||
|
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
||||||
|
_connection = "-";
|
||||||
|
AddModuleMessage(Localizer["Message.Connection.Added"], MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Required.Connection"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ToggleConnectionString()
|
private void ToggleConnectionString()
|
||||||
{
|
{
|
||||||
|
@ -145,14 +307,15 @@ else
|
||||||
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Execute()
|
private async Task Execute()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_tenantid != "-1" && !string.IsNullOrEmpty(_sql))
|
if (_databasetype != "-" && !string.IsNullOrEmpty(_sql))
|
||||||
{
|
{
|
||||||
var sqlquery = new SqlQuery { TenantId = int.Parse(_tenantid), Query = _sql };
|
var dbtype = _databases.FirstOrDefault(item => item.Name == _databasetype).DBType;
|
||||||
|
var sqlquery = new SqlQuery { DBConnectionString = _connection, DBType = dbtype, Query = _sql };
|
||||||
sqlquery = await SqlService.ExecuteQueryAsync(sqlquery);
|
sqlquery = await SqlService.ExecuteQueryAsync(sqlquery);
|
||||||
_results = sqlquery.Results;
|
_results = sqlquery.Results;
|
||||||
AddModuleMessage(Localizer["Success.QueryExecuted"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.QueryExecuted"], MessageType.Success);
|
||||||
|
|
|
@ -190,7 +190,7 @@
|
||||||
{
|
{
|
||||||
_version = Constants.Version;
|
_version = Constants.Version;
|
||||||
|
|
||||||
Dictionary<string, object> systeminfo = await SystemService.GetSystemInfoAsync("environment");
|
var systeminfo = await SystemService.GetSystemInfoAsync("environment");
|
||||||
if (systeminfo != null)
|
if (systeminfo != null)
|
||||||
{
|
{
|
||||||
_clrversion = systeminfo["CLRVersion"].ToString();
|
_clrversion = systeminfo["CLRVersion"].ToString();
|
||||||
|
@ -247,7 +247,9 @@
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await SystemService.UpdateSystemInfoAsync("Log", "Clear");
|
var settings = new Dictionary<string, object>();
|
||||||
|
settings.Add("clearlog", "true");
|
||||||
|
await SystemService.UpdateSystemInfoAsync(settings);
|
||||||
_log = string.Empty;
|
_log = string.Empty;
|
||||||
AddModuleMessage(Localizer["Success.ClearLog"], MessageType.Success);
|
AddModuleMessage(Localizer["Success.ClearLog"], MessageType.Success);
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@
|
||||||
<value>Enter a complete connection string including all parameters and delimiters</value>
|
<value>Enter a complete connection string including all parameters and delimiters</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionString.Text" xml:space="preserve">
|
<data name="ConnectionString.Text" xml:space="preserve">
|
||||||
<value>String:</value>
|
<value>Settings:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EnterConnectionParameters" xml:space="preserve">
|
<data name="EnterConnectionParameters" xml:space="preserve">
|
||||||
<value>Enter Connection Parameters</value>
|
<value>Enter Connection Parameters</value>
|
||||||
|
|
|
@ -163,7 +163,7 @@
|
||||||
<value>Enter the site name</value>
|
<value>Enter the site name</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.HelpText" xml:space="preserve">
|
<data name="Tenant.HelpText" xml:space="preserve">
|
||||||
<value>Enter the tenant for the site</value>
|
<value>The name of the database used for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.HelpText" xml:space="preserve">
|
<data name="Aliases.HelpText" xml:space="preserve">
|
||||||
<value>The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder).</value>
|
<value>The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder).</value>
|
||||||
|
@ -214,7 +214,7 @@
|
||||||
<value>Include a splash icon for your PWA. It should be a PNG which is 512 X 512 pixels in dimension.</value>
|
<value>Include a splash icon for your PWA. It should be a PNG which is 512 X 512 pixels in dimension.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Text" xml:space="preserve">
|
<data name="Tenant.Text" xml:space="preserve">
|
||||||
<value>Tenant: </value>
|
<value>Database: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.Text" xml:space="preserve">
|
<data name="Aliases.Text" xml:space="preserve">
|
||||||
<value>Aliases: </value>
|
<value>Aliases: </value>
|
||||||
|
@ -292,7 +292,7 @@
|
||||||
<value>Browse</value>
|
<value>Browse</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TenantInformation.Heading" xml:space="preserve">
|
<data name="TenantInformation.Heading" xml:space="preserve">
|
||||||
<value>Tenant Information</value>
|
<value>Database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="PWASettings.Heading" xml:space="preserve">
|
<data name="PWASettings.Heading" xml:space="preserve">
|
||||||
<value>PWA Settings</value>
|
<value>PWA Settings</value>
|
||||||
|
@ -304,13 +304,13 @@
|
||||||
<value>Connection:</value>
|
<value>Connection:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Database.Text" xml:space="preserve">
|
<data name="Database.Text" xml:space="preserve">
|
||||||
<value>Database:</value>
|
<value>Type:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionString.HelpText" xml:space="preserve">
|
<data name="ConnectionString.HelpText" xml:space="preserve">
|
||||||
<value>The connection information for the database</value>
|
<value>The connection information for the database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Database.HelpText" xml:space="preserve">
|
<data name="Database.HelpText" xml:space="preserve">
|
||||||
<value>The database for the tenant</value>
|
<value>The type of database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DeleteSite.Text" xml:space="preserve">
|
<data name="DeleteSite.Text" xml:space="preserve">
|
||||||
<value>Delete Site</value>
|
<value>Delete Site</value>
|
||||||
|
|
|
@ -123,9 +123,6 @@
|
||||||
<data name="SqlServer" xml:space="preserve">
|
<data name="SqlServer" xml:space="preserve">
|
||||||
<value>SQL Server</value>
|
<value>SQL Server</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Server.Text" xml:space="preserve">
|
|
||||||
<value>Server: </value>
|
|
||||||
</data>
|
|
||||||
<data name="Container.Select" xml:space="preserve">
|
<data name="Container.Select" xml:space="preserve">
|
||||||
<value>Select Container</value>
|
<value>Select Container</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -145,7 +142,7 @@
|
||||||
<value>Select the default container for the site</value>
|
<value>Select the default container for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Text" xml:space="preserve">
|
<data name="Tenant.Text" xml:space="preserve">
|
||||||
<value>Tenant: </value>
|
<value>Database: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Aliases.Text" xml:space="preserve">
|
<data name="Aliases.Text" xml:space="preserve">
|
||||||
<value>Aliases: </value>
|
<value>Aliases: </value>
|
||||||
|
@ -157,10 +154,10 @@
|
||||||
<value>Select Site Template</value>
|
<value>Select Site Template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Select" xml:space="preserve">
|
<data name="Tenant.Select" xml:space="preserve">
|
||||||
<value>Select Tenant</value>
|
<value>Select Database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.Add" xml:space="preserve">
|
<data name="Tenant.Add" xml:space="preserve">
|
||||||
<value>Create New Tenant</value>
|
<value>Create Database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.Theme.LoadContainers" xml:space="preserve">
|
<data name="Error.Theme.LoadContainers" xml:space="preserve">
|
||||||
<value>Error Loading Containers For Theme</value>
|
<value>Error Loading Containers For Theme</value>
|
||||||
|
@ -172,19 +169,19 @@
|
||||||
<value>Invalid Host Password</value>
|
<value>Invalid Host Password</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Error.TenantName.Exists" xml:space="preserve">
|
<data name="Error.TenantName.Exists" xml:space="preserve">
|
||||||
<value>Tenant Name Is Missing Or Already Exists</value>
|
<value>Database Name Is Missing Or Already Exists</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.SiteName.InUse" xml:space="preserve">
|
<data name="Message.SiteName.InUse" xml:space="preserve">
|
||||||
<value>{0} Already Used For Another Site</value>
|
<value>{0} Already Used For Another Site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Message.Required.Tenant" xml:space="preserve">
|
<data name="Message.Required.Tenant" xml:space="preserve">
|
||||||
<value>You Must Provide A Tenant, Site Name, Alias, Default Theme/Container, And Site Template</value>
|
<value>You Must Provide A Database, Site Name, Alias, Default Theme/Container, And Site Template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Name.HelpText" xml:space="preserve">
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name of the site</value>
|
<value>Enter the name of the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DefaultTheme.HelpText" xml:space="preserve">
|
<data name="DefaultTheme.HelpText" xml:space="preserve">
|
||||||
<value>Select the default theme for the website</value>
|
<value>Select the default theme for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="AdminContainer.HelpText" xml:space="preserve">
|
<data name="AdminContainer.HelpText" xml:space="preserve">
|
||||||
<value>Select the admin container for the site</value>
|
<value>Select the admin container for the site</value>
|
||||||
|
@ -193,28 +190,13 @@
|
||||||
<value>Select the site template</value>
|
<value>Select the site template</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.HelpText" xml:space="preserve">
|
<data name="Tenant.HelpText" xml:space="preserve">
|
||||||
<value>Select the tenant for the site</value>
|
<value>Select the database for the site</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TenantName.HelpText" xml:space="preserve">
|
<data name="TenantName.HelpText" xml:space="preserve">
|
||||||
<value>Enter the name for the tenant</value>
|
<value>Enter the name for the database</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DatabaseType.HelpText" xml:space="preserve">
|
<data name="DatabaseType.HelpText" xml:space="preserve">
|
||||||
<value>Select the database type for the tenant</value>
|
<value>Select the database type</value>
|
||||||
</data>
|
|
||||||
<data name="DatabaseServer.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the server for the tenant</value>
|
|
||||||
</data>
|
|
||||||
<data name="Database.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the database for the tenant</value>
|
|
||||||
</data>
|
|
||||||
<data name="IntegratedSecurity.HelpText" xml:space="preserve">
|
|
||||||
<value>Select if you want integrated security or not</value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabaseUsername.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the username for the integrated security</value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabasePassword.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the password for the integrated security</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="HostUsername.HelpText" xml:space="preserve">
|
<data name="HostUsername.HelpText" xml:space="preserve">
|
||||||
<value>Enter the username of an existing host user</value>
|
<value>Enter the username of an existing host user</value>
|
||||||
|
@ -232,23 +214,14 @@
|
||||||
<value>Site Template: </value>
|
<value>Site Template: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TenantName.Text" xml:space="preserve">
|
<data name="TenantName.Text" xml:space="preserve">
|
||||||
<value>Tenant Name: </value>
|
<value>Name: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="DatabaseType.Text" xml:space="preserve">
|
<data name="DatabaseType.Text" xml:space="preserve">
|
||||||
<value>Database Type: </value>
|
<value>Type: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Database.Text" xml:space="preserve">
|
<data name="Database.Text" xml:space="preserve">
|
||||||
<value>Database: </value>
|
<value>Database: </value>
|
||||||
</data>
|
</data>
|
||||||
<data name="IntegratedSecurity.Text" xml:space="preserve">
|
|
||||||
<value>Integrated Security: </value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabaseUsername.Text" xml:space="preserve">
|
|
||||||
<value>Database Username: </value>
|
|
||||||
</data>
|
|
||||||
<data name="DatabasePassword.Text" xml:space="preserve">
|
|
||||||
<value>Database Password: </value>
|
|
||||||
</data>
|
|
||||||
<data name="HostUsername.Text" xml:space="preserve">
|
<data name="HostUsername.Text" xml:space="preserve">
|
||||||
<value>Host Username:</value>
|
<value>Host Username:</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -274,7 +247,7 @@
|
||||||
<value>Enter a complete connection string including all parameters and delimiters</value>
|
<value>Enter a complete connection string including all parameters and delimiters</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ConnectionString.Text" xml:space="preserve">
|
<data name="ConnectionString.Text" xml:space="preserve">
|
||||||
<value>String:</value>
|
<value>Settings:</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EnterConnectionParameters" xml:space="preserve">
|
<data name="EnterConnectionParameters" xml:space="preserve">
|
||||||
<value>Enter Connection Parameters</value>
|
<value>Enter Connection Parameters</value>
|
||||||
|
|
|
@ -117,30 +117,75 @@
|
||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="Connection.Text" xml:space="preserve">
|
||||||
|
<value>Connection: </value>
|
||||||
|
</data>
|
||||||
|
<data name="Connection.HelpText" xml:space="preserve">
|
||||||
|
<value>Select a database connection (from appsettings.json)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Connection.Select" xml:space="preserve">
|
||||||
|
<value>Select Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="Connection.Add" xml:space="preserve">
|
||||||
|
<value>Add Connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="Name.Text" xml:space="preserve">
|
||||||
|
<value>Name: </value>
|
||||||
|
</data>
|
||||||
|
<data name="Name.HelpText" xml:space="preserve">
|
||||||
|
<value>Enter the name of the connection</value>
|
||||||
|
</data>
|
||||||
|
<data name="DatabaseType.Text" xml:space="preserve">
|
||||||
|
<value>Type: </value>
|
||||||
|
</data>
|
||||||
|
<data name="DatabaseType.HelpText" xml:space="preserve">
|
||||||
|
<value>Select the database type</value>
|
||||||
|
</data>
|
||||||
|
<data name="Type.Select" xml:space="preserve">
|
||||||
|
<value>Select Type</value>
|
||||||
|
</data>
|
||||||
|
<data name="EnterConnectionParameters" xml:space="preserve">
|
||||||
|
<value>Enter Connection Parameters</value>
|
||||||
|
</data>
|
||||||
|
<data name="EnterConnectionString" xml:space="preserve">
|
||||||
|
<value>Enter Connection String</value>
|
||||||
|
</data>
|
||||||
|
<data name="ConnectionString.Text" xml:space="preserve">
|
||||||
|
<value>Settings: </value>
|
||||||
|
</data>
|
||||||
|
<data name="ConnectionString.HelpText" xml:space="preserve">
|
||||||
|
<value>A complete connection string including all parameters and delimiters</value>
|
||||||
|
</data>
|
||||||
|
<data name="Add" xml:space="preserve">
|
||||||
|
<value>Add</value>
|
||||||
|
</data>
|
||||||
<data name="Tenant.Text" xml:space="preserve">
|
<data name="Tenant.Text" xml:space="preserve">
|
||||||
<value>Tenant: </value>
|
<value>Database: </value>
|
||||||
</data>
|
|
||||||
<data name="Tenant.Select" xml:space="preserve">
|
|
||||||
<value>Select Tenant</value>
|
|
||||||
</data>
|
|
||||||
<data name="Execute" xml:space="preserve">
|
|
||||||
<value>Execute</value>
|
|
||||||
</data>
|
|
||||||
<data name="Message.Required.Tenant" xml:space="preserve">
|
|
||||||
<value>You Must Select A Tenant And Provide A Valid SQL Query</value>
|
|
||||||
</data>
|
|
||||||
<data name="Return.NoResult" xml:space="preserve">
|
|
||||||
<value>No Results Returned</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="Tenant.HelpText" xml:space="preserve">
|
<data name="Tenant.HelpText" xml:space="preserve">
|
||||||
<value>Select the tenant associated with the database server</value>
|
<value>The database using this connection</value>
|
||||||
</data>
|
|
||||||
<data name="SqlQuery.HelpText" xml:space="preserve">
|
|
||||||
<value>Enter the SQL query for the database server</value>
|
|
||||||
</data>
|
</data>
|
||||||
<data name="SqlQuery.Text" xml:space="preserve">
|
<data name="SqlQuery.Text" xml:space="preserve">
|
||||||
<value>SQL Query: </value>
|
<value>SQL Query: </value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SqlQuery.HelpText" xml:space="preserve">
|
||||||
|
<value>Enter a valid SQL query for the database</value>
|
||||||
|
</data>
|
||||||
|
<data name="Execute" xml:space="preserve">
|
||||||
|
<value>Execute</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Required.Tenant" xml:space="preserve">
|
||||||
|
<value>You Must Select A Database Type And Provide A Valid SQL Query</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Required.Connection" xml:space="preserve">
|
||||||
|
<value>You Must Provide A Connection Name And Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Connection.Added" xml:space="preserve">
|
||||||
|
<value>Connection Added Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Return.NoResult" xml:space="preserve">
|
||||||
|
<value>No Results Returned</value>
|
||||||
|
</data>
|
||||||
<data name="Success.QueryExecuted" xml:space="preserve">
|
<data name="Success.QueryExecuted" xml:space="preserve">
|
||||||
<value>SQL Query Executed</value>
|
<value>SQL Query Executed</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
|
@ -32,11 +32,5 @@ namespace Oqtane.Services
|
||||||
/// <param name="settings"></param>
|
/// <param name="settings"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task UpdateSystemInfoAsync(Dictionary<string, object> settings);
|
Task UpdateSystemInfoAsync(Dictionary<string, object> settings);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// updates a config value
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
Task UpdateSystemInfoAsync(string settingKey, object settingValue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Threading.Tasks;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Oqtane.Documentation;
|
using Oqtane.Documentation;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
|
@ -32,9 +33,5 @@ namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
await PostJsonAsync(Apiurl, settings);
|
await PostJsonAsync(Apiurl, settings);
|
||||||
}
|
}
|
||||||
public async Task UpdateSystemInfoAsync(string settingKey, object settingValue)
|
|
||||||
{
|
|
||||||
await PutJsonAsync($"{Apiurl}/{settingKey}/{settingValue}", "");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
var installation = new Installation { Success = false, Message = "" };
|
var installation = new Installation { Success = false, Message = "" };
|
||||||
|
|
||||||
if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || string.IsNullOrEmpty(_configManager.GetSetting("ConnectionStrings:" + SettingKeys.ConnectionStringKey, ""))))
|
if (ModelState.IsValid && (User.IsInRole(RoleNames.Host) || string.IsNullOrEmpty(_configManager.GetSetting($"{SettingKeys.ConnectionStringsSection}:{SettingKeys.ConnectionStringKey}", ""))))
|
||||||
{
|
{
|
||||||
installation = _databaseManager.Install(config);
|
installation = _databaseManager.Install(config);
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,23 @@ namespace Oqtane.Controllers
|
||||||
{
|
{
|
||||||
var results = new List<Dictionary<string, string>>();
|
var results = new List<Dictionary<string, string>>();
|
||||||
Dictionary<string, string> row;
|
Dictionary<string, string> row;
|
||||||
Tenant tenant = _tenants.GetTenant(sqlquery.TenantId);
|
|
||||||
|
if (string.IsNullOrEmpty(sqlquery.DBType) || string.IsNullOrEmpty(sqlquery.DBConnectionString))
|
||||||
|
{
|
||||||
|
Tenant tenant = _tenants.GetTenant(sqlquery.TenantId);
|
||||||
|
if (tenant != null)
|
||||||
|
{
|
||||||
|
sqlquery.DBType = tenant.DBType;
|
||||||
|
sqlquery.DBConnectionString = tenant.DBConnectionString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
foreach (string query in sqlquery.Query.Split("GO", StringSplitOptions.RemoveEmptyEntries))
|
foreach (string query in sqlquery.Query.Split("GO", StringSplitOptions.RemoveEmptyEntries))
|
||||||
{
|
{
|
||||||
IDataReader dr = _sql.ExecuteReader(tenant, query);
|
IDataReader dr = _sql.ExecuteReader(sqlquery.DBType, sqlquery.DBConnectionString, query);
|
||||||
_logger.Log(LogLevel.Information, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId}", query, sqlquery.TenantId);
|
_logger.Log(LogLevel.Information, this, LogFunction.Other, "Sql Query {Query} Executed on Database {DBType} and Connection {DBConnectionString}", query, sqlquery.DBType, sqlquery.DBConnectionString);
|
||||||
while (dr.Read())
|
while (dr.Read())
|
||||||
{
|
{
|
||||||
row = new Dictionary<string, string>();
|
row = new Dictionary<string, string>();
|
||||||
|
@ -53,7 +63,7 @@ namespace Oqtane.Controllers
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
results.Add(new Dictionary<string, string>() { { "Error", ex.Message } });
|
results.Add(new Dictionary<string, string>() { { "Error", ex.Message } });
|
||||||
_logger.Log(LogLevel.Warning, this, LogFunction.Other, "Sql Query {Query} Executed on Tenant {TenantId} Resulted In An Error {Error}", sqlquery.Query, sqlquery.TenantId, ex.Message);
|
_logger.Log(LogLevel.Warning, this, LogFunction.Other, "Sql Query {Query} Executed on Database {DBType} and Connection {DBConnectionString} Resulted In An Error {Error}", sqlquery.Query, sqlquery.DBType, sqlquery.DBConnectionString, ex.Message);
|
||||||
}
|
}
|
||||||
sqlquery.Results = results;
|
sqlquery.Results = results;
|
||||||
return sqlquery;
|
return sqlquery;
|
||||||
|
|
|
@ -63,6 +63,12 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
systeminfo.Add("Log", log);
|
systeminfo.Add("Log", log);
|
||||||
break;
|
break;
|
||||||
|
case "connectionstrings":
|
||||||
|
foreach (var kvp in _configManager.GetSettings(SettingKeys.ConnectionStringsSection))
|
||||||
|
{
|
||||||
|
systeminfo.Add(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return systeminfo;
|
return systeminfo;
|
||||||
|
@ -88,19 +94,11 @@ namespace Oqtane.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PUT: api/<controller>
|
|
||||||
[HttpPut("{key}/{value}")]
|
|
||||||
[Authorize(Roles = RoleNames.Host)]
|
|
||||||
public void Put(string key, object value)
|
|
||||||
{
|
|
||||||
UpdateSetting(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateSetting(string key, object value)
|
private void UpdateSetting(string key, object value)
|
||||||
{
|
{
|
||||||
switch (key)
|
switch (key.ToLower())
|
||||||
{
|
{
|
||||||
case "Log":
|
case "clearlog":
|
||||||
string path = Path.Combine(_environment.ContentRootPath, "Content", "Log", "error.log");
|
string path = Path.Combine(_environment.ContentRootPath, "Content", "Log", "error.log");
|
||||||
if (System.IO.File.Exists(path))
|
if (System.IO.File.Exists(path))
|
||||||
{
|
{
|
||||||
|
|
|
@ -72,6 +72,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
|
|
||||||
internal static IServiceCollection AddOqtaneTransientServices(this IServiceCollection services)
|
internal static IServiceCollection AddOqtaneTransientServices(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
services.AddTransient<IDBContextDependencies, DBContextDependencies>();
|
||||||
services.AddTransient<ITenantManager, TenantManager>();
|
services.AddTransient<ITenantManager, TenantManager>();
|
||||||
services.AddTransient<IAliasAccessor, AliasAccessor>();
|
services.AddTransient<IAliasAccessor, AliasAccessor>();
|
||||||
services.AddTransient<IUserPermissions, UserPermissions>();
|
services.AddTransient<IUserPermissions, UserPermissions>();
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Nodes;
|
using System.Text.Json.Nodes;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
@ -42,6 +44,16 @@ namespace Oqtane.Infrastructure
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Dictionary<string, string> GetSettings(string sectionKey)
|
||||||
|
{
|
||||||
|
var settings = new Dictionary<string, string>();
|
||||||
|
foreach (var kvp in _config.GetSection(sectionKey).GetChildren().AsEnumerable())
|
||||||
|
{
|
||||||
|
settings.Add(kvp.Key, kvp.Value);
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddOrUpdateSetting<T>(string key, T value, bool reload)
|
public void AddOrUpdateSetting<T>(string key, T value, bool reload)
|
||||||
{
|
{
|
||||||
AddOrUpdateSetting("appsettings.json", key, value, reload);
|
AddOrUpdateSetting("appsettings.json", key, value, reload);
|
||||||
|
|
|
@ -162,6 +162,16 @@ namespace Oqtane.Infrastructure
|
||||||
{
|
{
|
||||||
install.DefaultContainer = GetInstallationConfig(SettingKeys.DefaultContainerKey, Constants.DefaultContainer);
|
install.DefaultContainer = GetInstallationConfig(SettingKeys.DefaultContainerKey, Constants.DefaultContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add new site
|
||||||
|
if (install.TenantName != TenantNames.Master && install.ConnectionString.Contains("="))
|
||||||
|
{
|
||||||
|
_configManager.AddOrUpdateSetting($"{SettingKeys.ConnectionStringsSection}:{install.TenantName}", install.ConnectionString, false);
|
||||||
|
}
|
||||||
|
if (install.TenantName == TenantNames.Master && !install.ConnectionString.Contains("="))
|
||||||
|
{
|
||||||
|
install.ConnectionString = _config.GetConnectionString(install.ConnectionString);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -273,7 +283,7 @@ namespace Oqtane.Infrastructure
|
||||||
var database = Activator.CreateInstance(type) as IDatabase;
|
var database = Activator.CreateInstance(type) as IDatabase;
|
||||||
|
|
||||||
// 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(Constants.DataDirectory)?.ToString();
|
||||||
if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory ?? String.Empty);
|
if (!Directory.Exists(dataDirectory)) Directory.CreateDirectory(dataDirectory ?? String.Empty);
|
||||||
|
|
||||||
var dbOptions = new DbContextOptionsBuilder().UseOqtaneDatabase(database, NormalizeConnectionString(install.ConnectionString)).Options;
|
var dbOptions = new DbContextOptionsBuilder().UseOqtaneDatabase(database, NormalizeConnectionString(install.ConnectionString)).Options;
|
||||||
|
@ -316,10 +326,7 @@ namespace Oqtane.Infrastructure
|
||||||
|
|
||||||
using (var masterDbContext = new MasterDBContext(new DbContextOptions<MasterDBContext>(), null, _config))
|
using (var masterDbContext = new MasterDBContext(new DbContextOptions<MasterDBContext>(), null, _config))
|
||||||
{
|
{
|
||||||
if (installation.Success && (install.DatabaseType == Constants.DefaultDBType))
|
AddEFMigrationsHistory(sql, install.ConnectionString, install.DatabaseType, "", true);
|
||||||
{
|
|
||||||
UpgradeSqlServer(sql, install.ConnectionString, install.DatabaseType, true);
|
|
||||||
}
|
|
||||||
// push latest model into database
|
// push latest model into database
|
||||||
masterDbContext.Database.Migrate();
|
masterDbContext.Database.Migrate();
|
||||||
result.Success = true;
|
result.Success = true;
|
||||||
|
@ -354,7 +361,7 @@ namespace Oqtane.Infrastructure
|
||||||
tenant = new Tenant
|
tenant = new Tenant
|
||||||
{
|
{
|
||||||
Name = install.TenantName,
|
Name = install.TenantName,
|
||||||
DBConnectionString = DenormalizeConnectionString(install.ConnectionString),
|
DBConnectionString = (install.TenantName == TenantNames.Master) ? SettingKeys.ConnectionStringKey : install.TenantName,
|
||||||
DBType = install.DatabaseType,
|
DBType = install.DatabaseType,
|
||||||
CreatedBy = "",
|
CreatedBy = "",
|
||||||
CreatedOn = DateTime.UtcNow,
|
CreatedOn = DateTime.UtcNow,
|
||||||
|
@ -413,21 +420,19 @@ namespace Oqtane.Infrastructure
|
||||||
var upgrades = scope.ServiceProvider.GetRequiredService<IUpgradeManager>();
|
var upgrades = scope.ServiceProvider.GetRequiredService<IUpgradeManager>();
|
||||||
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
var sql = scope.ServiceProvider.GetRequiredService<ISqlRepository>();
|
||||||
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
var tenantManager = scope.ServiceProvider.GetRequiredService<ITenantManager>();
|
||||||
|
var DBContextDependencies = scope.ServiceProvider.GetRequiredService<IDBContextDependencies>();
|
||||||
|
|
||||||
using (var db = GetInstallationContext())
|
using (var db = GetInstallationContext())
|
||||||
{
|
{
|
||||||
foreach (var tenant in db.Tenant.ToList())
|
foreach (var tenant in db.Tenant.ToList())
|
||||||
{
|
{
|
||||||
tenantManager.SetTenant(tenant.TenantId);
|
tenantManager.SetTenant(tenant.TenantId);
|
||||||
|
tenant.DBConnectionString = MigrateConnectionString(db, tenant);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var tenantDbContext = new TenantDBContext(tenantManager, null))
|
using (var tenantDbContext = new TenantDBContext(DBContextDependencies))
|
||||||
{
|
{
|
||||||
if (install.DatabaseType == Constants.DefaultDBType)
|
AddEFMigrationsHistory(sql, _configManager.GetSetting($"{SettingKeys.ConnectionStringsSection}:{tenant.DBConnectionString}", ""), tenant.DBType, tenant.Version, false);
|
||||||
{
|
|
||||||
UpgradeSqlServer(sql, tenant.DBConnectionString, tenant.DBType, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// push latest model into database
|
// push latest model into database
|
||||||
tenantDbContext.Database.Migrate();
|
tenantDbContext.Database.Migrate();
|
||||||
result.Success = true;
|
result.Success = true;
|
||||||
|
@ -753,8 +758,8 @@ 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(Constants.DataDirectory)?.ToString();
|
||||||
connectionString = connectionString.Replace(dataDirectory ?? String.Empty, "|DataDirectory|");
|
connectionString = connectionString.Replace(dataDirectory ?? String.Empty, $"|{Constants.DataDirectory}|");
|
||||||
return connectionString;
|
return connectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -780,8 +785,8 @@ namespace Oqtane.Infrastructure
|
||||||
|
|
||||||
private string NormalizeConnectionString(string connectionString)
|
private string NormalizeConnectionString(string connectionString)
|
||||||
{
|
{
|
||||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString();
|
var dataDirectory = AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString();
|
||||||
connectionString = connectionString.Replace("|DataDirectory|", dataDirectory);
|
connectionString = connectionString.Replace($"|{Constants.DataDirectory}|", dataDirectory);
|
||||||
return connectionString;
|
return connectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,14 +804,39 @@ namespace Oqtane.Infrastructure
|
||||||
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType, true);
|
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpgradeSqlServer(ISqlRepository sql, string connectionString, string databaseType, bool isMaster)
|
public void AddEFMigrationsHistory(ISqlRepository sql, string connectionString, string databaseType, string version, bool isMaster)
|
||||||
{
|
{
|
||||||
var script = (isMaster) ? "MigrateMaster.sql" : "MigrateTenant.sql";
|
// in version 2.1.0 the __EFMigrationsHistory tables were introduced and must be added to existing SQL Server installations
|
||||||
|
if ((isMaster || (version != null && Version.Parse(version).CompareTo(Version.Parse("2.1.0")) < 0)) && databaseType == Constants.DefaultDBType)
|
||||||
|
{
|
||||||
|
var script = (isMaster) ? "MigrateMaster.sql" : "MigrateTenant.sql";
|
||||||
|
|
||||||
var query = sql.GetScriptFromAssembly(Assembly.GetExecutingAssembly(), script);
|
var query = sql.GetScriptFromAssembly(Assembly.GetExecutingAssembly(), script);
|
||||||
query = query.Replace("{{Version}}", Constants.Version);
|
query = query.Replace("{{Version}}", Constants.Version);
|
||||||
|
|
||||||
sql.ExecuteNonQuery(connectionString, databaseType, query);
|
sql.ExecuteNonQuery(connectionString, databaseType, query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string MigrateConnectionString(InstallationContext db, Tenant tenant)
|
||||||
|
{
|
||||||
|
// migrate connection strings from the Tenant table to appsettings
|
||||||
|
if (tenant.DBConnectionString.Contains("="))
|
||||||
|
{
|
||||||
|
var defaultConnection = _configManager.GetConnectionString(SettingKeys.ConnectionStringKey);
|
||||||
|
if (tenant.DBConnectionString == defaultConnection)
|
||||||
|
{
|
||||||
|
tenant.DBConnectionString = SettingKeys.ConnectionStringKey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_configManager.AddOrUpdateSetting($"{SettingKeys.ConnectionStringsSection}:{tenant.Name}", tenant.DBConnectionString, false);
|
||||||
|
tenant.DBConnectionString = tenant.Name;
|
||||||
|
}
|
||||||
|
db.Entry(tenant).State = EntityState.Modified;
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
return tenant.DBConnectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ValidateConfiguration()
|
private void ValidateConfiguration()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
namespace Oqtane.Infrastructure
|
namespace Oqtane.Infrastructure
|
||||||
|
@ -7,6 +8,7 @@ namespace Oqtane.Infrastructure
|
||||||
public IConfigurationSection GetSection(string sectionKey);
|
public IConfigurationSection GetSection(string sectionKey);
|
||||||
public T GetSetting<T>(string settingKey, T defaultValue);
|
public T GetSetting<T>(string settingKey, T defaultValue);
|
||||||
public T GetSetting<T>(string sectionKey, string settingKey, T defaultValue);
|
public T GetSetting<T>(string sectionKey, string settingKey, T defaultValue);
|
||||||
|
public Dictionary<string, string> GetSettings(string sectionKey);
|
||||||
void AddOrUpdateSetting<T>(string key, T value, bool reload);
|
void AddOrUpdateSetting<T>(string key, T value, bool reload);
|
||||||
void AddOrUpdateSetting<T>(string file, 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 key, bool reload);
|
||||||
|
|
|
@ -2,7 +2,6 @@ using Oqtane.Infrastructure;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Modules.HtmlText.Repository;
|
using Oqtane.Modules.HtmlText.Repository;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Oqtane.Enums;
|
using Oqtane.Enums;
|
||||||
using Oqtane.Repository;
|
using Oqtane.Repository;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
@ -17,15 +16,13 @@ namespace Oqtane.Modules.HtmlText.Manager
|
||||||
public class HtmlTextManager : MigratableModuleBase, IInstallable, IPortable
|
public class HtmlTextManager : MigratableModuleBase, IInstallable, IPortable
|
||||||
{
|
{
|
||||||
private readonly IHtmlTextRepository _htmlText;
|
private readonly IHtmlTextRepository _htmlText;
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly IDBContextDependencies _DBContextDependencies;
|
||||||
private readonly IHttpContextAccessor _accessor;
|
|
||||||
private readonly ISqlRepository _sqlRepository;
|
private readonly ISqlRepository _sqlRepository;
|
||||||
|
|
||||||
public HtmlTextManager(IHtmlTextRepository htmlText, ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor, ISqlRepository sqlRepository)
|
public HtmlTextManager(IHtmlTextRepository htmlText, IDBContextDependencies DBContextDependencies, ISqlRepository sqlRepository)
|
||||||
{
|
{
|
||||||
_htmlText = htmlText;
|
_htmlText = htmlText;
|
||||||
_tenantManager = tenantManager;
|
_DBContextDependencies = DBContextDependencies;
|
||||||
_accessor = httpContextAccessor;
|
|
||||||
_sqlRepository = sqlRepository;
|
_sqlRepository = sqlRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,12 +53,12 @@ namespace Oqtane.Modules.HtmlText.Manager
|
||||||
// version 1.0.0 used SQL scripts rather than migrations, so we need to seed the migration history table
|
// version 1.0.0 used SQL scripts rather than migrations, so we need to seed the migration history table
|
||||||
_sqlRepository.ExecuteNonQuery(tenant, MigrationUtils.BuildInsertScript("HtmlText.01.00.00.00"));
|
_sqlRepository.ExecuteNonQuery(tenant, MigrationUtils.BuildInsertScript("HtmlText.01.00.00.00"));
|
||||||
}
|
}
|
||||||
return Migrate(new HtmlTextContext(_tenantManager, _accessor), tenant, MigrationType.Up);
|
return Migrate(new HtmlTextContext(_DBContextDependencies), tenant, MigrationType.Up);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Uninstall(Tenant tenant)
|
public bool Uninstall(Tenant tenant)
|
||||||
{
|
{
|
||||||
return Migrate(new HtmlTextContext(_tenantManager, _accessor), tenant, MigrationType.Down);
|
return Migrate(new HtmlTextContext(_DBContextDependencies), tenant, MigrationType.Down);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace Oqtane.Modules.HtmlText.Repository
|
||||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||||
public class HtmlTextContext : DBContextBase, ITransientService, IMultiDatabase
|
public class HtmlTextContext : DBContextBase, ITransientService, IMultiDatabase
|
||||||
{
|
{
|
||||||
public HtmlTextContext(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) : base(tenantManager, httpContextAccessor) { }
|
public HtmlTextContext(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) { }
|
||||||
|
|
||||||
public virtual DbSet<Models.HtmlText> HtmlText { get; set; }
|
public virtual DbSet<Models.HtmlText> HtmlText { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
@ -6,11 +7,13 @@ using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Migrations;
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Oqtane.Databases.Interfaces;
|
using Oqtane.Databases.Interfaces;
|
||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Migrations.Framework;
|
using Oqtane.Migrations.Framework;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
using Oqtane.Shared;
|
||||||
|
|
||||||
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
// ReSharper disable BuiltInTypeReferenceStyleForMemberAccess
|
||||||
|
|
||||||
|
@ -18,17 +21,17 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class DBContextBase : IdentityUserContext<IdentityUser>
|
public class DBContextBase : IdentityUserContext<IdentityUser>
|
||||||
{
|
{
|
||||||
private readonly ITenantResolver _tenantResolver;
|
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly ITenantManager _tenantManager;
|
||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IHttpContextAccessor _accessor;
|
||||||
private string _connectionString;
|
private readonly IConfigurationRoot _config;
|
||||||
private string _databaseType;
|
private string _connectionString = "";
|
||||||
|
private string _databaseType = "";
|
||||||
|
|
||||||
public DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor)
|
public DBContextBase(IDBContextDependencies DBContextDependencies)
|
||||||
{
|
{
|
||||||
_connectionString = String.Empty;
|
_tenantManager = DBContextDependencies.TenantManager;
|
||||||
_tenantManager = tenantManager;
|
_accessor = DBContextDependencies.Accessor;
|
||||||
_accessor = httpContextAccessor;
|
_config = DBContextDependencies.Config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDatabase ActiveDatabase { get; set; }
|
public IDatabase ActiveDatabase { get; set; }
|
||||||
|
@ -39,21 +42,11 @@ namespace Oqtane.Repository
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(_connectionString))
|
if (string.IsNullOrEmpty(_connectionString))
|
||||||
{
|
{
|
||||||
|
Tenant tenant = _tenantManager.GetTenant();
|
||||||
Tenant tenant;
|
|
||||||
if (_tenantResolver != null)
|
|
||||||
{
|
|
||||||
tenant = _tenantResolver.GetTenant();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tenant = _tenantManager.GetTenant();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tenant != null)
|
if (tenant != null)
|
||||||
{
|
{
|
||||||
_connectionString = tenant.DBConnectionString
|
_connectionString = _config.GetConnectionString(tenant.DBConnectionString)
|
||||||
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
.Replace($"|{Constants.DataDirectory}|", AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString());
|
||||||
_databaseType = tenant.DBType;
|
_databaseType = tenant.DBType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,12 +86,17 @@ namespace Oqtane.Repository
|
||||||
return base.SaveChangesAsync(cancellationToken);
|
return base.SaveChangesAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("This constructor is obsolete. Use DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) instead.", false)]
|
[Obsolete("This constructor is obsolete. Use DBContextBase(IDBContextDependencies DBContextDependencies) instead.", false)]
|
||||||
public DBContextBase(ITenantResolver tenantResolver, IHttpContextAccessor httpContextAccessor)
|
public DBContextBase(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor)
|
||||||
{
|
{
|
||||||
_connectionString = String.Empty;
|
_tenantManager = tenantManager;
|
||||||
_tenantResolver = tenantResolver;
|
|
||||||
_accessor = httpContextAccessor;
|
_accessor = httpContextAccessor;
|
||||||
|
|
||||||
|
// anti-pattern used to reference config service in base class without causing breaking change
|
||||||
|
_config = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory())
|
||||||
|
.AddJsonFile("appsettings.json")
|
||||||
|
.Build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
Oqtane.Server/Repository/Context/DBContextDependencies.cs
Normal file
20
Oqtane.Server/Repository/Context/DBContextDependencies.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
|
||||||
|
namespace Oqtane.Repository
|
||||||
|
{
|
||||||
|
public class DBContextDependencies : IDBContextDependencies
|
||||||
|
{
|
||||||
|
public DBContextDependencies(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor, IConfigurationRoot config)
|
||||||
|
{
|
||||||
|
TenantManager = tenantManager;
|
||||||
|
Accessor = httpContextAccessor;
|
||||||
|
Config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ITenantManager TenantManager { get; }
|
||||||
|
public IHttpContextAccessor Accessor { get; }
|
||||||
|
public IConfigurationRoot Config { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,5 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
|
||||||
using Oqtane.Databases.Interfaces;
|
|
||||||
using Oqtane.Extensions;
|
using Oqtane.Extensions;
|
||||||
using Oqtane.Interfaces;
|
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using IDatabase = Oqtane.Databases.Interfaces.IDatabase;
|
using IDatabase = Oqtane.Databases.Interfaces.IDatabase;
|
||||||
|
|
||||||
|
|
|
@ -41,8 +41,8 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
if (_config.IsInstalled())
|
if (_config.IsInstalled())
|
||||||
{
|
{
|
||||||
_connectionString = _config.GetConnectionString("DefaultConnection")
|
_connectionString = _config.GetConnectionString(SettingKeys.ConnectionStringKey)
|
||||||
.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory")?.ToString());
|
.Replace($"|{Constants.DataDirectory}|", AppDomain.CurrentDomain.GetData(Constants.DataDirectory)?.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
_databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
|
_databaseType = _config.GetSection(SettingKeys.DatabaseSection)[SettingKeys.DatabaseTypeKey];
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Oqtane.Infrastructure;
|
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Repository.Databases.Interfaces;
|
using Oqtane.Repository.Databases.Interfaces;
|
||||||
|
|
||||||
|
@ -12,7 +10,7 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class TenantDBContext : DBContextBase, IMultiDatabase
|
public class TenantDBContext : DBContextBase, IMultiDatabase
|
||||||
{
|
{
|
||||||
public TenantDBContext(ITenantManager tenantManager, IHttpContextAccessor httpContextAccessor) : base(tenantManager, httpContextAccessor) { }
|
public TenantDBContext(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) { }
|
||||||
|
|
||||||
public virtual DbSet<Site> Site { get; set; }
|
public virtual DbSet<Site> Site { get; set; }
|
||||||
public virtual DbSet<Page> Page { get; set; }
|
public virtual DbSet<Page> Page { get; set; }
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Oqtane.Infrastructure;
|
||||||
|
|
||||||
|
namespace Oqtane.Repository
|
||||||
|
{
|
||||||
|
public interface IDBContextDependencies
|
||||||
|
{
|
||||||
|
ITenantManager TenantManager { get; }
|
||||||
|
IHttpContextAccessor Accessor { get; }
|
||||||
|
IConfigurationRoot Config { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ namespace Oqtane.Repository
|
||||||
|
|
||||||
IDataReader ExecuteReader(Tenant tenant, string query);
|
IDataReader ExecuteReader(Tenant tenant, string query);
|
||||||
|
|
||||||
|
IDataReader ExecuteReader(string DBType, string DBConnectionString, string query);
|
||||||
|
|
||||||
string GetScriptFromAssembly(Assembly assembly, string fileName);
|
string GetScriptFromAssembly(Assembly assembly, string fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
using Oqtane.Databases.Interfaces;
|
using Oqtane.Databases.Interfaces;
|
||||||
using Oqtane.Interfaces;
|
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
// ReSharper disable ConvertToUsingDeclaration
|
// ReSharper disable ConvertToUsingDeclaration
|
||||||
// ReSharper disable InvertIf
|
// ReSharper disable InvertIf
|
||||||
|
@ -15,6 +14,13 @@ namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
public class SqlRepository : ISqlRepository
|
public class SqlRepository : ISqlRepository
|
||||||
{
|
{
|
||||||
|
private IConfigurationRoot _config;
|
||||||
|
|
||||||
|
public SqlRepository(IConfigurationRoot config)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
}
|
||||||
|
|
||||||
public void ExecuteScript(Tenant tenant, string script)
|
public void ExecuteScript(Tenant tenant, string script)
|
||||||
{
|
{
|
||||||
// execute script in current tenant
|
// execute script in current tenant
|
||||||
|
@ -75,13 +81,19 @@ namespace Oqtane.Repository
|
||||||
public IDataReader ExecuteReader(Tenant tenant, string query)
|
public IDataReader ExecuteReader(Tenant tenant, string query)
|
||||||
{
|
{
|
||||||
var db = GetActiveDatabase(tenant.DBType);
|
var db = GetActiveDatabase(tenant.DBType);
|
||||||
return db.ExecuteReader(tenant.DBConnectionString, query);
|
return db.ExecuteReader(GetConnectionString(tenant.DBConnectionString), query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDataReader ExecuteReader(string DBType, string DBConnectionString, string query)
|
||||||
|
{
|
||||||
|
var db = GetActiveDatabase(DBType);
|
||||||
|
return db.ExecuteReader(GetConnectionString(DBConnectionString), query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ExecuteNonQuery(string connectionString, string databaseType, string query)
|
public int ExecuteNonQuery(string connectionString, string databaseType, string query)
|
||||||
{
|
{
|
||||||
var db = GetActiveDatabase(databaseType);
|
var db = GetActiveDatabase(databaseType);
|
||||||
return db.ExecuteNonQuery(connectionString, query);
|
return db.ExecuteNonQuery(GetConnectionString(connectionString), query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetScriptFromAssembly(Assembly assembly, string fileName)
|
public string GetScriptFromAssembly(Assembly assembly, string fileName)
|
||||||
|
@ -119,5 +131,14 @@ namespace Oqtane.Repository
|
||||||
|
|
||||||
return activeDatabase;
|
return activeDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetConnectionString(string connectionString)
|
||||||
|
{
|
||||||
|
if (!connectionString.Contains("="))
|
||||||
|
{
|
||||||
|
connectionString = _config.GetConnectionString(connectionString);
|
||||||
|
}
|
||||||
|
return connectionString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace Oqtane
|
||||||
//add possibility to switch off swagger on production.
|
//add possibility to switch off swagger on production.
|
||||||
_useSwagger = Configuration.GetSection("UseSwagger").Value != "false";
|
_useSwagger = Configuration.GetSection("UseSwagger").Value != "false";
|
||||||
|
|
||||||
AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(env.ContentRootPath, "Data"));
|
AppDomain.CurrentDomain.SetData(Constants.DataDirectory, Path.Combine(env.ContentRootPath, "Data"));
|
||||||
|
|
||||||
_env = env;
|
_env = env;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,25 +12,23 @@ namespace [Owner].[Module].Manager
|
||||||
{
|
{
|
||||||
public class [Module]Manager : MigratableModuleBase, IInstallable, IPortable
|
public class [Module]Manager : MigratableModuleBase, IInstallable, IPortable
|
||||||
{
|
{
|
||||||
private I[Module]Repository _[Module]Repository;
|
private readonly I[Module]Repository _[Module]Repository;
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly IDBContextDependencies _DBContextDependencies;
|
||||||
private readonly IHttpContextAccessor _accessor;
|
|
||||||
|
|
||||||
public [Module]Manager(I[Module]Repository [Module]Repository, ITenantManager tenantManager, IHttpContextAccessor accessor)
|
public [Module]Manager(I[Module]Repository [Module]Repository, IDBContextDependencies DBContextDependencies)
|
||||||
{
|
{
|
||||||
_[Module]Repository = [Module]Repository;
|
_[Module]Repository = [Module]Repository;
|
||||||
_tenantManager = tenantManager;
|
_DBContextDependencies = DBContextDependencies;
|
||||||
_accessor = accessor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Install(Tenant tenant, string version)
|
public bool Install(Tenant tenant, string version)
|
||||||
{
|
{
|
||||||
return Migrate(new [Module]Context(_tenantManager, _accessor), tenant, MigrationType.Up);
|
return Migrate(new [Module]Context(_DBContextDependencies), tenant, MigrationType.Up);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Uninstall(Tenant tenant)
|
public bool Uninstall(Tenant tenant)
|
||||||
{
|
{
|
||||||
return Migrate(new [Module]Context(_tenantManager, _accessor), tenant, MigrationType.Down);
|
return Migrate(new [Module]Context(_DBContextDependencies), tenant, MigrationType.Down);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ExportModule(Module module)
|
public string ExportModule(Module module)
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace [Owner].[Module].Repository
|
||||||
{
|
{
|
||||||
public virtual DbSet<Models.[Module]> [Module] { get; set; }
|
public virtual DbSet<Models.[Module]> [Module] { get; set; }
|
||||||
|
|
||||||
public [Module]Context(ITenantManager tenantManager, IHttpContextAccessor accessor) : base(tenantManager, accessor)
|
public [Module]Context(IDBContextDependencies DBContextDependencies) : base(DBContextDependencies) { }
|
||||||
{
|
{
|
||||||
// ContextBase handles multi-tenant database connections
|
// ContextBase handles multi-tenant database connections
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ namespace Oqtane.Models
|
||||||
/// Reference to the <see cref="Tenant"/> this belongs to
|
/// Reference to the <see cref="Tenant"/> this belongs to
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int TenantId { get; set; }
|
public int TenantId { get; set; }
|
||||||
|
public string DBType { get; set; }
|
||||||
|
public string DBConnectionString { get; set; }
|
||||||
public string Query { get; set; }
|
public string Query { get; set; }
|
||||||
public List<Dictionary<string, string>> Results { get; set; }
|
public List<Dictionary<string, string>> Results { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace Oqtane.Shared
|
||||||
public const string UpdaterPackageId = "Oqtane.Updater";
|
public const string UpdaterPackageId = "Oqtane.Updater";
|
||||||
public const string PackageRegistryUrl = "https://www.oqtane.net";
|
public const string PackageRegistryUrl = "https://www.oqtane.net";
|
||||||
|
|
||||||
|
public const string DataDirectory = "DataDirectory";
|
||||||
public const string DefaultDBType = "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer";
|
public const string DefaultDBType = "Oqtane.Database.SqlServer.SqlServerDatabase, Oqtane.Database.SqlServer";
|
||||||
|
|
||||||
public const string PageComponent = "Oqtane.UI.ThemeBuilder, Oqtane.Client";
|
public const string PageComponent = "Oqtane.UI.ThemeBuilder, Oqtane.Client";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user