335 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			335 lines
		
	
	
		
			11 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 != "-")
 | 
						|
			{
 | 
						|
				<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 {
 | 
						|
	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).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);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |