diff --git a/src/Umbraco.Abstractions/Features/IUmbracoFeatureController.cs b/src/Umbraco.Abstractions/Features/IUmbracoFeature.cs similarity index 100% rename from src/Umbraco.Abstractions/Features/IUmbracoFeatureController.cs rename to src/Umbraco.Abstractions/Features/IUmbracoFeature.cs diff --git a/src/Umbraco.Abstractions/Install/FilePermissionDirectoryHelper.cs b/src/Umbraco.Abstractions/Install/FilePermissionDirectoryHelper.cs new file mode 100644 index 0000000000..bc57083cbd --- /dev/null +++ b/src/Umbraco.Abstractions/Install/FilePermissionDirectoryHelper.cs @@ -0,0 +1,39 @@ +using System; +using System.IO; +using Umbraco.Core.IO; + +namespace Umbraco.Web.Install +{ + public class FilePermissionDirectoryHelper + { + + + // tries to create a file + // if successful, the file is deleted + // creates the directory if needed - does not delete it + public static bool TryCreateDirectory(string dir, IIOHelper ioHelper) + { + try + { + var dirPath = ioHelper.MapPath(dir); + + if (Directory.Exists(dirPath) == false) + Directory.CreateDirectory(dirPath); + + var filePath = dirPath + "/" + CreateRandomFileName() + ".tmp"; + File.WriteAllText(filePath, "This is an Umbraco internal test file. It is safe to delete it."); + File.Delete(filePath); + return true; + } + catch + { + return false; + } + } + + public static string CreateRandomFileName() + { + return "umbraco-test." + Guid.NewGuid().ToString("N").Substring(0, 8); + } + } +} diff --git a/src/Umbraco.Abstractions/InstallLog.cs b/src/Umbraco.Abstractions/InstallLog.cs new file mode 100644 index 0000000000..cb14ebd650 --- /dev/null +++ b/src/Umbraco.Abstractions/InstallLog.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Umbraco.Core.Models +{ + public class InstallLog + { + public Guid InstallId { get; } + public bool IsUpgrade { get; set; } + public bool InstallCompleted { get; set; } + public DateTime Timestamp { get; set; } + public int VersionMajor { get; } + public int VersionMinor { get; } + public int VersionPatch { get; } + public string VersionComment { get; } + public string Error { get; } + public string UserAgent { get; } + public string DbProvider { get; set; } + + public InstallLog(Guid installId, bool isUpgrade, bool installCompleted, DateTime timestamp, int versionMajor, int versionMinor, int versionPatch, string versionComment, string error, string userAgent, string dbProvider) + { + InstallId = installId; + IsUpgrade = isUpgrade; + InstallCompleted = installCompleted; + Timestamp = timestamp; + VersionMajor = versionMajor; + VersionMinor = versionMinor; + VersionPatch = versionPatch; + VersionComment = versionComment; + Error = error; + UserAgent = userAgent; + DbProvider = dbProvider; + } + } +} diff --git a/src/Umbraco.Abstractions/Persistence/Repositories/IInstallationRepository.cs b/src/Umbraco.Abstractions/Persistence/Repositories/IInstallationRepository.cs new file mode 100644 index 0000000000..fbc7d2cfbc --- /dev/null +++ b/src/Umbraco.Abstractions/Persistence/Repositories/IInstallationRepository.cs @@ -0,0 +1,11 @@ +using System; +using System.Threading.Tasks; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Persistence.Repositories +{ + public interface IInstallationRepository + { + Task SaveInstallLogAsync(InstallLog installLog); + } +} diff --git a/src/Umbraco.Abstractions/Persistence/Repositories/IUpgradeCheckRepository.cs b/src/Umbraco.Abstractions/Persistence/Repositories/IUpgradeCheckRepository.cs new file mode 100644 index 0000000000..6d56994781 --- /dev/null +++ b/src/Umbraco.Abstractions/Persistence/Repositories/IUpgradeCheckRepository.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Semver; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Persistence.Repositories +{ + public interface IUpgradeCheckRepository + { + Task CheckUpgradeAsync(SemVersion version); + } +} diff --git a/src/Umbraco.Abstractions/Persistence/Repositories/InstallationRepository.cs b/src/Umbraco.Abstractions/Persistence/Repositories/InstallationRepository.cs new file mode 100644 index 0000000000..01c91fe051 --- /dev/null +++ b/src/Umbraco.Abstractions/Persistence/Repositories/InstallationRepository.cs @@ -0,0 +1,36 @@ +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core.Models; +using Umbraco.Core.Serialization; + +namespace Umbraco.Core.Persistence.Repositories.Implement +{ + public class InstallationRepository : IInstallationRepository + { + private readonly IJsonSerializer _jsonSerializer; + private static HttpClient _httpClient; + private const string RestApiInstallUrl = "https://our.umbraco.com/umbraco/api/Installation/Install"; + + public InstallationRepository(IJsonSerializer jsonSerializer) + { + _jsonSerializer = jsonSerializer; + } + + public async Task SaveInstallLogAsync(InstallLog installLog) + { + try + { + if (_httpClient == null) + _httpClient = new HttpClient(); + + var content = new StringContent(_jsonSerializer.Serialize(installLog), Encoding.UTF8, "application/json"); + + await _httpClient.PostAsync(RestApiInstallUrl, content); + } + // this occurs if the server for Our is down or cannot be reached + catch (HttpRequestException) + { } + } + } +} diff --git a/src/Umbraco.Abstractions/Persistence/Repositories/UpgradeCheckRepository.cs b/src/Umbraco.Abstractions/Persistence/Repositories/UpgradeCheckRepository.cs new file mode 100644 index 0000000000..b20c6d26b9 --- /dev/null +++ b/src/Umbraco.Abstractions/Persistence/Repositories/UpgradeCheckRepository.cs @@ -0,0 +1,58 @@ +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Semver; +using Umbraco.Core.Models; +using Umbraco.Core.Serialization; + +namespace Umbraco.Core.Persistence.Repositories.Implement +{ + public class UpgradeCheckRepository : IUpgradeCheckRepository + { + private readonly IJsonSerializer _jsonSerializer; + private static HttpClient _httpClient; + private const string RestApiUpgradeChecklUrl = "https://our.umbraco.com/umbraco/api/UpgradeCheck/CheckUpgrade"; + + public UpgradeCheckRepository(IJsonSerializer jsonSerializer) + { + _jsonSerializer = jsonSerializer; + } + + public async Task CheckUpgradeAsync(SemVersion version) + { + try + { + if (_httpClient == null) + _httpClient = new HttpClient(); + + var content = new StringContent(_jsonSerializer.Serialize(new CheckUpgradeDto(version)), Encoding.UTF8, "application/json"); + + var task = await _httpClient.PostAsync(RestApiUpgradeChecklUrl,content); + var json = await task.Content.ReadAsStringAsync(); + var result = _jsonSerializer.Deserialize(json); + + return result ?? new UpgradeResult("None", "", ""); + } + catch (HttpRequestException) + { + // this occurs if the server for Our is down or cannot be reached + return new UpgradeResult("None", "", ""); + } + } + private class CheckUpgradeDto + { + public CheckUpgradeDto(SemVersion version) + { + VersionMajor = version.Major; + VersionMinor = version.Minor; + VersionPatch = version.Patch; + VersionComment = version.Prerelease; + } + + public int VersionMajor { get; } + public int VersionMinor { get; } + public int VersionPatch { get; } + public string VersionComment { get; } + } + } +} diff --git a/src/Umbraco.Abstractions/Services/IUpgradeService.cs b/src/Umbraco.Abstractions/Services/IUpgradeService.cs new file mode 100644 index 0000000000..70bbb68085 --- /dev/null +++ b/src/Umbraco.Abstractions/Services/IUpgradeService.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Semver; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Services +{ + public interface IUpgradeService + { + Task CheckUpgrade(SemVersion version); + } +} diff --git a/src/Umbraco.Abstractions/Services/UpgradeService.cs b/src/Umbraco.Abstractions/Services/UpgradeService.cs new file mode 100644 index 0000000000..ead5270b41 --- /dev/null +++ b/src/Umbraco.Abstractions/Services/UpgradeService.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Semver; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Repositories; +using Umbraco.Core.Services; + +namespace Umbraco.Core +{ + public class UpgradeService : IUpgradeService + { + private readonly IUpgradeCheckRepository _upgradeCheckRepository; + + public UpgradeService(IUpgradeCheckRepository upgradeCheckRepository) + { + _upgradeCheckRepository = upgradeCheckRepository; + } + + public async Task CheckUpgrade(SemVersion version) + { + return await _upgradeCheckRepository.CheckUpgradeAsync(version); + } + } +} diff --git a/src/Umbraco.Abstractions/UpgradeResult.cs b/src/Umbraco.Abstractions/UpgradeResult.cs new file mode 100644 index 0000000000..a27f6bb6a3 --- /dev/null +++ b/src/Umbraco.Abstractions/UpgradeResult.cs @@ -0,0 +1,16 @@ +namespace Umbraco.Core.Models +{ + public class UpgradeResult + { + public string UpgradeType { get; } + public string Comment { get; } + public string UpgradeUrl { get; } + + public UpgradeResult(string upgradeType, string comment, string upgradeUrl) + { + UpgradeType = upgradeType; + Comment = comment; + UpgradeUrl = upgradeUrl; + } + } +} diff --git a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs index 0939dd0f71..61ff4ecb6d 100644 --- a/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs +++ b/src/Umbraco.Infrastructure/Composing/CompositionExtensions/Repositories.cs @@ -47,6 +47,8 @@ namespace Umbraco.Core.Composing.CompositionExtensions composition.RegisterUnique(); composition.RegisterUnique(); composition.RegisterUnique(); + composition.RegisterUnique(); + composition.RegisterUnique(); return composition; } diff --git a/src/Umbraco.Infrastructure/Models/DataType.cs b/src/Umbraco.Infrastructure/Models/DataType.cs index c237f6381c..299795f865 100644 --- a/src/Umbraco.Infrastructure/Models/DataType.cs +++ b/src/Umbraco.Infrastructure/Models/DataType.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Runtime.Serialization; using Newtonsoft.Json; using Umbraco.Core.Models.Entities; diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs index 04609b2821..fa991d6679 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/DataTypeFactory.cs @@ -1,25 +1,24 @@ using System; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; using Umbraco.Core.PropertyEditors; -using Umbraco.Core.Services; -using Umbraco.Core.Strings; - namespace Umbraco.Core.Persistence.Factories { internal static class DataTypeFactory { - public static IDataType BuildEntity(DataTypeDto dto, PropertyEditorCollection editors, ILogger logger, IIOHelper ioHelper, IDataTypeService dataTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) + public static IDataType BuildEntity(DataTypeDto dto, PropertyEditorCollection editors, ILogger logger) { + // Check we have an editor for the data type. if (!editors.TryGet(dto.EditorAlias, out var editor)) { - logger.Warn(typeof(DataType), "Could not find an editor with alias {EditorAlias}, treating as Label." - +" The site may fail to boot and / or load data types and run.", dto.EditorAlias); - //convert to label - editor = new LabelPropertyEditor(logger, ioHelper,dataTypeService , localizedTextService, localizationService, shortStringHelper); + logger.Warn(typeof(DataType), "Could not find an editor with alias {EditorAlias}, treating as Label. " + + "The site may fail to boot and/or load data types and run.", dto.EditorAlias); + + // Create as special type, which downstream can be handled by converting to a LabelPropertyEditor to make clear + // the situation to the user. + editor = new MissingPropertyEditor(); } var dataType = new DataType(editor); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs index 1f0d944c7e..42a89384d7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -7,7 +7,6 @@ using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; @@ -17,7 +16,6 @@ using Umbraco.Core.Persistence.Querying; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; using Umbraco.Core.Services; -using Umbraco.Core.Strings; using static Umbraco.Core.Persistence.SqlExtensionsStatics; namespace Umbraco.Core.Persistence.Repositories.Implement @@ -28,22 +26,11 @@ namespace Umbraco.Core.Persistence.Repositories.Implement internal class DataTypeRepository : NPocoRepositoryBase, IDataTypeRepository { private readonly Lazy _editors; - private readonly IIOHelper _ioHelper; - private readonly Lazy _dataTypeService; - private readonly ILocalizedTextService _localizedTextService; - private readonly ILocalizationService _localizationService; - private readonly IShortStringHelper _shortStringHelper; - // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4237 - get rid of Lazy injection and fix circular dependencies - public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy editors, ILogger logger, IIOHelper ioHelper, Lazy dataTypeService, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) + public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy editors, ILogger logger) : base(scopeAccessor, cache, logger) { _editors = editors; - _ioHelper = ioHelper; - _dataTypeService = dataTypeService; - _localizedTextService = localizedTextService; - _localizationService = localizationService; - _shortStringHelper = shortStringHelper; } #region Overrides of RepositoryBase @@ -67,7 +54,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } var dtos = Database.Fetch(dataTypeSql); - return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, Logger,_ioHelper, _dataTypeService.Value, _localizedTextService, _localizationService, _shortStringHelper)).ToArray(); + return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, Logger)).ToArray(); } protected override IEnumerable PerformGetByQuery(IQuery query) @@ -78,7 +65,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var dtos = Database.Fetch(sql); - return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, Logger, _ioHelper, _dataTypeService.Value, _localizedTextService, _localizationService, _shortStringHelper)).ToArray(); + return dtos.Select(x => DataTypeFactory.BuildEntity(x, _editors.Value, Logger)).ToArray(); } #endregion diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs index f3db5c5906..2f1b6c5814 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs @@ -543,6 +543,16 @@ ORDER BY colName"; } } + // If userlogin or the email has changed then need to reset security stamp + if (changedCols.Contains("userLogin") || changedCols.Contains("userEmail")) + { + userDto.EmailConfirmedDate = null; + userDto.SecurityStampToken = entity.SecurityStamp = Guid.NewGuid().ToString(); + + changedCols.Add("emailConfirmedDate"); + changedCols.Add("securityStampToken"); + } + //only update the changed cols if (changedCols.Count > 0) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MissingPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MissingPropertyEditor.cs new file mode 100644 index 0000000000..902aab7cc7 --- /dev/null +++ b/src/Umbraco.Infrastructure/PropertyEditors/MissingPropertyEditor.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +namespace Umbraco.Core.PropertyEditors +{ + /// + /// Represents a temporary representation of an editor for cases where a data type is created but not editor is available. + /// + public class MissingPropertyEditor : IDataEditor + { + public string Alias => "Umbraco.Missing"; + + public EditorType Type => EditorType.Nothing; + + public string Name => "Missing property editor"; + + public string Icon => string.Empty; + + public string Group => string.Empty; + + public bool IsDeprecated => false; + + public IDictionary DefaultConfiguration => throw new NotImplementedException(); + + public IPropertyIndexValueFactory PropertyIndexValueFactory => throw new NotImplementedException(); + + public IConfigurationEditor GetConfigurationEditor() + { + return new ConfigurationEditor(); + } + + public IDataValueEditor GetValueEditor() + { + throw new NotImplementedException(); + } + + public IDataValueEditor GetValueEditor(object configuration) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs index bb0b8b5e36..2586fcd9f5 100644 --- a/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs +++ b/src/Umbraco.Infrastructure/Runtime/CoreInitialComposer.cs @@ -19,11 +19,13 @@ using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Scoping; using Umbraco.Core.Serialization; using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; using Umbraco.Core.Strings; using Umbraco.Core.Sync; using Umbraco.Web.Models.PublishedContent; using Umbraco.Web.PublishedCache; using Umbraco.Web; +using Umbraco.Web.Migrations.PostMigrations; using Umbraco.Web.Install; using Umbraco.Web.Trees; using Umbraco.Web.PropertyEditors; @@ -147,8 +149,8 @@ namespace Umbraco.Core.Runtime // by default, register a noop factory composition.RegisterUnique(); - // by default, register a noop rebuilder - composition.RegisterUnique(); + // by default + composition.RegisterUnique(); composition.SetCultureDictionaryFactory(); composition.Register(f => f.GetInstance().CreateDictionary(), Lifetime.Singleton); @@ -164,6 +166,10 @@ namespace Umbraco.Core.Runtime // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards composition.Dashboards() .Add(composition.TypeLoader.GetTypes()); + + // will be injected in controllers when needed to invoke rest endpoints on Our + composition.RegisterUnique(); + composition.RegisterUnique(); } } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs index f9d0256568..08bed264ae 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/DataTypeService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; +using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; @@ -10,6 +11,7 @@ using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Scoping; +using Umbraco.Core.Strings; namespace Umbraco.Core.Services.Implement { @@ -23,10 +25,15 @@ namespace Umbraco.Core.Services.Implement private readonly IContentTypeRepository _contentTypeRepository; private readonly IAuditRepository _auditRepository; private readonly IEntityRepository _entityRepository; + private readonly IIOHelper _ioHelper; + private readonly ILocalizedTextService _localizedTextService; + private readonly ILocalizationService _localizationService; + private readonly IShortStringHelper _shortStringHelper; public DataTypeService(IScopeProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory, IDataTypeRepository dataTypeRepository, IDataTypeContainerRepository dataTypeContainerRepository, - IAuditRepository auditRepository, IEntityRepository entityRepository, IContentTypeRepository contentTypeRepository) + IAuditRepository auditRepository, IEntityRepository entityRepository, IContentTypeRepository contentTypeRepository, + IIOHelper ioHelper, ILocalizedTextService localizedTextService, ILocalizationService localizationService, IShortStringHelper shortStringHelper) : base(provider, logger, eventMessagesFactory) { _dataTypeRepository = dataTypeRepository; @@ -34,6 +41,10 @@ namespace Umbraco.Core.Services.Implement _auditRepository = auditRepository; _entityRepository = entityRepository; _contentTypeRepository = contentTypeRepository; + _ioHelper = ioHelper; + _localizedTextService = localizedTextService; + _localizationService = localizationService; + _shortStringHelper = shortStringHelper; } #region Containers @@ -227,7 +238,9 @@ namespace Umbraco.Core.Services.Implement { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - return _dataTypeRepository.Get(Query().Where(x => x.Name == name)).FirstOrDefault(); + var dataType = _dataTypeRepository.Get(Query().Where(x => x.Name == name)).FirstOrDefault(); + ConvertMissingEditorOfDataTypeToLabel(dataType); + return dataType; } } @@ -240,7 +253,9 @@ namespace Umbraco.Core.Services.Implement { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - return _dataTypeRepository.Get(id); + var dataType = _dataTypeRepository.Get(id); + ConvertMissingEditorOfDataTypeToLabel(dataType); + return dataType; } } @@ -254,7 +269,9 @@ namespace Umbraco.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.Key == id); - return _dataTypeRepository.Get(query).FirstOrDefault(); + var dataType = _dataTypeRepository.Get(query).FirstOrDefault(); + ConvertMissingEditorOfDataTypeToLabel(dataType); + return dataType; } } @@ -268,7 +285,9 @@ namespace Umbraco.Core.Services.Implement using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.EditorAlias == propertyEditorAlias); - return _dataTypeRepository.Get(query); + var dataType = _dataTypeRepository.Get(query); + ConvertMissingEditorsOfDataTypesToLabels(dataType); + return dataType; } } @@ -281,7 +300,31 @@ namespace Umbraco.Core.Services.Implement { using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { - return _dataTypeRepository.GetMany(ids); + var dataTypes = _dataTypeRepository.GetMany(ids); + ConvertMissingEditorsOfDataTypesToLabels(dataTypes); + return dataTypes; + } + } + + private void ConvertMissingEditorOfDataTypeToLabel(IDataType dataType) + { + if (dataType == null) + { + return; + } + + ConvertMissingEditorsOfDataTypesToLabels(new[] { dataType }); + } + + private void ConvertMissingEditorsOfDataTypesToLabels(IEnumerable dataTypes) + { + // Any data types that don't have an associated editor are created of a specific type. + // We convert them to labels to make clear to the user why the data type cannot be used. + var dataTypesWithMissingEditors = dataTypes + .Where(x => x.Editor is MissingPropertyEditor); + foreach (var dataType in dataTypesWithMissingEditors) + { + dataType.Editor = new LabelPropertyEditor(Logger, _ioHelper, this, _localizedTextService, _localizationService, _shortStringHelper); } } diff --git a/src/Umbraco.Infrastructure/Services/Implement/IInstallationService.cs b/src/Umbraco.Infrastructure/Services/Implement/IInstallationService.cs new file mode 100644 index 0000000000..334088f8ae --- /dev/null +++ b/src/Umbraco.Infrastructure/Services/Implement/IInstallationService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using Umbraco.Core.Models; + +namespace Umbraco.Core.Services +{ + public interface IInstallationService + { + Task LogInstall(InstallLog installLog); + } +} diff --git a/src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs b/src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs new file mode 100644 index 0000000000..a1f74e0862 --- /dev/null +++ b/src/Umbraco.Infrastructure/Services/Implement/Implement/InstallationService.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; +using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Repositories; + +namespace Umbraco.Core.Services.Implement +{ + public class InstallationService : IInstallationService + { + private readonly IInstallationRepository _installationRepository; + + public InstallationService(IInstallationRepository installationRepository) + { + _installationRepository = installationRepository; + } + + public async Task LogInstall(InstallLog installLog) + { + await _installationRepository.SaveInstallLogAsync(installLog); + } + } +} diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs index e383eb0223..029978347a 100644 --- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs @@ -364,7 +364,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public override bool EnsureEnvironment(out IEnumerable errors) { // must have app_data and be able to write files into it - var ok = FilePermissionHelper.TryCreateDirectory(GetLocalFilesPath(), _ioHelper); + var ok = FilePermissionDirectoryHelper.TryCreateDirectory(GetLocalFilesPath(), _ioHelper); errors = ok ? Enumerable.Empty() : new[] { "NuCache local files." }; return ok; } diff --git a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj index 2001309138..4c369ec2fa 100644 --- a/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj +++ b/src/Umbraco.PublishedCache.NuCache/Umbraco.PublishedCache.NuCache.csproj @@ -13,7 +13,6 @@ - diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs index 6be417e484..81214ccdb2 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs @@ -99,7 +99,7 @@ namespace Umbraco.Tests.Cache.PublishedCache //var publishedMedia = PublishedMediaTests.GetNode(mRoot.Id, GetUmbracoContext("/test", 1234)); var umbracoContext = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), Current.Services.MediaService, Current.Services.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance(), VariationContextAccessor); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null, HostingEnvironment), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance(), VariationContextAccessor); var publishedMedia = cache.GetById(mRoot.Id); Assert.IsNotNull(publishedMedia); diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index a49fdf3abe..6658c689e1 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -275,7 +275,7 @@ AnotherContentFinder public void GetDataEditors() { var types = _typeLoader.GetDataEditors(); - Assert.AreEqual(38, types.Count()); + Assert.AreEqual(39, types.Count()); } /// diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs index 03c6ddba47..1f68f905c7 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs @@ -545,7 +545,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache // was library.GetMedia which had its own cache, but MediaService *also* caches // so, library.GetMedia is gone and now we directly work with MediaService // (code below copied from what library was doing) - var media = Current.Services.MediaService.GetById(parentId); + var media = _mediaService.GetById(parentId); if (media == null) { return Enumerable.Empty(); diff --git a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index fc45f0ba3f..30bf5be17b 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -50,7 +50,7 @@ namespace Umbraco.Tests.Persistence.Repositories TemplateRepository tr; var ctRepository = CreateRepository(scopeAccessor, out contentTypeRepository, out tr); var editors = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty())); - dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, new Lazy(() => editors), Logger, IOHelper, new Lazy(() => DataTypeService), LocalizedTextService, LocalizationService, ShortStringHelper); + dtdRepository = new DataTypeRepository(scopeAccessor, appCaches, new Lazy(() => editors), Logger); return ctRepository; } diff --git a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs index 8b2514eec0..201b84f29a 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/UserRepositoryTest.cs @@ -423,6 +423,35 @@ namespace Umbraco.Tests.Persistence.Repositories } } + [Test] + public void Can_Invalidate_SecurityStamp_On_Username_Change() + { + // Arrange + var provider = TestObjects.GetScopeProvider(Logger); + using (var scope = provider.CreateScope()) + { + var repository = CreateRepository(provider); + var userGroupRepository = CreateUserGroupRepository(provider); + + var user = CreateAndCommitUserWithGroup(repository, userGroupRepository); + var originalSecurityStamp = user.SecurityStamp; + + // Ensure when user generated a security stamp is present + Assert.That(user.SecurityStamp, Is.Not.Null); + Assert.That(user.SecurityStamp, Is.Not.Empty); + + // Update username + user.Username = user.Username + "UPDATED"; + repository.Save(user); + + // Get the user + var updatedUser = repository.Get(user.Id); + + // Ensure the Security Stamp is invalidated & no longer the same + Assert.AreNotEqual(originalSecurityStamp, updatedUser.SecurityStamp); + } + } + private void AssertPropertyValues(IUser updatedItem, IUser originalUser) { Assert.That(updatedItem.Id, Is.EqualTo(originalUser.Id)); diff --git a/src/Umbraco.Tests/TestHelpers/TestObjects.cs b/src/Umbraco.Tests/TestHelpers/TestObjects.cs index 92b9dd0ad2..f237fb0fc7 100644 --- a/src/Umbraco.Tests/TestHelpers/TestObjects.cs +++ b/src/Umbraco.Tests/TestHelpers/TestObjects.cs @@ -158,7 +158,7 @@ namespace Umbraco.Tests.TestHelpers var localizationService = GetLazyService(factory, c => new LocalizationService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c))); var userService = GetLazyService(factory, c => new UserService(scopeProvider, logger, eventMessagesFactory, runtimeState, GetRepo(c), GetRepo(c),globalSettings)); - var dataTypeService = GetLazyService(factory, c => new DataTypeService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c))); + var dataTypeService = GetLazyService(factory, c => new DataTypeService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), ioHelper, localizedTextService.Value, localizationService.Value, TestHelper.ShortStringHelper)); var propertyValidationService = new Lazy(() => new PropertyValidationService(propertyEditorCollection, dataTypeService.Value)); var contentService = GetLazyService(factory, c => new ContentService(scopeProvider, logger, eventMessagesFactory, GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), GetRepo(c), propertyValidationService)); var notificationService = GetLazyService(factory, c => new NotificationService(scopeProvider, userService.Value, contentService.Value, localizationService.Value, logger, ioHelper, GetRepo(c), globalSettings, umbracoSettings.Content)); diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 16e4ca2c11..a490ba8b6a 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -569,10 +569,6 @@ {0fad7d2a-d7dd-45b1-91fd-488bb6cdacea} Umbraco.Examine.Lucene - - {f9b7fe05-0f93-4d0d-9c10-690b33ecbbd8} - Umbraco.Examine - {3ae7bf57-966b-45a5-910a-954d7c554441} Umbraco.Infrastructure diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 1889e4b032..42a89c5d13 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -1109,9 +1109,9 @@ "integrity": "sha512-kU/fHIGf2a4a3bH7E1tzALTHk+QfoUSCK9fEcMFisd6ZWvNDwPzXWAilItqOC3EDiAXPmGHaNc9/aXiD9xrAxQ==" }, "angular-aria": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/angular-aria/-/angular-aria-1.7.5.tgz", - "integrity": "sha512-X2dGRw+PK7hrV7/X1Ns4e5P3KC/OBFi1l7z//D/v7zbZObsAx48qBoX7unsck+s4+mnO+ikNNkHG5N49VfAyRw==" + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/angular-aria/-/angular-aria-1.7.9.tgz", + "integrity": "sha512-luI3Jemd1AbOQW0krdzfEG3fM0IFtLY0bSSqIDEx3POE0XjKIC1MkrO8Csyq9PPgueLphyAPofzUwZ8YeZ88SA==" }, "angular-chart.js": { "version": "1.1.1", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index 508409b4ea..c150af79de 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -13,7 +13,7 @@ "ace-builds": "1.4.2", "angular": "1.7.9", "angular-animate": "1.7.5", - "angular-aria": "1.7.5", + "angular-aria": "1.7.9", "angular-chart.js": "^1.1.1", "angular-cookies": "1.7.5", "angular-dynamic-locale": "0.1.37", diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js index d562b21d52..9a9d6d4a76 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbcheckbox.directive.js @@ -71,6 +71,7 @@ templateUrl: 'views/components/forms/umb-checkbox.html', controller: UmbCheckboxController, controllerAs: 'vm', + transclude: true, bindings: { model: "=", inputId: "@", diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js index 7ed84547f1..d79140f947 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/forms/umbradiobutton.directive.js @@ -69,6 +69,7 @@ templateUrl: 'views/components/forms/umb-radiobutton.html', controller: UmbRadiobuttonController, controllerAs: 'vm', + transclude: true, bindings: { model: "=", inputId: "@", diff --git a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js index 284a7db4d8..d481205657 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/editor.service.js @@ -169,6 +169,7 @@ When building a custom infinite editor view you can use the same components as a let editorsKeyboardShorcuts = []; var editors = []; var isEnabled = true; + var lastElementInFocus = null; // events for backdrop @@ -261,6 +262,12 @@ When building a custom infinite editor view you can use the same components as a */ unbindKeyboardShortcuts(); + // if this is the first editor layer, save the currently focused element + // so we can re-apply focus to it once all the editor layers are closed + if (editors.length === 0) { + lastElementInFocus = document.activeElement; + } + // set flag so we know when the editor is open in "infinite mode" editor.infiniteMode = true; @@ -301,6 +308,10 @@ When building a custom infinite editor view you can use the same components as a $timeout(function() { // rebind keyboard shortcuts for the new editor in focus rebindKeyboardShortcuts(); + + if (editors.length === 0 && lastElementInFocus) { + lastElementInFocus.focus(); + } }, 0); } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less index 76a4df0056..b9efd8f7d8 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-form-check.less @@ -3,15 +3,21 @@ .umb-form-check { display: flex; - flex-wrap: wrap; - align-items: center; position: relative; - padding: 0 0 0 26px !important; + padding-left: 0px; margin: 0; min-height: 22px; - line-height: 22px; cursor: pointer !important; + .umb-form-check__symbol { + margin-top: 1px; + margin-right: 10px; + } + .umb-form-check__info { + + } + + &.-small-text{ font-size: 13px; } @@ -22,7 +28,6 @@ &__text { position: relative; - top: 1px; user-select: none; } @@ -90,10 +95,6 @@ &__state { display: flex; height: 18px; - margin-top: 2px; - position: absolute; - top: 0; - left: 0; } &__check { @@ -101,6 +102,7 @@ position: relative; background: @white; border: 1px solid @inputBorder; + border-radius: @baseBorderRadius; width: @checkboxWidth; height: @checkboxHeight; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-mini-search.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-mini-search.less index ac15b3dcf8..68cb9b2e58 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-mini-search.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-mini-search.less @@ -4,16 +4,21 @@ .icon { position: absolute; - padding: 5px 8px; + width: 30px; + height: 30px; + display: flex; + justify-content: center; + align-items: center; + margin: 1px; + padding: 0; pointer-events: none; - top: 2px; color: @ui-action-discreet-type; transition: color .1s linear; } input { width: 0px; - padding-left:24px; + padding-left: 24px; margin-bottom: 0px; background-color: transparent; border-color: @ui-action-discreet-border; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html index 82b21e4c3b..ba5adf199a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-checkbox.html @@ -1,22 +1,28 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-radiobutton.html b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-radiobutton.html index 9ee50bcae1..a34d548ea6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-radiobutton.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/forms/umb-radiobutton.html @@ -1,16 +1,20 @@ diff --git a/src/Umbraco.Web.UI.Client/src/views/components/grid/grid-rte.html b/src/Umbraco.Web.UI.Client/src/views/components/grid/grid-rte.html index b5531f477a..cbd1ac3f30 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/grid/grid-rte.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/grid/grid-rte.html @@ -1,4 +1,4 @@ 
-
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-search/umb-mini-search.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-search/umb-mini-search.html index 20ce87f0eb..93801f14b8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-search/umb-mini-search.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-mini-search/umb-mini-search.html @@ -1,5 +1,5 @@ - + GetCheck() { var updChkCookie = Request.Headers.GetCookies("UMB_UPDCHK").FirstOrDefault(); var updateCheckCookie = updChkCookie != null ? updChkCookie["UMB_UPDCHK"].Value : ""; @@ -31,23 +38,15 @@ namespace Umbraco.Web.Editors { try { - var check = new org.umbraco.update.CheckForUpgrade { Timeout = 2000 }; + var version = new SemVersion(_umbracoVersion.Current.Major, _umbracoVersion.Current.Minor, + _umbracoVersion.Current.Build, _umbracoVersion.Comment); + var result = await _upgradeService.CheckUpgrade(version); - var result = check.CheckUpgrade(_umbracoVersion.Current.Major, - _umbracoVersion.Current.Minor, - _umbracoVersion.Current.Build, - _umbracoVersion.Comment); - - return new UpgradeCheckResponse(result.UpgradeType.ToString(), result.Comment, result.UpgradeUrl, _umbracoVersion); + return new UpgradeCheckResponse(result.UpgradeType, result.Comment, result.UpgradeUrl, _umbracoVersion); } - catch (System.Net.WebException) + catch { - //this occurs if the server is down or cannot be reached - return null; - } - catch (System.Web.Services.Protocols.SoapException) - { - //this occurs if the server has a timeout + //We don't want to crash due to this return null; } } diff --git a/src/Umbraco.Web/HttpContextAccessorExtensions.cs b/src/Umbraco.Web/HttpContextAccessorExtensions.cs index 4c2dcf0a0d..2076510ce0 100644 --- a/src/Umbraco.Web/HttpContextAccessorExtensions.cs +++ b/src/Umbraco.Web/HttpContextAccessorExtensions.cs @@ -1,4 +1,4 @@ -using System.IO; +using System; using System.Web; namespace Umbraco.Web @@ -9,7 +9,7 @@ namespace Umbraco.Web { var httpContext = httpContextAccessor.HttpContext; - if(httpContext is null) throw new IOException("HttpContext is null"); + if(httpContext is null) throw new InvalidOperationException("HttpContext is null"); return httpContext; } diff --git a/src/Umbraco.Web/Install/FilePermissionHelper.cs b/src/Umbraco.Web/Install/FilePermissionHelper.cs index be7c88729a..be4c2b1dd0 100644 --- a/src/Umbraco.Web/Install/FilePermissionHelper.cs +++ b/src/Umbraco.Web/Install/FilePermissionHelper.cs @@ -141,7 +141,7 @@ namespace Umbraco.Web.Install { try { - var path = _ioHelper.MapPath(dir + "/" + CreateRandomName()); + var path = _ioHelper.MapPath(dir + "/" + FilePermissionDirectoryHelper.CreateRandomFileName()); Directory.CreateDirectory(path); Directory.Delete(path); return true; @@ -152,29 +152,6 @@ namespace Umbraco.Web.Install } } - // tries to create a file - // if successful, the file is deleted - // creates the directory if needed - does not delete it - public static bool TryCreateDirectory(string dir, IIOHelper ioHelper) - { - try - { - var dirPath = ioHelper.MapPath(dir); - - if (Directory.Exists(dirPath) == false) - Directory.CreateDirectory(dirPath); - - var filePath = dirPath + "/" + CreateRandomName() + ".tmp"; - File.WriteAllText(filePath, "This is an Umbraco internal test file. It is safe to delete it."); - File.Delete(filePath); - return true; - } - catch - { - return false; - } - } - // tries to create a file // if successful, the file is deleted // @@ -194,7 +171,7 @@ namespace Umbraco.Web.Install if (canWrite) { - var filePath = dirPath + "/" + CreateRandomName() + ".tmp"; + var filePath = dirPath + "/" + FilePermissionDirectoryHelper.CreateRandomFileName() + ".tmp"; File.WriteAllText(filePath, "This is an Umbraco internal test file. It is safe to delete it."); File.Delete(filePath); return true; @@ -261,10 +238,5 @@ namespace Umbraco.Web.Install return false; } } - - private static string CreateRandomName() - { - return "umbraco-test." + Guid.NewGuid().ToString("N").Substring(0, 8); - } } } diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index dd23b33c8f..f7344d0b0b 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -2,14 +2,17 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; +using System.Threading.Tasks; using System.Web; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Cookie; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; +using Umbraco.Core.Models; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.SqlSyntax; +using Umbraco.Core.Services; using Umbraco.Web.Composing; using Umbraco.Web.Install.Models; @@ -24,12 +27,18 @@ namespace Umbraco.Web.Install private readonly IGlobalSettings _globalSettings; private readonly IUmbracoVersion _umbracoVersion; private readonly IConnectionStrings _connectionStrings; + private readonly IInstallationService _installationService; private readonly ICookieManager _cookieManager; private InstallationType? _installationType; public InstallHelper(IHttpContextAccessor httpContextAccessor, DatabaseBuilder databaseBuilder, - ILogger logger, IGlobalSettings globalSettings, IUmbracoVersion umbracoVersion, IConnectionStrings connectionStrings, ICookieManager cookieManager) + ILogger logger, + IGlobalSettings globalSettings, + IUmbracoVersion umbracoVersion, + IConnectionStrings connectionStrings, + IInstallationService installationService, + ICookieManager cookieManager) { _httpContextAccessor = httpContextAccessor; _logger = logger; @@ -37,6 +46,7 @@ namespace Umbraco.Web.Install _umbracoVersion = umbracoVersion; _databaseBuilder = databaseBuilder; _connectionStrings = connectionStrings ?? throw new ArgumentNullException(nameof(connectionStrings)); + _installationService = installationService; _cookieManager = cookieManager; } @@ -45,7 +55,7 @@ namespace Umbraco.Web.Install return _installationType ?? (_installationType = IsBrandNewInstall ? InstallationType.NewInstall : InstallationType.Upgrade).Value; } - public void InstallStatus(bool isCompleted, string errorMsg) + public async Task InstallStatus(bool isCompleted, string errorMsg) { var httpContext = _httpContextAccessor.GetRequiredHttpContext(); @@ -65,9 +75,13 @@ namespace Umbraco.Web.Install if (installId == Guid.Empty) installId = Guid.NewGuid(); } + else + { + installId = Guid.NewGuid(); // Guid.TryParse will have reset installId to Guid.Empty + } } - _cookieManager.SetCookieValue(Constants.Web.InstallerCookieName, "1"); + _cookieManager.SetCookieValue(Constants.Web.InstallerCookieName, installId.ToString()); var dbProvider = string.Empty; if (IsBrandNewInstall == false) @@ -77,18 +91,13 @@ namespace Umbraco.Web.Install dbProvider = GetDbProviderString(Current.SqlContext); } - var check = new org.umbraco.update.CheckForUpgrade(); - check.Install(installId, - IsBrandNewInstall == false, - isCompleted, - DateTime.Now, - _umbracoVersion.Current.Major, - _umbracoVersion.Current.Minor, - _umbracoVersion.Current.Build, - _umbracoVersion.Comment, - errorMsg, - userAgent, - dbProvider); + var installLog = new InstallLog(installId: installId, isUpgrade: IsBrandNewInstall == false, + installCompleted: isCompleted, timestamp: DateTime.Now, versionMajor: _umbracoVersion.Current.Major, + versionMinor: _umbracoVersion.Current.Minor, versionPatch: _umbracoVersion.Current.Build, + versionComment: _umbracoVersion.Comment, error: errorMsg, userAgent: userAgent, + dbProvider: dbProvider); + + await _installationService.LogInstall(installLog); } catch (Exception ex) { diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index aa32de01bc..f199fd5f5a 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -571,11 +571,6 @@ - - True - True - Reference.map - Component @@ -598,30 +593,18 @@ - - - - - - - MSDiscoCodeGenerator - Reference.cs - Designer - Mvc\web.config - - Reference.map - - - Reference.map + + SettingsSingleFileGenerator + Settings.Designer.cs diff --git a/src/Umbraco.Web/Web References/org.umbraco.update/Reference.cs b/src/Umbraco.Web/Web References/org.umbraco.update/Reference.cs deleted file mode 100644 index 230594fcbd..0000000000 --- a/src/Umbraco.Web/Web References/org.umbraco.update/Reference.cs +++ /dev/null @@ -1,286 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -// -// This source code was auto-generated by Microsoft.VSDesigner, Version 4.0.30319.42000. -// -#pragma warning disable 1591 - -namespace Umbraco.Web.org.umbraco.update { - using System; - using System.Web.Services; - using System.Diagnostics; - using System.Web.Services.Protocols; - using System.Xml.Serialization; - using System.ComponentModel; - - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.7.3062.0")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Web.Services.WebServiceBindingAttribute(Name="CheckForUpgradeSoap", Namespace="http://update.umbraco.org/")] - public partial class CheckForUpgrade : System.Web.Services.Protocols.SoapHttpClientProtocol { - - private System.Threading.SendOrPostCallback InstallOperationCompleted; - - private System.Threading.SendOrPostCallback CheckUpgradeOperationCompleted; - - private bool useDefaultCredentialsSetExplicitly; - - /// - public CheckForUpgrade() { - this.Url = "http://update.umbraco.org/checkforupgrade.asmx"; - if ((this.IsLocalFileSystemWebService(this.Url) == true)) { - this.UseDefaultCredentials = true; - this.useDefaultCredentialsSetExplicitly = false; - } - else { - this.useDefaultCredentialsSetExplicitly = true; - } - } - - public new string Url { - get { - return base.Url; - } - set { - if ((((this.IsLocalFileSystemWebService(base.Url) == true) - && (this.useDefaultCredentialsSetExplicitly == false)) - && (this.IsLocalFileSystemWebService(value) == false))) { - base.UseDefaultCredentials = false; - } - base.Url = value; - } - } - - public new bool UseDefaultCredentials { - get { - return base.UseDefaultCredentials; - } - set { - base.UseDefaultCredentials = value; - this.useDefaultCredentialsSetExplicitly = true; - } - } - - /// - public event InstallCompletedEventHandler InstallCompleted; - - /// - public event CheckUpgradeCompletedEventHandler CheckUpgradeCompleted; - - /// - [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://update.umbraco.org/Install", RequestNamespace="http://update.umbraco.org/", ResponseNamespace="http://update.umbraco.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public void Install(System.Guid installId, bool isUpgrade, bool installCompleted, System.DateTime timestamp, int versionMajor, int versionMinor, int versionPatch, string versionComment, string error, string userAgent, string dbProvider) { - this.Invoke("Install", new object[] { - installId, - isUpgrade, - installCompleted, - timestamp, - versionMajor, - versionMinor, - versionPatch, - versionComment, - error, - userAgent, - dbProvider}); - } - - /// - public void InstallAsync(System.Guid installId, bool isUpgrade, bool installCompleted, System.DateTime timestamp, int versionMajor, int versionMinor, int versionPatch, string versionComment, string error, string userAgent, string dbProvider) { - this.InstallAsync(installId, isUpgrade, installCompleted, timestamp, versionMajor, versionMinor, versionPatch, versionComment, error, userAgent, dbProvider, null); - } - - /// - public void InstallAsync(System.Guid installId, bool isUpgrade, bool installCompleted, System.DateTime timestamp, int versionMajor, int versionMinor, int versionPatch, string versionComment, string error, string userAgent, string dbProvider, object userState) { - if ((this.InstallOperationCompleted == null)) { - this.InstallOperationCompleted = new System.Threading.SendOrPostCallback(this.OnInstallOperationCompleted); - } - this.InvokeAsync("Install", new object[] { - installId, - isUpgrade, - installCompleted, - timestamp, - versionMajor, - versionMinor, - versionPatch, - versionComment, - error, - userAgent, - dbProvider}, this.InstallOperationCompleted, userState); - } - - private void OnInstallOperationCompleted(object arg) { - if ((this.InstallCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.InstallCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://update.umbraco.org/CheckUpgrade", RequestNamespace="http://update.umbraco.org/", ResponseNamespace="http://update.umbraco.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] - public UpgradeResult CheckUpgrade(int versionMajor, int versionMinor, int versionPatch, string versionComment) { - object[] results = this.Invoke("CheckUpgrade", new object[] { - versionMajor, - versionMinor, - versionPatch, - versionComment}); - return ((UpgradeResult)(results[0])); - } - - /// - public void CheckUpgradeAsync(int versionMajor, int versionMinor, int versionPatch, string versionComment) { - this.CheckUpgradeAsync(versionMajor, versionMinor, versionPatch, versionComment, null); - } - - /// - public void CheckUpgradeAsync(int versionMajor, int versionMinor, int versionPatch, string versionComment, object userState) { - if ((this.CheckUpgradeOperationCompleted == null)) { - this.CheckUpgradeOperationCompleted = new System.Threading.SendOrPostCallback(this.OnCheckUpgradeOperationCompleted); - } - this.InvokeAsync("CheckUpgrade", new object[] { - versionMajor, - versionMinor, - versionPatch, - versionComment}, this.CheckUpgradeOperationCompleted, userState); - } - - private void OnCheckUpgradeOperationCompleted(object arg) { - if ((this.CheckUpgradeCompleted != null)) { - System.Web.Services.Protocols.InvokeCompletedEventArgs invokeArgs = ((System.Web.Services.Protocols.InvokeCompletedEventArgs)(arg)); - this.CheckUpgradeCompleted(this, new CheckUpgradeCompletedEventArgs(invokeArgs.Results, invokeArgs.Error, invokeArgs.Cancelled, invokeArgs.UserState)); - } - } - - /// - public new void CancelAsync(object userState) { - base.CancelAsync(userState); - } - - private bool IsLocalFileSystemWebService(string url) { - if (((url == null) - || (url == string.Empty))) { - return false; - } - System.Uri wsUri = new System.Uri(url); - if (((wsUri.Port >= 1024) - && (string.Compare(wsUri.Host, "localHost", System.StringComparison.OrdinalIgnoreCase) == 0))) { - return true; - } - return false; - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.3062.0")] - [System.SerializableAttribute()] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://update.umbraco.org/")] - public partial class UpgradeResult { - - private string commentField; - - private UpgradeType upgradeTypeField; - - private string upgradeUrlField; - - /// - public string Comment { - get { - return this.commentField; - } - set { - this.commentField = value; - } - } - - /// - public UpgradeType UpgradeType { - get { - return this.upgradeTypeField; - } - set { - this.upgradeTypeField = value; - } - } - - /// - public string UpgradeUrl { - get { - return this.upgradeUrlField; - } - set { - this.upgradeUrlField = value; - } - } - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.7.3062.0")] - [System.SerializableAttribute()] - [System.Xml.Serialization.XmlTypeAttribute(Namespace="http://update.umbraco.org/")] - public enum UpgradeType { - - /// - None, - - /// - Patch, - - /// - Minor, - - /// - Major, - - /// - Critical, - - /// - Error, - - /// - OutOfSync, - } - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.7.3062.0")] - public delegate void InstallCompletedEventHandler(object sender, System.ComponentModel.AsyncCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.7.3062.0")] - public delegate void CheckUpgradeCompletedEventHandler(object sender, CheckUpgradeCompletedEventArgs e); - - /// - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.7.3062.0")] - [System.Diagnostics.DebuggerStepThroughAttribute()] - [System.ComponentModel.DesignerCategoryAttribute("code")] - public partial class CheckUpgradeCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { - - private object[] results; - - internal CheckUpgradeCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) : - base(exception, cancelled, userState) { - this.results = results; - } - - /// - public UpgradeResult Result { - get { - this.RaiseExceptionIfNecessary(); - return ((UpgradeResult)(this.results[0])); - } - } - } -} - -#pragma warning restore 1591 \ No newline at end of file diff --git a/src/Umbraco.Web/Web References/org.umbraco.update/Reference.map b/src/Umbraco.Web/Web References/org.umbraco.update/Reference.map deleted file mode 100644 index ded6650264..0000000000 --- a/src/Umbraco.Web/Web References/org.umbraco.update/Reference.map +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/Umbraco.Web/Web References/org.umbraco.update/UpgradeResult.datasource b/src/Umbraco.Web/Web References/org.umbraco.update/UpgradeResult.datasource deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/Umbraco.Web/Web References/org.umbraco.update/UpgradeResult1.datasource b/src/Umbraco.Web/Web References/org.umbraco.update/UpgradeResult1.datasource deleted file mode 100644 index c42c98b0b7..0000000000 --- a/src/Umbraco.Web/Web References/org.umbraco.update/UpgradeResult1.datasource +++ /dev/null @@ -1,10 +0,0 @@ - - - - umbraco.presentation.org.umbraco.update.UpgradeResult, Web References.org.umbraco.update.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null - \ No newline at end of file diff --git a/src/Umbraco.Web/Web References/org.umbraco.update/checkforupgrade.disco b/src/Umbraco.Web/Web References/org.umbraco.update/checkforupgrade.disco deleted file mode 100644 index 366f4fdd6e..0000000000 --- a/src/Umbraco.Web/Web References/org.umbraco.update/checkforupgrade.disco +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Umbraco.Web/Web References/org.umbraco.update/checkforupgrade.wsdl b/src/Umbraco.Web/Web References/org.umbraco.update/checkforupgrade.wsdl deleted file mode 100644 index e2aba65c7c..0000000000 --- a/src/Umbraco.Web/Web References/org.umbraco.update/checkforupgrade.wsdl +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file