326 lines
10 KiB
Plaintext
326 lines
10 KiB
Plaintext
@namespace Oqtane.Modules.Admin.Sql
|
|
@inherits ModuleBase
|
|
@inject NavigationManager NavigationManager
|
|
@inject ISystemService SystemService
|
|
@inject ITenantService TenantService
|
|
@inject IDatabaseService DatabaseService
|
|
@inject ISqlService SqlService
|
|
@inject IStringLocalizer<Index> Localizer
|
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
|
|
|
@if (_tenants == null)
|
|
{
|
|
<p><em>@SharedLocalizer["Loading"]</em></p>
|
|
}
|
|
else
|
|
{
|
|
<div class="container">
|
|
<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>
|
|
<div class="col-sm-9">
|
|
<select id="tenant" class="form-select" value="@_connection" @onchange="(e => ConnectionChanged(e))">
|
|
<option value="-"><@Localizer["Connection.Select"]></option>
|
|
<option value="+"><@Localizer["Connection.Add"]></option>
|
|
@foreach (var connection in _connections)
|
|
{
|
|
<option value="@connection.Key">@connection.Key</option>
|
|
}
|
|
</select>
|
|
</div>
|
|
</div>
|
|
@if (_connection == "+")
|
|
{
|
|
<div class="row mb-1 align-items-center">
|
|
<Label Class="col-sm-3" For="name" HelpText="Enter the name of the connection" ResourceKey="Name">Name: </Label>
|
|
<div class="col-sm-9">
|
|
<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="databasetype" HelpText="Select the database type" ResourceKey="DatabaseType">Type: </Label>
|
|
<div class="col-sm-9">
|
|
@if (_databases != null)
|
|
{
|
|
<div class="input-group">
|
|
<select id="databasetype" class="form-select" value="@_databasetype" @onchange="(e => DatabaseTypeChanged(e))" required>
|
|
@foreach (var database in _databases)
|
|
{
|
|
<option value="@database.Name">@Localizer[@database.Name]</option>
|
|
}
|
|
</select>
|
|
@if (!_showConnectionString)
|
|
{
|
|
<button type="button" class="btn btn-secondary" @onclick="ShowConnectionString">@Localizer["EnterConnectionString"]</button>
|
|
}
|
|
else
|
|
{
|
|
<button type="button" class="btn btn-secondary" @onclick="ShowConnectionString">@Localizer["EnterConnectionParameters"]</button>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
@if (!_showConnectionString)
|
|
{
|
|
if (_databaseConfigType != null)
|
|
{
|
|
@DatabaseConfigComponent
|
|
}
|
|
}
|
|
else
|
|
{
|
|
<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>
|
|
<div class="col-sm-9">
|
|
<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 != "-")
|
|
{
|
|
@if (!string.IsNullOrEmpty(_tenant))
|
|
{
|
|
<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">
|
|
<input id="databasetype" class="form-control" @bind="@_databasetype" readonly />
|
|
</div>
|
|
</div>
|
|
<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 {
|
|
private string _connection = "-";
|
|
private Dictionary<string, object> _connections;
|
|
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 _connectionstringtype = "password";
|
|
private string _connectionstringtoggle = string.Empty;
|
|
private string _sql = string.Empty;
|
|
private List<Dictionary<string, string>> _results;
|
|
|
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
try
|
|
{
|
|
_connections = await SystemService.GetSystemInfoAsync("connectionstrings");
|
|
_tenants = await TenantService.GetTenantsAsync();
|
|
_databases = await DatabaseService.GetDatabasesAsync();
|
|
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await logger.LogError(ex, "Error Loading Tenants {Error}", ex.Message);
|
|
AddModuleMessage(ex.Message, MessageType.Error);
|
|
}
|
|
}
|
|
|
|
private async void ConnectionChanged(ChangeEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
_connection = (string)e.Value;
|
|
if (_connection != "-" && _connection != "+")
|
|
{
|
|
_connectionstring = _connections[_connection].ToString();
|
|
_tenant = "";
|
|
_databasetype = "";
|
|
var tenant = _tenants.FirstOrDefault(item => item.DBConnectionString == _connection);
|
|
if (tenant != null)
|
|
{
|
|
_tenant = tenant.Name;
|
|
_databasetype = _databases.FirstOrDefault(item => item.DBType == tenant.DBType && item.Name != "LocalDB").Name;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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()
|
|
{
|
|
if (_connectionstringtype == "password")
|
|
{
|
|
_connectionstringtype = "text";
|
|
_connectionstringtoggle = SharedLocalizer["HidePassword"];
|
|
}
|
|
else
|
|
{
|
|
_connectionstringtype = "password";
|
|
_connectionstringtoggle = SharedLocalizer["ShowPassword"];
|
|
}
|
|
}
|
|
|
|
private async Task Execute()
|
|
{
|
|
try
|
|
{
|
|
if (_databasetype != "-" && !string.IsNullOrEmpty(_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);
|
|
_results = sqlquery.Results;
|
|
AddModuleMessage(Localizer["Success.QueryExecuted"], MessageType.Success);
|
|
}
|
|
else
|
|
{
|
|
AddModuleMessage(Localizer["Message.Required.Tenant"], MessageType.Warning);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await logger.LogError(ex, "Error Executing SQL Query {SQL} {Error}", _sql, ex.Message);
|
|
AddModuleMessage(ex.Message, MessageType.Error);
|
|
}
|
|
}
|
|
}
|