using System.Globalization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; using Newtonsoft.Json; using Nop.Core; using Nop.Core.Caching; using Nop.Core.Configuration; using Nop.Core.Infrastructure; using Nop.Data; using Nop.Data.Configuration; using Nop.Services.Common; using Nop.Services.Installation; using Nop.Services.Plugins; using Nop.Services.Security; using Nop.Web.Framework.Security; using Nop.Web.Infrastructure.Installation; using Nop.Web.Models.Install; namespace Nop.Web.Controllers; [AutoValidateAntiforgeryToken] public partial class InstallController : Controller { #region Fields protected readonly AppSettings _appSettings; protected readonly Lazy _locService; protected readonly Lazy _installationService; protected readonly INopFileProvider _fileProvider; protected readonly Lazy _permissionService; protected readonly Lazy _pluginService; protected readonly Lazy _staticCacheManager; protected readonly Lazy _uploadService; protected readonly Lazy _webHelper; protected readonly Lazy _nopHttpClient; #endregion #region Ctor public InstallController(AppSettings appSettings, Lazy locService, Lazy installationService, INopFileProvider fileProvider, Lazy permissionService, Lazy pluginService, Lazy staticCacheManager, Lazy uploadService, Lazy webHelper, Lazy nopHttpClient) { _appSettings = appSettings; _locService = locService; _installationService = installationService; _fileProvider = fileProvider; _permissionService = permissionService; _pluginService = pluginService; _staticCacheManager = staticCacheManager; _uploadService = uploadService; _webHelper = webHelper; _nopHttpClient = nopHttpClient; } #endregion #region Utilites protected virtual InstallModel PrepareCountryList(InstallModel model) { if (!model.InstallRegionalResources) return model; var browserCulture = _locService.Value.GetBrowserCulture(); var countries = new List { //This item was added in case it was not possible to automatically determine the country by culture new() { Value = string.Empty, Text = _locService.Value.GetResource("CountrySelect") } }; countries.AddRange(from country in ISO3166.GetCollection() from localization in ISO3166.GetLocalizationInfo(country.Alpha2) let lang = ISO3166.GetLocalizationInfo(country.Alpha2).Count() > 1 ? $" [{localization.Language} language]" : string.Empty let item = new SelectListItem { Value = $"{country.Alpha2}-{localization.Culture}", Text = $"{country.Name}{lang}", Selected = (localization.Culture == browserCulture) && browserCulture[^2..] == country.Alpha2 } select item); model.AvailableCountries.AddRange(countries); return model; } protected virtual InstallModel PrepareLanguageList(InstallModel model) { foreach (var lang in _locService.Value.GetAvailableLanguages()) { model.AvailableLanguages.Add(new SelectListItem { Value = Url.RouteUrl("InstallationChangeLanguage", new { language = lang.Code }), Text = lang.Name, Selected = _locService.Value.GetCurrentLanguage().Code == lang.Code }); } return model; } protected virtual InstallModel PrepareAvailableDataProviders(InstallModel model) { model.AvailableDataProviders.AddRange( _locService.Value.GetAvailableProviderTypes() .OrderBy(v => v.Value) .Select(pt => new SelectListItem { Value = pt.Key.ToString(), Text = pt.Value })); return model; } #endregion #region Methods public virtual IActionResult Index() { if (DataSettingsManager.IsDatabaseInstalled()) return RedirectToRoute("Homepage"); var model = new InstallModel { AdminEmail = "admin@yourStore.com", InstallSampleData = false, SubscribeNewsletters = true, InstallRegionalResources = _appSettings.Get().InstallRegionalResources, DisableSampleDataOption = _appSettings.Get().DisableSampleData, CreateDatabaseIfNotExists = false, ConnectionStringRaw = false, DataProvider = DataProviderType.SqlServer }; PrepareAvailableDataProviders(model); PrepareLanguageList(model); PrepareCountryList(model); return View(model); } [HttpPost] public virtual async Task Index(InstallModel model) { if (DataSettingsManager.IsDatabaseInstalled()) return RedirectToRoute("Homepage"); model.DisableSampleDataOption = _appSettings.Get().DisableSampleData; model.InstallRegionalResources = _appSettings.Get().InstallRegionalResources; PrepareAvailableDataProviders(model); PrepareLanguageList(model); PrepareCountryList(model); //Consider granting access rights to the resource to the ASP.NET request identity. //ASP.NET has a base process identity //(typically {MACHINE}\ASPNET on IIS 5 or Network Service on IIS 6 and IIS 7, //and the configured application pool identity on IIS 7.5) that is used if the application is not impersonating. //If the application is impersonating via , //the identity will be the anonymous user (typically IUSR_MACHINENAME) or the authenticated request user. //validate permissions var dirsToCheck = _fileProvider.GetDirectoriesWrite(); foreach (var dir in dirsToCheck) if (!_fileProvider.CheckPermissions(dir, false, true, true, false)) ModelState.AddModelError(string.Empty, string.Format(_locService.Value.GetResource("ConfigureDirectoryPermissions"), CurrentOSUser.FullName, dir)); var filesToCheck = _fileProvider.GetFilesWrite(); foreach (var file in filesToCheck) { if (!_fileProvider.FileExists(file)) continue; if (!_fileProvider.CheckPermissions(file, false, true, true, true)) ModelState.AddModelError(string.Empty, string.Format(_locService.Value.GetResource("ConfigureFilePermissions"), CurrentOSUser.FullName, file)); } if (!ModelState.IsValid) return View(model); try { var dataProvider = DataProviderManager.GetDataProvider(model.DataProvider); var connectionString = model.ConnectionStringRaw ? model.ConnectionString : dataProvider.BuildConnectionString(model); if (string.IsNullOrEmpty(connectionString)) throw new Exception(_locService.Value.GetResource("ConnectionStringWrongFormat")); DataSettingsManager.SaveSettings(new DataConfig { DataProvider = model.DataProvider, ConnectionString = connectionString }, _fileProvider); if (model.CreateDatabaseIfNotExists && !await dataProvider.DatabaseExistsAsync()) { try { dataProvider.CreateDatabase(model.Collation); } catch (Exception ex) { throw new Exception(string.Format(_locService.Value.GetResource("DatabaseCreationError"), ex.Message)); } } else { //check whether database exists if (!await dataProvider.DatabaseExistsAsync()) throw new Exception(_locService.Value.GetResource("DatabaseNotExists")); } dataProvider.InitializeDatabase(); if (model.SubscribeNewsletters) { try { var resultRequest = await _nopHttpClient.Value.SubscribeNewslettersAsync(model.AdminEmail); } catch { // ignored } } var cultureInfo = new CultureInfo(NopCommonDefaults.DefaultLanguageCulture); var regionInfo = new RegionInfo(NopCommonDefaults.DefaultLanguageCulture); var languagePackInfo = (DownloadUrl: string.Empty, Progress: 0); if (model.InstallRegionalResources) { //try to get CultureInfo and RegionInfo if (model.Country != null) try { cultureInfo = new CultureInfo(model.Country[3..]); regionInfo = new RegionInfo(model.Country[3..]); } catch { // ignored } //get URL to download language pack if (cultureInfo.Name != NopCommonDefaults.DefaultLanguageCulture) { try { var languageCode = _locService.Value.GetCurrentLanguage().Code[0..2]; var resultString = await _nopHttpClient.Value.InstallationCompletedAsync(model.AdminEmail, languageCode, cultureInfo.Name); var result = JsonConvert.DeserializeAnonymousType(resultString, new { Message = string.Empty, LanguagePack = new { Culture = string.Empty, Progress = 0, DownloadLink = string.Empty } }); if (result != null && result.LanguagePack.Progress > NopCommonDefaults.LanguagePackMinTranslationProgressToInstall) { languagePackInfo.DownloadUrl = result.LanguagePack.DownloadLink; languagePackInfo.Progress = result.LanguagePack.Progress; } } catch { // ignored } } //upload CLDR await _uploadService.Value.UploadLocalePatternAsync(cultureInfo); } //now resolve installation service await _installationService.Value.InstallRequiredDataAsync(model.AdminEmail, model.AdminPassword, languagePackInfo, regionInfo, cultureInfo); if (model.InstallSampleData) await _installationService.Value.InstallSampleDataAsync(model.AdminEmail); //prepare plugins to install _pluginService.Value.ClearInstalledPluginsList(); var pluginsIgnoredDuringInstallation = new List(); if (!string.IsNullOrEmpty(_appSettings.Get().DisabledPlugins)) { pluginsIgnoredDuringInstallation = _appSettings.Get().DisabledPlugins .Split(',', StringSplitOptions.RemoveEmptyEntries).Select(pluginName => pluginName.Trim()).ToList(); } var plugins = (await _pluginService.Value.GetPluginDescriptorsAsync(LoadPluginsMode.All)) .Where(pluginDescriptor => !pluginsIgnoredDuringInstallation.Contains(pluginDescriptor.SystemName)) .OrderBy(pluginDescriptor => pluginDescriptor.Group).ThenBy(pluginDescriptor => pluginDescriptor.DisplayOrder) .ToList(); foreach (var plugin in plugins) { await _pluginService.Value.PreparePluginToInstallAsync(plugin.SystemName, checkDependencies: false); } //register default permissions var permissionProviders = new List { typeof(StandardPermissionProvider) }; foreach (var providerType in permissionProviders) { var provider = (IPermissionProvider)Activator.CreateInstance(providerType); await _permissionService.Value.InstallPermissionsAsync(provider); } return View(new InstallModel { RestartUrl = Url.RouteUrl("Homepage") }); } catch (Exception exception) { await _staticCacheManager.Value.ClearAsync(); //clear provider settings if something got wrong DataSettingsManager.SaveSettings(new DataConfig(), _fileProvider); ModelState.AddModelError(string.Empty, string.Format(_locService.Value.GetResource("SetupFailed"), exception.Message)); } return View(model); } public virtual IActionResult ChangeLanguage(string language) { if (DataSettingsManager.IsDatabaseInstalled()) return RedirectToRoute("Homepage"); _locService.Value.SaveCurrentLanguage(language); //Reload the page return RedirectToAction("Index", "Install"); } [HttpPost] public virtual IActionResult RestartInstall() { if (DataSettingsManager.IsDatabaseInstalled()) return RedirectToRoute("Homepage"); return View("Index", new InstallModel { RestartUrl = Url.RouteUrl("Installation") }); } public virtual IActionResult RestartApplication() { if (DataSettingsManager.IsDatabaseInstalled()) return RedirectToRoute("Homepage"); //restart application _webHelper.Value.RestartAppDomain(); return new EmptyResult(); } #endregion }