Files
Umbraco-CMS/src/Umbraco.Infrastructure/Install/InstallHelper.cs
Bjarke Berg ce47281c04 Determine correct if we can create a database with current connectionstring (#14030)
* Fix CanForceCreateDatabase method and add some unit tests

* Fixed an old copy/paste error

* A little nitpicking over wording and formatting

---------

Co-authored-by: kjac <kja@umbraco.dk>
2023-03-31 11:44:56 +02:00

171 lines
7.5 KiB
C#

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Install.Models;
using Umbraco.Cms.Core.Net;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Web;
using Umbraco.Cms.Infrastructure.Migrations.Install;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Web.Common.DependencyInjection;
using Umbraco.Extensions;
using Umbraco.Cms.Infrastructure.Persistence;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Infrastructure.Install
{
public sealed class InstallHelper
{
private readonly DatabaseBuilder _databaseBuilder;
private readonly ILogger<InstallHelper> _logger;
private readonly IUmbracoVersion _umbracoVersion;
private readonly IOptionsMonitor<ConnectionStrings> _connectionStrings;
private readonly IInstallationService _installationService;
private readonly ICookieManager _cookieManager;
private readonly IUserAgentProvider _userAgentProvider;
private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory;
private readonly IFireAndForgetRunner _fireAndForgetRunner;
private readonly IEnumerable<IDatabaseProviderMetadata> _databaseProviderMetadata;
private InstallationType? _installationType;
public InstallHelper(DatabaseBuilder databaseBuilder,
ILogger<InstallHelper> logger,
IUmbracoVersion umbracoVersion,
IOptionsMonitor<ConnectionStrings> connectionStrings,
IInstallationService installationService,
ICookieManager cookieManager,
IUserAgentProvider userAgentProvider,
IUmbracoDatabaseFactory umbracoDatabaseFactory,
IFireAndForgetRunner fireAndForgetRunner,
IEnumerable<IDatabaseProviderMetadata> databaseProviderMetadata)
{
_logger = logger;
_umbracoVersion = umbracoVersion;
_databaseBuilder = databaseBuilder;
_connectionStrings = connectionStrings;
_installationService = installationService;
_cookieManager = cookieManager;
_userAgentProvider = userAgentProvider;
_umbracoDatabaseFactory = umbracoDatabaseFactory;
_fireAndForgetRunner = fireAndForgetRunner;
_databaseProviderMetadata = databaseProviderMetadata;
// We need to initialize the type already, as we can't detect later, if the connection string is added on the fly.
GetInstallationType();
}
[Obsolete("Please use constructor that takes an IEnumerable<IDatabaseProviderMetadata> instead, scheduled for removal in Umbraco 12")]
public InstallHelper(
DatabaseBuilder databaseBuilder,
ILogger<InstallHelper> logger,
IUmbracoVersion umbracoVersion,
IOptionsMonitor<ConnectionStrings> connectionStrings,
IInstallationService installationService,
ICookieManager cookieManager,
IUserAgentProvider userAgentProvider,
IUmbracoDatabaseFactory umbracoDatabaseFactory,
IFireAndForgetRunner fireAndForgetRunner)
: this(
databaseBuilder,
logger,
umbracoVersion,
connectionStrings,
installationService,
cookieManager,
userAgentProvider,
umbracoDatabaseFactory,
fireAndForgetRunner,
StaticServiceProvider.Instance.GetRequiredService<IEnumerable<IDatabaseProviderMetadata>>()
)
{
}
[Obsolete("Please use constructor that takes an IFireAndForgetRunner and IEnumerable<IDatabaseProviderMetadata> instead, scheduled for removal in Umbraco 12")]
public InstallHelper(
DatabaseBuilder databaseBuilder,
ILogger<InstallHelper> logger,
IUmbracoVersion umbracoVersion,
IOptionsMonitor<ConnectionStrings> connectionStrings,
IInstallationService installationService,
ICookieManager cookieManager,
IUserAgentProvider userAgentProvider,
IUmbracoDatabaseFactory umbracoDatabaseFactory)
: this(
databaseBuilder,
logger,
umbracoVersion,
connectionStrings,
installationService,
cookieManager,
userAgentProvider,
umbracoDatabaseFactory,
StaticServiceProvider.Instance.GetRequiredService<IFireAndForgetRunner>(),
StaticServiceProvider.Instance.GetRequiredService<IEnumerable<IDatabaseProviderMetadata>>())
{
}
public InstallationType GetInstallationType() => _installationType ??= IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade;
public async Task SetInstallStatusAsync(bool isCompleted, string errorMsg)
{
try
{
var userAgent = _userAgentProvider.GetUserAgent();
// Check for current install ID
var installCookie = _cookieManager.GetCookieValue(Constants.Web.InstallerCookieName);
if (!Guid.TryParse(installCookie, out Guid installId))
{
installId = Guid.NewGuid();
_cookieManager.SetCookieValue(Constants.Web.InstallerCookieName, installId.ToString());
}
var dbProvider = string.Empty;
if (IsBrandNewInstall == false)
{
// we don't have DatabaseProvider anymore... doing it differently
//dbProvider = ApplicationContext.Current.DatabaseContext.DatabaseProvider.ToString();
dbProvider = _umbracoDatabaseFactory.SqlContext.SqlSyntax.DbProvider;
}
var installLog = new InstallLog(
installId: installId,
isUpgrade: IsBrandNewInstall == false,
installCompleted: isCompleted,
timestamp: DateTime.Now,
versionMajor: _umbracoVersion.Version.Major,
versionMinor: _umbracoVersion.Version.Minor,
versionPatch: _umbracoVersion.Version.Build,
versionComment: _umbracoVersion.Comment,
error: errorMsg,
userAgent: userAgent,
dbProvider: dbProvider);
_fireAndForgetRunner.RunFireAndForget(() => _installationService.LogInstall(installLog));
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred in InstallStatus trying to check upgrades");
}
}
/// <summary>
/// Checks if this is a brand new install, meaning that there is no configured database connection or the database is empty.
/// </summary>
/// <value>
/// <c>true</c> if this is a brand new install; otherwise, <c>false</c>.
/// </value>
private bool IsBrandNewInstall =>
_connectionStrings.CurrentValue.IsConnectionStringConfigured() == false ||
_databaseBuilder.IsDatabaseConfigured == false ||
(_databaseBuilder.CanConnectToDatabase == false && _databaseProviderMetadata.CanForceCreateDatabase(_umbracoDatabaseFactory)) ||
_databaseBuilder.IsUmbracoInstalled() == false;
}
}