("SELECT COUNT(*) FROM umbracoUser");
has = result != 1;
}
scope.Complete();
return has;
}
}
internal bool IsUmbracoInstalled()
{
using (var scope = _scopeProvider.CreateScope(autoComplete: true))
{
return _scopeAccessor.AmbientScope?.Database.IsUmbracoInstalled() ?? false;
}
}
#endregion
#region Configure Connection String
public bool ConfigureDatabaseConnection(DatabaseModel databaseSettings, bool isTrialRun)
{
IDatabaseProviderMetadata? providerMeta;
// if the database model is null then we will attempt quick install.
if (databaseSettings == null)
{
providerMeta = _databaseProviderMetadata
.OrderBy(x => x.SortOrder)
.Where(x => x.SupportsQuickInstall)
.FirstOrDefault(x => x.IsAvailable);
databaseSettings = new DatabaseModel
{
DatabaseName = providerMeta?.DefaultDatabaseName!,
};
}
else
{
providerMeta = _databaseProviderMetadata
.FirstOrDefault(x => x.Id == databaseSettings.DatabaseProviderMetadataId);
}
if (providerMeta == null)
{
throw new InstallException("Unable to determine database provider configuration.");
}
var connectionString = providerMeta.GenerateConnectionString(databaseSettings);
var providerName = databaseSettings.ProviderName ?? providerMeta.ProviderName;
if (providerMeta.RequiresConnectionTest && !CanConnect(connectionString, providerName!))
{
return false;
}
if (!isTrialRun)
{
_configManipulator.SaveConnectionString(connectionString!, providerName);
Configure(connectionString!, providerName, _globalSettings.CurrentValue.InstallMissingDatabase || providerMeta.ForceCreateDatabase);
}
return true;
}
private void Configure(string connectionString, string? providerName, bool installMissingDatabase)
{
// Update existing connection string
var umbracoConnectionString = _connectionStrings.Get(Core.Constants.System.UmbracoConnectionName);
umbracoConnectionString.ConnectionString = connectionString;
umbracoConnectionString.ProviderName = providerName;
_databaseFactory.Configure(umbracoConnectionString);
if (installMissingDatabase)
{
CreateDatabase();
}
}
#endregion
#region Database Schema
public void CreateDatabase() => _dbProviderFactoryCreator.CreateDatabase(_databaseFactory.ProviderName!, _databaseFactory.ConnectionString!);
///
/// Validates the database schema.
///
///
/// This assumes that the database exists and the connection string is
/// configured and it is possible to connect to the database.
///
public DatabaseSchemaResult? ValidateSchema()
{
using (var scope = _scopeProvider.CreateScope())
{
var result = ValidateSchema(scope);
scope.Complete();
return result;
}
}
private DatabaseSchemaResult? ValidateSchema(IScope scope)
{
if (_databaseFactory.Initialized == false)
return new DatabaseSchemaResult();
if (_databaseSchemaValidationResult != null)
return _databaseSchemaValidationResult;
_databaseSchemaValidationResult = _scopeAccessor.AmbientScope?.Database.ValidateSchema();
scope.Complete();
return _databaseSchemaValidationResult;
}
///
/// Creates the database schema and inserts initial data.
///
///
/// This assumes that the database exists and the connection string is
/// configured and it is possible to connect to the database.
///
public Result? CreateSchemaAndData()
{
using (var scope = _scopeProvider.CreateScope())
{
var result = CreateSchemaAndData(scope);
scope.Complete();
return result;
}
}
private Result? CreateSchemaAndData(IScope scope)
{
try
{
var readyForInstall = CheckReadyForInstall();
if (readyForInstall.Success == false)
{
return readyForInstall.Result;
}
_logger.LogInformation("Database configuration status: Started");
var database = _scopeAccessor.AmbientScope?.Database;
var message = string.Empty;
var schemaResult = ValidateSchema();
var hasInstalledVersion = schemaResult?.DetermineHasInstalledVersion() ?? false;
//If the determined version is "empty" its a new install - otherwise upgrade the existing
if (!hasInstalledVersion)
{
if (_runtimeState.Level == RuntimeLevel.Run)
throw new Exception("Umbraco is already configured!");
var creator = _databaseSchemaCreatorFactory.Create(database);
creator.InitializeDatabaseSchema();
message = message + "Installation completed!
";
//now that everything is done, we need to determine the version of SQL server that is executing
_logger.LogInformation("Database configuration status: {DbConfigStatus}", message);
return new Result { Message = message, Success = true, Percentage = "100" };
}
//we need to do an upgrade so return a new status message and it will need to be done during the next step
_logger.LogInformation("Database requires upgrade");
message = "Upgrading database, this may take some time...
";
return new Result
{
RequiresUpgrade = true,
Message = message,
Success = true,
Percentage = "30"
};
}
catch (Exception ex)
{
return HandleInstallException(ex);
}
}
///
/// Upgrades the database schema and data by running migrations.
///
///
/// This assumes that the database exists and the connection string is
/// configured and it is possible to connect to the database.
/// Runs whichever migrations need to run.
///
public Result? UpgradeSchemaAndData(UmbracoPlan plan)
{
try
{
var readyForInstall = CheckReadyForInstall();
if (readyForInstall.Success == false)
{
return readyForInstall.Result;
}
_logger.LogInformation("Database upgrade started");
// upgrade
var upgrader = new Upgrader(plan);
upgrader.Execute(_migrationPlanExecutor, _scopeProvider, _keyValueService);
var message = "Upgrade completed!
";
//now that everything is done, we need to determine the version of SQL server that is executing
_logger.LogInformation("Database configuration status: {DbConfigStatus}", message);
return new Result { Message = message, Success = true, Percentage = "100" };
}
catch (Exception ex)
{
return HandleInstallException(ex);
}
}
private Attempt CheckReadyForInstall()
{
if (_databaseFactory.CanConnect == false)
{
return Attempt.Fail(new Result
{
Message = "Database configuration is invalid. Please check that the entered database exists and"
+ " that the provided username and password has write access to the database.",
Success = false,
Percentage = "10"
});
}
return Attempt.Succeed();
}
private Result HandleInstallException(Exception ex)
{
_logger.LogError(ex, "Database configuration failed");
if (_databaseSchemaValidationResult != null)
{
_logger.LogInformation("The database schema validation produced the following summary: {DbSchemaSummary}", _databaseSchemaValidationResult.GetSummary());
}
return new Result
{
Message =
"The database configuration failed with the following message: " + ex.Message +
$"\n Please check log file for additional information (can be found in '{Constants.SystemDirectories.LogFiles}')",
Success = false,
Percentage = "90"
};
}
///
/// Represents the result of a database creation or upgrade.
///
public class Result
{
///
/// Gets or sets a value indicating whether an upgrade is required.
///
public bool RequiresUpgrade { get; set; }
///
/// Gets or sets the message returned by the operation.
///
public string? Message { get; set; }
///
/// Gets or sets a value indicating whether the operation succeeded.
///
public bool Success { get; set; }
///
/// Gets or sets an install progress pseudo-percentage.
///
public string? Percentage { get; set; }
}
#endregion
}
}