From 9649e61f17085aa30f04c10d7725fc47cb780d79 Mon Sep 17 00:00:00 2001 From: Aaron Powell Date: Thu, 13 Dec 2018 11:54:32 +1100 Subject: [PATCH 01/23] Fixing #3866 - making a few methods public --- src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index ea818c60e3..a54b997cb8 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -417,7 +417,7 @@ namespace Umbraco.Core.Migrations.Install #region Database Schema - internal DatabaseSchemaResult ValidateDatabaseSchema() + public DatabaseSchemaResult ValidateDatabaseSchema() { using (var scope = _scopeProvider.CreateScope()) { @@ -442,7 +442,7 @@ namespace Umbraco.Core.Migrations.Install return _databaseSchemaValidationResult; } - internal Result CreateDatabaseSchemaAndData() + public Result CreateDatabaseSchemaAndData() { using (var scope = _scopeProvider.CreateScope()) { @@ -522,7 +522,7 @@ namespace Umbraco.Core.Migrations.Install } // This assumes all of the previous checks are done! - internal Result UpgradeSchemaAndData() + public Result UpgradeSchemaAndData() { try { @@ -630,7 +630,7 @@ namespace Umbraco.Core.Migrations.Install }; } - internal class Result + public class Result { public bool RequiresUpgrade { get; set; } public string Message { get; set; } From 33b9870aecb794cf6c534a2e70915a74838fd3e6 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Sun, 16 Dec 2018 21:52:45 +0100 Subject: [PATCH 02/23] Only perform save when previewing - not a publish --- .../src/common/directives/components/content/edit.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 407416f2a1..f1e2150579 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -815,7 +815,7 @@ //ensure the save flag is set selectedVariant.save = true; - performSave({ saveMethod: contentResource.publish, action: "save" }).then(function (data) { + performSave({ saveMethod: $scope.saveMethod(), action: "save" }).then(function (data) { previewWindow.location.href = redirect; }, function (err) { //validation issues .... From ebc689032d787e0cd6532a1ffce15a5d3ad77472 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Dec 2018 10:48:33 +0100 Subject: [PATCH 03/23] fix dictionary pickers in code editors --- .../insertcodesnippet/insertcodesnippet.controller.js | 2 +- .../src/views/partialviewmacros/edit.controller.js | 2 +- .../src/views/partialviews/edit.controller.js | 2 +- .../src/views/templates/edit.controller.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js index 526d076048..2b40d496f5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/insertcodesnippet/insertcodesnippet.controller.js @@ -77,7 +77,7 @@ var emptyStateMessage = values[2]; var dictionaryItemPicker = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js index afc00bb7e2..372cecb36c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js @@ -201,7 +201,7 @@ var emptyStateMessage = values[1]; var dictionaryPicker = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js index ff14ea0ebd..292898814d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js @@ -207,7 +207,7 @@ var emptyStateMessage = values[1]; var dictionaryItem = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, diff --git a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js index 8ac9dc78e8..1f6fb8863a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js @@ -438,7 +438,7 @@ var emptyStateMessage = values[1]; var dictionaryItem = { - section: "settings", + section: "translation", treeAlias: "dictionary", entityType: "dictionary", multiPicker: false, From 4068dca93874eaacbef7d249284fc84fee0752d4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 17 Dec 2018 13:55:08 +0100 Subject: [PATCH 04/23] reenable infinite editing animations --- .../components/editor/umbeditors.directive.js | 67 ++++++------------- .../less/components/editor/umb-editor.less | 2 +- 2 files changed, 20 insertions(+), 49 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js index e68c2bbc9a..58afc72f6c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/editor/umbeditors.directive.js @@ -25,25 +25,6 @@ // shown so we don't animate a lot of editors which aren't necessary var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ allowedNumberOfVisibleEditors +')'); - // this is a temporary fix because the animations doesn't perform well - // TODO: fix animation and remove this - moveEditors.forEach(function(editor, index){ - - // resize the small editors to 100% so we can easily slide them - if(editor.classList.contains("umb-editor--small")) { - editor.style.width = "100%"; - } - - // set left position to indent the editors - if(scope.editors.length >= allowedNumberOfVisibleEditors) { - $(editor).css({"left": index * editorIndent}); - } else { - $(editor).css({"left": (index + 1) * editorIndent}); - } - - }); - - /* // collapse open editors before opening the new one var collapseEditorAnimation = anime({ targets: moveEditors, @@ -61,9 +42,8 @@ return (index + 1) * editorIndent; }, easing: 'easeInOutQuint', - duration: 500 + duration: 300 }); - */ // push the new editor to the dom scope.editors.push(editor); @@ -95,7 +75,7 @@ translateX: [100 + '%', 0], opacity: [0, 1], easing: 'easeInOutQuint', - duration: 400, + duration: 300, complete: function() { $timeout(function(){ editor.animating = false; @@ -126,11 +106,12 @@ $timeout(function(){ scope.editors.splice(-1,1); removeOverlayFromPrevEditor(); - expandEditors(); }); } }); + expandEditors(); + }); } @@ -142,42 +123,32 @@ var editorsElement = el[0]; // only select the editors which are allowed to be // shown so we don't animate a lot of editors which aren't necessary - var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ 4 +')'); + // as the last element hasn't been removed from the dom yet we have to select the last four and then skip the last child (as it is the one closing). + var moveEditors = editorsElement.querySelectorAll('.umb-editor:nth-last-child(-n+'+ allowedNumberOfVisibleEditors + 1 +'):not(:last-child)'); + var editorWidth = editorsElement.offsetWidth; - // this is a temporary fix because the animations doesn't perform well - // TODO: fix animation and remove this - moveEditors.forEach(function(editor, index){ - // set left position - $(editor).css({"left": (index + 1) * editorIndent}); - - // if the new top editor is a small editor we will have to resize it back to the right size on - // move it all the way to the right side - if(editor.classList.contains("umb-editor--small") && index + 1 === moveEditors.length) { - editor.style.width = "500px"; - $(editor).css({"left": ""}); - } - }); - - // We need to figure out how to performance optimize this - // TODO: optimize animation - /* var expandEditorAnimation = anime({ targets: moveEditors, left: function(el, index, length){ - return (index + 1) * editorIndent; + // move the editor all the way to the right if the top one is a small + if(el.classList.contains("umb-editor--small")) { + // only change the size if it is the editor on top + if(index + 1 === length) { + return editorWidth - 500; + } + } else { + return (index + 1) * editorIndent; + } }, width: function(el, index, length) { - if(el.classList.contains("umb-editor--small")) { + // set the correct size if the top editor is of type "small" + if(el.classList.contains("umb-editor--small") && index + 1 === length) { return "500px"; } }, easing: 'easeInOutQuint', - duration: 500, - completed: function() { - - } + duration: 300 }); - */ }); diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less index 640a276443..321fabadad 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/umb-editor.less @@ -42,6 +42,6 @@ bottom: 0; right: 0; left: 0; - background: rgba(0,0,0,0.2); + background: rgba(0,0,0,0.4); z-index: @zIndexEditor; } \ No newline at end of file From c020383c22a4514c93dcedffb4d42feb8346e3cb Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 13 Dec 2018 13:47:09 +0100 Subject: [PATCH 05/23] Remove confusing LazyCollectionBuilderBase.Remove --- .../Composing/LazyCollectionBuilderBase.cs | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs b/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs index 52e5a764fd..ee263f458f 100644 --- a/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs +++ b/src/Umbraco.Core/Composing/LazyCollectionBuilderBase.cs @@ -75,37 +75,6 @@ namespace Umbraco.Core.Composing return This; } - /// - /// Removes a type from the collection. - /// - /// The type to remove. - /// The builder. - public TBuilder Remove() - where T : TItem - { - Configure(types => - { - var type = typeof(T); - if (types.Contains(type)) types.Remove(type); - }); - return This; - } - - /// - /// Removes a type from the collection. - /// - /// The type to remove. - /// The builder. - public TBuilder Remove(Type type) - { - Configure(types => - { - EnsureType(type, "remove"); - if (types.Contains(type)) types.Remove(type); - }); - return This; - } - /// /// Adds a types producer to the collection. /// From 8152862ad2b9d086b953996083453b3f15678313 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 13 Dec 2018 15:08:12 +0100 Subject: [PATCH 06/23] Fix issue with figuring out whether a published content version is draft --- .../PublishedContent/IPublishedContent.cs | 2 +- .../PublishedContentWrapped.cs | 2 +- .../CaseInsensitiveDictionaryConverter.cs | 25 +++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Published/NestedContentTests.cs | 2 +- .../PublishedContentDataTableTests.cs | 2 +- .../SolidPublishedSnapshot.cs | 3 +- .../TestHelpers/Stubs/TestPublishedContent.cs | 2 +- .../Models/PublishedContentBase.cs | 2 +- .../PublishedCache/NuCache/ContentCache.cs | 42 +++++------ .../NuCache/DataSource/ContentNestedData.cs | 3 + .../NuCache/DataSource/CultureVariation.cs | 3 + .../NuCache/DataSource/DatabaseDataSource.cs | 41 ++++++----- .../NuCache/Navigable/NavigableContent.cs | 2 +- .../NuCache/PublishedContent.cs | 23 +++++- .../NuCache/PublishedSnapshotService.cs | 3 +- .../PublishedCache/PublishedMember.cs | 2 +- .../DictionaryPublishedContent.cs | 2 +- .../XmlPublishedCache/XmlPublishedContent.cs | 9 +-- src/Umbraco.Web/PublishedContentExtensions.cs | 72 ++++++------------- src/Umbraco.Web/umbraco.presentation/page.cs | 4 +- 21 files changed, 136 insertions(+), 111 deletions(-) create mode 100644 src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs index 5b604eff3f..0c049e81bf 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs @@ -151,7 +151,7 @@ namespace Umbraco.Core.Models.PublishedContent /// is the edited version) or false (document is published, and has not been edited, and /// what is returned is the published version). /// - bool IsDraft { get; } + bool IsDraft(string culture = null); // fixme - consider having an IsPublished flag too // so that when IsDraft is true, we can check whether there is a published version? diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs index 5bdeb3685d..6a69d0b9e1 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs @@ -109,7 +109,7 @@ namespace Umbraco.Core.Models.PublishedContent public virtual PublishedItemType ItemType => _content.ItemType; /// - public virtual bool IsDraft => _content.IsDraft; + public virtual bool IsDraft(string culture = null) => _content.IsDraft(culture); #endregion diff --git a/src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs b/src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs new file mode 100644 index 0000000000..a92d562a52 --- /dev/null +++ b/src/Umbraco.Core/Serialization/CaseInsensitiveDictionaryConverter.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Newtonsoft.Json.Converters; + +namespace Umbraco.Core.Serialization +{ + /// + /// Marks dictionaries so they are deserialized as case-insensitive. + /// + /// + /// [JsonConverter(typeof(CaseInsensitiveDictionaryConverter{PropertyData[]}))] + /// public Dictionary{string, PropertyData[]} PropertyData {{ get; set; }} + /// + public class CaseInsensitiveDictionaryConverter : CustomCreationConverter + { + public override bool CanWrite => false; + + public override bool CanRead => true; + + public override bool CanConvert(Type objectType) => typeof(IDictionary).IsAssignableFrom(objectType); + + public override IDictionary Create(Type objectType) => new Dictionary(StringComparer.OrdinalIgnoreCase); + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index d69fab18a1..cd5c005de7 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -1312,6 +1312,7 @@ + diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests/Published/NestedContentTests.cs index 920fa2acd5..cf00345b65 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests/Published/NestedContentTests.cs @@ -262,7 +262,7 @@ namespace Umbraco.Tests.Published // ReSharper disable UnassignedGetOnlyAutoProperty public override PublishedItemType ItemType { get; } - public override bool IsDraft { get; } + public override bool IsDraft(string culture = null) => false; public override IPublishedContent Parent { get; } public override IEnumerable Children { get; } public override PublishedContentType ContentType { get; } diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index a640423515..aa9e7e4918 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -216,7 +216,7 @@ namespace Umbraco.Tests.PublishedContent public DateTime UpdateDate { get; set; } public Guid Version { get; set; } public int Level { get; set; } - public bool IsDraft { get; set; } + public bool IsDraft(string culture = null) => false; public IEnumerable Properties { get; set; } diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index efd1c6ae8b..0c4059ca7c 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -162,7 +162,6 @@ namespace Umbraco.Tests.PublishedContent WriterId = CreatorId = 0; CreateDate = UpdateDate = DateTime.Now; Version = Guid.Empty; - IsDraft = false; ContentType = contentType; } @@ -192,7 +191,7 @@ namespace Umbraco.Tests.PublishedContent public string GetUrl(string culture = null) => throw new NotSupportedException(); public PublishedItemType ItemType { get { return PublishedItemType.Content; } } - public bool IsDraft { get; set; } + public bool IsDraft(string culture = null) => false; #endregion diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs index 0faf1537b3..9c0bb61cb3 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs @@ -47,7 +47,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs public string Url { get; set; } public string GetUrl(string culture = null) => throw new NotSupportedException(); public PublishedItemType ItemType => ContentType.ItemType; - public bool IsDraft { get; set; } + public bool IsDraft(string culture = null) => false; public IPublishedContent Parent { get; set; } public IEnumerable Children { get; set; } diff --git a/src/Umbraco.Web/Models/PublishedContentBase.cs b/src/Umbraco.Web/Models/PublishedContentBase.cs index 1b8128b4c0..667cf145bd 100644 --- a/src/Umbraco.Web/Models/PublishedContentBase.cs +++ b/src/Umbraco.Web/Models/PublishedContentBase.cs @@ -142,7 +142,7 @@ namespace Umbraco.Web.Models public abstract PublishedItemType ItemType { get; } /// - public abstract bool IsDraft { get; } + public abstract bool IsDraft(string culture = null); #endregion diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs index edef545d2a..0197d2d640 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs @@ -147,7 +147,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var urlSegment = n.GetUrlSegment(culture); var hasDomains = _domainHelper.NodeHasDomains(n.Id); while (hasDomains == false && n != null) // n is null at root - { + { // no segment indicates this is not published when this is a variant if (urlSegment.IsNullOrWhiteSpace()) return null; @@ -173,7 +173,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var path = "/" + string.Join("/", pathParts); // will be "/" or "/foo" or "/foo/bar" etc //prefix the root node id containing the domain if it exists (this is a standard way of creating route paths) //and is done so that we know the ID of the domain node for the path - var route = (n?.Id.ToString(CultureInfo.InvariantCulture) ?? "") + path; + var route = (n?.Id.ToString(CultureInfo.InvariantCulture) ?? "") + path; return route; } @@ -223,24 +223,14 @@ namespace Umbraco.Web.PublishedCache.NuCache public override IPublishedContent GetById(bool preview, int contentId) { - var n = _snapshot.Get(contentId); - if (n == null) return null; - - // both .Draft and .Published cannot be null at the same time - return preview - ? n.Draft ?? GetPublishedContentAsPreviewing(n.Published) - : n.Published; + var node = _snapshot.Get(contentId); + return GetNodePublishedContent(node, preview); } public override IPublishedContent GetById(bool preview, Guid contentId) { - var n = _snapshot.Get(contentId); - if (n == null) return null; - - // both .Draft and .Published cannot be null at the same time - return preview - ? n.Draft ?? GetPublishedContentAsPreviewing(n.Published) - : n.Published; + var node = _snapshot.Get(contentId); + return GetNodePublishedContent(node, preview); } public override bool HasById(bool preview, int contentId) @@ -274,14 +264,24 @@ namespace Umbraco.Web.PublishedCache.NuCache var c = _snapshot.GetAtRoot(); // both .Draft and .Published cannot be null at the same time - return c.Select(n => preview - ? n.Draft ?? GetPublishedContentAsPreviewing(n.Published) - : n.Published).WhereNotNull().OrderBy(x => x.SortOrder); + return c.Select(n => GetNodePublishedContent(n, preview)).WhereNotNull().OrderBy(x => x.SortOrder); + } + + private static IPublishedContent GetNodePublishedContent(ContentNode node, bool preview) + { + if (node == null) + return null; + + // both .Draft and .Published cannot be null at the same time + + return preview + ? node.Draft ?? GetPublishedContentAsDraft(node.Published) + : node.Published; } // gets a published content as a previewing draft, if preview is true // this is for published content when previewing - internal static IPublishedContent GetPublishedContentAsPreviewing(IPublishedContent content /*, bool preview*/) + private static IPublishedContent GetPublishedContentAsDraft(IPublishedContent content /*, bool preview*/) { if (content == null /*|| preview == false*/) return null; //content; @@ -290,7 +290,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // case we need to unwrap to get to the original IPublishedContentOrMedia. var inner = PublishedContent.UnwrapIPublishedContent(content); - return inner.AsPreviewingModel(); + return inner.AsDraft(); } public override bool HasContent(bool preview) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs index be3e813275..0f120024cc 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/ContentNestedData.cs @@ -1,5 +1,6 @@ using Newtonsoft.Json; using System.Collections.Generic; +using Umbraco.Core.Serialization; namespace Umbraco.Web.PublishedCache.NuCache.DataSource { @@ -9,9 +10,11 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource internal class ContentNestedData { [JsonProperty("properties")] + [JsonConverter(typeof(CaseInsensitiveDictionaryConverter))] public Dictionary PropertyData { get; set; } [JsonProperty("cultureData")] + [JsonConverter(typeof(CaseInsensitiveDictionaryConverter))] public Dictionary CultureData { get; set; } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs index 50a2adaeb8..c6e603f5a9 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/CultureVariation.cs @@ -13,5 +13,8 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource [JsonProperty("date")] public DateTime Date { get; set; } + + [JsonProperty("isDraft")] + public bool IsDraft { get; set; } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs index a143997fab..4531d37b2b 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs @@ -182,27 +182,30 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource ContentData d = null; ContentData p = null; - if (dto.EditData == null) + if (dto.Edited) { - if (Debugger.IsAttached) - throw new Exception("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); - Current.Logger.Warn("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); - } - else - { - var nested = DeserializeNestedData(dto.EditData); - - d = new ContentData + if (dto.EditData == null) { - Name = dto.EditName, - Published = false, - TemplateId = dto.EditTemplateId, - VersionId = dto.VersionId, - VersionDate = dto.EditVersionDate, - WriterId = dto.EditWriterId, - Properties = nested.PropertyData, - CultureInfos = nested.CultureData - }; + if (Debugger.IsAttached) + throw new Exception("Missing cmsContentNu edited content for node " + dto.Id + ", consider rebuilding."); + Current.Logger.Warn("Missing cmsContentNu edited content for node {NodeId}, consider rebuilding.", dto.Id); + } + else + { + var nested = DeserializeNestedData(dto.EditData); + + d = new ContentData + { + Name = dto.EditName, + Published = false, + TemplateId = dto.EditTemplateId, + VersionId = dto.VersionId, + VersionDate = dto.EditVersionDate, + WriterId = dto.EditWriterId, + Properties = nested.PropertyData, + CultureInfos = nested.CultureData + }; + } } if (dto.Published) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs index ae34d0cb32..51badc8b9a 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/Navigable/NavigableContent.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.Navigable XmlString(i++, _content.WriterId), XmlString(i++, _content.CreatorId), XmlString(i++, _content.UrlSegment), - XmlString(i, _content.IsDraft) + XmlString(i, _content.IsDraft()) }; } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index a4610e82db..36e5698e32 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -273,8 +273,27 @@ namespace Umbraco.Web.PublishedCache.NuCache /// public override PublishedItemType ItemType => _contentNode.ContentType.ItemType; + // fixme + // was => _contentData.Published == false; /// - public override bool IsDraft => _contentData.Published == false; + public override bool IsDraft(string culture = null) + { + // if this is the 'published' published content, nothing can be draft + if (_contentData.Published) + return false; + + // not the 'published' published content, and does not vary = must be draft + if (!ContentType.VariesByCulture()) + return true; + + // handle context culture + if (culture == null) + culture = VariationContextAccessor?.VariationContext?.Culture ?? ""; + + // not the 'published' published content, and varies + // = depends on the culture + return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft; + } #endregion @@ -410,7 +429,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private string AsPreviewingCacheKey => _asPreviewingCacheKey ?? (_asPreviewingCacheKey = CacheKeys.PublishedContentAsPreviewing(Key)); // used by ContentCache - internal IPublishedContent AsPreviewingModel() + internal IPublishedContent AsDraft() { if (IsPreviewing) return this; diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 100833216e..4d6115f02d 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -1206,7 +1206,8 @@ namespace Umbraco.Web.PublishedCache.NuCache foreach (var (culture, info) in infos) { - cultureData[culture] = new CultureVariation { Name = info.Name, Date = content.GetUpdateDate(culture) ?? DateTime.MinValue }; + var cultureIsDraft = !published && content is IContent d && d.IsCultureEdited(culture); + cultureData[culture] = new CultureVariation { Name = info.Name, Date = content.GetUpdateDate(culture) ?? DateTime.MinValue, IsDraft = cultureIsDraft }; } } diff --git a/src/Umbraco.Web/PublishedCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/PublishedMember.cs index 44ce2328b7..56c8f440d8 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedMember.cs @@ -79,7 +79,7 @@ namespace Umbraco.Web.PublishedCache public override PublishedItemType ItemType => PublishedItemType.Member; - public override bool IsDraft => false; + public override bool IsDraft(string culture = null) => false; public override IPublishedContent Parent => null; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs index 7a8ce65ae3..4453fe7321 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs @@ -176,7 +176,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public override int Level => _level; - public override bool IsDraft => false; + public override bool IsDraft(string culture = null) => false; public override IEnumerable Properties => _properties; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index 3c143a6066..af867cc089 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -221,13 +221,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache } } - public override bool IsDraft + public override bool IsDraft(string culture = null) { - get - { - EnsureNodeInitialized(); - return _isDraft; - } + EnsureNodeInitialized(); + return _isDraft; // bah } public override IEnumerable Properties diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 2bc0d7be3f..eb47fd2f2d 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -141,50 +141,35 @@ namespace Umbraco.Web #endregion - // fixme - .HasValue() and .Value() refactoring - in progress - see exceptions below - - #region HasValue + #region HasValue, Value, Value /// /// Gets a value indicating whether the content has a value for a property identified by its alias. /// /// The content. /// The property alias. - /// A value indicating whether to navigate the tree upwards until a property with a value is found. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. /// A value indicating whether the content has a value for the property identified by the alias. - /// Returns true if GetProperty(alias, recurse) is not null and GetProperty(alias, recurse).HasValue is true. - public static bool HasValue(this IPublishedContent content, string alias, bool recurse) + /// Returns true if HasValue is true, or a fallback strategy can provide a value. + public static bool HasValue(this IPublishedContent content, string alias, string culture = null, string segment = null, Fallback fallback = default) { - throw new NotImplementedException("WorkInProgress"); + var property = content.GetProperty(alias); - //var prop = content.GetProperty(alias, recurse); - //return prop != null && prop.HasValue(); + // if we have a property, and it has a value, return that value + if (property != null && property.HasValue(culture, segment)) + return true; + + // else let fallback try to get a value + // fixme - really? + if (PublishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, null, out _)) + return true; + + // else... no + return false; } - /// - /// Returns one of two strings depending on whether the content has a value for a property identified by its alias. - /// - /// The content. - /// The property alias. - /// A value indicating whether to navigate the tree upwards until a property with a value is found. - /// The value to return if the content has a value for the property. - /// The value to return if the content has no value for the property. - /// Either or depending on whether the content - /// has a value for the property identified by the alias. - public static IHtmlString HasValue(this IPublishedContent content, string alias, bool recurse, - string valueIfTrue, string valueIfFalse = null) - { - throw new NotImplementedException("WorkInProgress"); - - //return content.HasValue(alias, recurse) - // ? new HtmlString(valueIfTrue) - // : new HtmlString(valueIfFalse ?? string.Empty); - } - - #endregion - - #region Value - /// /// Gets the value of a content's property identified by its alias, if it exists, otherwise a default value. /// @@ -207,15 +192,14 @@ namespace Umbraco.Web if (PublishedValueFallback.TryGetValue(content, alias, culture, segment, fallback, defaultValue, out var value)) return value; + if (property == null) + return null; + // else... if we have a property, at least let the converter return its own - // vision of 'no value' (could be an empty enumerable) - otherwise, default - return property?.GetValue(culture, segment); + // vision of 'no value' (could be an empty enumerable) + return property.GetValue(culture, segment); } - #endregion - - #region Value - /// /// Gets the value of a content's property identified by its alias, converted to a specified type. /// @@ -383,16 +367,6 @@ namespace Umbraco.Web return recursive && content.IsComposedOf(docTypeAlias); } - public static bool IsNull(this IPublishedContent content, string alias, bool recurse) - { - return content.HasValue(alias, recurse) == false; - } - - public static bool IsNull(this IPublishedContent content, string alias) - { - return content.HasValue(alias) == false; - } - #endregion #region IsSomething: equality diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index e8d395881c..219e2101be 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -467,9 +467,9 @@ namespace umbraco get { return PublishedItemType.Content; } } - public bool IsDraft + public bool IsDraft(string culture = null) { - get { throw new NotImplementedException(); } + throw new NotImplementedException(); } public IPublishedContent Parent From d8d04c54e669dd6ab8de65b0e3943af5a55059f2 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Dec 2018 08:33:54 +0100 Subject: [PATCH 07/23] Fix IOHelper for debugging other apps --- src/Umbraco.Core/IO/IOHelper.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/IO/IOHelper.cs b/src/Umbraco.Core/IO/IOHelper.cs index 2f1675e08a..7773f378a5 100644 --- a/src/Umbraco.Core/IO/IOHelper.cs +++ b/src/Umbraco.Core/IO/IOHelper.cs @@ -284,11 +284,12 @@ namespace Umbraco.Core.IO binFolder = Path.Combine(GetRootDirectorySafe(), "bin"); -#if DEBUG + // do this all the time (no #if DEBUG) because Umbraco release + // can be used in tests by an app (eg Deploy) being debugged var debugFolder = Path.Combine(binFolder, "debug"); if (Directory.Exists(debugFolder)) return debugFolder; -#endif + var releaseFolder = Path.Combine(binFolder, "release"); if (Directory.Exists(releaseFolder)) return releaseFolder; From 53c67fad632d29dc522c738b01d3f81b0e355967 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Dec 2018 10:39:39 +0100 Subject: [PATCH 08/23] Rework for #3866 --- .../Migrations/Install/DatabaseBuilder.cs | 154 +++++++++--------- .../Install/DatabaseSchemaCreator.cs | 7 +- .../Install/DatabaseSchemaResult.cs | 146 +++-------------- .../Persistence/SchemaValidationTest.cs | 1 - .../Controllers/InstallApiController.cs | 2 +- .../InstallSteps/DatabaseConfigureStep.cs | 6 +- .../InstallSteps/DatabaseInstallStep.cs | 2 +- .../InstallSteps/DatabaseUpgradeStep.cs | 16 +- 8 files changed, 108 insertions(+), 226 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index a54b997cb8..ccf2365deb 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -33,6 +33,9 @@ namespace Umbraco.Core.Migrations.Install private DatabaseSchemaResult _databaseSchemaValidationResult; + /// + /// Initializes a new instance of the class. + /// public DatabaseBuilder(IScopeProvider scopeProvider, IGlobalSettings globalSettings, IUmbracoDatabaseFactory databaseFactory, IRuntimeState runtime, ILogger logger, IMigrationBuilder migrationBuilder, IKeyValueService keyValueService, PostMigrationCollection postMigrations) { _scopeProvider = scopeProvider; @@ -49,23 +52,20 @@ namespace Umbraco.Core.Migrations.Install /// /// Gets a value indicating whether the database is configured. It does not necessarily - /// mean that it is possible to connect, nor that Umbraco is installed, nor - /// up-to-date. + /// mean that it is possible to connect, nor that Umbraco is installed, nor up-to-date. /// public bool IsDatabaseConfigured => _databaseFactory.Configured; /// - /// Gets a value indicating whether it is possible to connect to the database. + /// Gets a value indicating whether it is possible to connect to the configured database. + /// It does not necessarily mean that Umbraco is installed, nor up-to-date. /// - public bool CanConnect => _databaseFactory.CanConnect; + public bool CanConnectToDatabase => _databaseFactory.CanConnect; - // that method was originally created by Per in DatabaseHelper- tests the db connection for install - // fixed by Shannon to not-ignore the provider - // fixed by Stephan as part of the v8 persistence cleanup, now using provider names + SqlCe exception - // moved by Stephan to DatabaseBuilder - // probably needs to be cleaned up - - public bool CheckConnection(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth) + /// + /// Verifies whether a it is possible to connect to a database. + /// + public bool CanConnect(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth) { // we do not test SqlCE connection if (databaseType.InvariantContains("sqlce")) @@ -93,7 +93,7 @@ namespace Umbraco.Core.Migrations.Install return DbConnectionExtensions.IsConnectionAvailable(connectionString, providerName); } - public bool HasSomeNonDefaultUser() + internal bool HasSomeNonDefaultUser() { using (var scope = _scopeProvider.CreateScope()) { @@ -417,17 +417,24 @@ namespace Umbraco.Core.Migrations.Install #region Database Schema - public DatabaseSchemaResult ValidateDatabaseSchema() + /// + /// 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. + /// + internal DatabaseSchemaResult ValidateSchema() { using (var scope = _scopeProvider.CreateScope()) { - var result = ValidateDatabaseSchema(scope); + var result = ValidateSchema(scope); scope.Complete(); return result; } } - private DatabaseSchemaResult ValidateDatabaseSchema(IScope scope) + private DatabaseSchemaResult ValidateSchema(IScope scope) { if (_databaseFactory.Configured == false) return new DatabaseSchemaResult(_databaseFactory.SqlContext.SqlSyntax); @@ -442,17 +449,24 @@ namespace Umbraco.Core.Migrations.Install return _databaseSchemaValidationResult; } - public Result CreateDatabaseSchemaAndData() + /// + /// 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 = CreateDatabaseSchemaAndData(scope); + var result = CreateSchemaAndData(scope); scope.Complete(); return result; } } - private Result CreateDatabaseSchemaAndData(IScope scope) + private Result CreateSchemaAndData(IScope scope) { try { @@ -468,28 +482,14 @@ namespace Umbraco.Core.Migrations.Install // If MySQL, we're going to ensure that database calls are maintaining proper casing as to remove the necessity for checks // for case insensitive queries. In an ideal situation (which is what we're striving for), all calls would be case sensitive. - - /* - var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database); - if (supportsCaseInsensitiveQueries == false) - { - message = "

 

The database you're trying to use does not support case insensitive queries.
We currently do not support these types of databases.

" + - "

You can fix this by changing the following setting in your my.ini file in your MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

Note: Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - - return new Result { Message = message, Success = false, Percentage = "15" }; - } - */ - - var message = GetResultMessageForMySql(); - var schemaResult = ValidateDatabaseSchema(); - var installedSchemaVersion = schemaResult.DetermineInstalledVersion(); + var message = database.DatabaseType.IsMySql() ? ResultMessageForMySql : ""; + var schemaResult = ValidateSchema(); + var hasInstalledVersion = schemaResult.DetermineHasInstalledVersion(); + //var installedSchemaVersion = schemaResult.DetermineInstalledVersion(); + //var hasInstalledVersion = !installedSchemaVersion.Equals(new Version(0, 0, 0)); //If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing - if (string.IsNullOrEmpty(_globalSettings.ConfigurationStatus) && installedSchemaVersion.Equals(new Version(0, 0, 0))) + if (string.IsNullOrEmpty(_globalSettings.ConfigurationStatus) && !hasInstalledVersion) { if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); @@ -521,7 +521,14 @@ namespace Umbraco.Core.Migrations.Install } } - // This assumes all of the previous checks are done! + /// + /// 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() { try @@ -534,7 +541,7 @@ namespace Umbraco.Core.Migrations.Install _logger.Info("Database upgrade started"); - var message = GetResultMessageForMySql(); + var message = _scopeProvider.SqlContext.DatabaseType.IsMySql() ? ResultMessageForMySql : ""; // upgrade var upgrader = new UmbracoUpgrader(); @@ -554,47 +561,14 @@ namespace Umbraco.Core.Migrations.Install } } - private string GetResultMessageForMySql() - { - if (_databaseFactory.GetType() == typeof(MySqlSyntaxProvider)) - { - return "

 

Congratulations, the database step ran successfully!

" + - "

Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.

" + - "

However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries

" + - "

Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - } - return string.Empty; - } - - /* - private string GetResultMessageForMySql(bool? supportsCaseInsensitiveQueries) - { - if (supportsCaseInsensitiveQueries == null) - { - return "

 

Warning! Could not check if your database type supports case insensitive queries.
We currently do not support these databases that do not support case insensitive queries.

" + - "

You can check this by looking for the following setting in your my.ini file in your MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

Note: Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - } - if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider)) - { - return "

 

Congratulations, the database step ran successfully!

" + - "

Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.

" + - "

However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries

" + - "

Make sure to check with your hosting provider if they support case insensitive queries as well.

" + - "

They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:

" + - "
lower_case_table_names=1

" + - "

For more technical information on case sensitivity in MySQL, have a look at " + - "the documentation on the subject

"; - } - return string.Empty; - }*/ + private const string ResultMessageForMySql = "

 

Congratulations, the database step ran successfully!

" + + "

Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.

" + + "

However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries

" + + "

Make sure to check with your hosting provider if they support case insensitive queries as well.

" + + "

They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:

" + + "
lower_case_table_names=1

" + + "

For more technical information on case sensitivity in MySQL, have a look at " + + "the documentation on the subject

"; private Attempt CheckReadyForInstall() { @@ -630,11 +604,29 @@ namespace Umbraco.Core.Migrations.Install }; } + /// + /// Represents the result of a database creation or upgrade. + /// public class Result { + /// + /// Gets or sets ... fixme + /// 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 ... fixme + /// public string Percentage { get; set; } } diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs index 64be8161f2..eba5e61390 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaCreator.cs @@ -138,9 +138,8 @@ namespace Umbraco.Core.Migrations.Install { var result = new DatabaseSchemaResult(SqlSyntax); - //get the db index defs - result.DbIndexDefinitions = SqlSyntax.GetDefinedIndexes(_database) - .Select(x => new DbIndexDefinition(x)).ToArray(); + result.IndexDefinitions.AddRange(SqlSyntax.GetDefinedIndexes(_database) + .Select(x => new DbIndexDefinition(x))); result.TableDefinitions.AddRange(OrderedTables .Select(x => DefinitionFactory.GetTableDefinition(x, SqlSyntax))); @@ -279,7 +278,7 @@ namespace Umbraco.Core.Migrations.Install { //These are just column indexes NOT constraints or Keys //var colIndexesInDatabase = result.DbIndexDefinitions.Where(x => x.IndexName.InvariantStartsWith("IX_")).Select(x => x.IndexName).ToList(); - var colIndexesInDatabase = result.DbIndexDefinitions.Select(x => x.IndexName).ToList(); + var colIndexesInDatabase = result.IndexDefinitions.Select(x => x.IndexName).ToList(); var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList(); //Add valid and invalid index differences to the result object diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs index 0ec27cf0b1..4c68addebc 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseSchemaResult.cs @@ -2,153 +2,55 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using Umbraco.Core.Configuration; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Migrations.Install { - public class DatabaseSchemaResult + /// + /// Represents ... + /// + internal class DatabaseSchemaResult { - private readonly ISqlSyntaxProvider _sqlSyntax; + private readonly bool _isMySql; public DatabaseSchemaResult(ISqlSyntaxProvider sqlSyntax) { - _sqlSyntax = sqlSyntax; + _isMySql = sqlSyntax is MySqlSyntaxProvider; + Errors = new List>(); TableDefinitions = new List(); ValidTables = new List(); ValidColumns = new List(); ValidConstraints = new List(); ValidIndexes = new List(); + IndexDefinitions = new List(); } - public List> Errors { get; set; } + public List> Errors { get; } - public List TableDefinitions { get; set; } + public List TableDefinitions { get; } - public List ValidTables { get; set; } + // fixme TableDefinitions are those that should be there, IndexDefinitions are those that... are in DB? + internal List IndexDefinitions { get; } - public List ValidColumns { get; set; } + public List ValidTables { get; } - public List ValidConstraints { get; set; } + public List ValidColumns { get; } - public List ValidIndexes { get; set; } + public List ValidConstraints { get; } - internal IEnumerable DbIndexDefinitions { get; set; } + public List ValidIndexes { get; } /// - /// Determines the version of the currently installed database by detecting the current database structure + /// Determines whether the database contains an installed version. /// - /// - /// A with Major and Minor values for - /// non-empty database, otherwise "0.0.0" for empty databases. - /// - public Version DetermineInstalledVersion() + /// + /// A database contains an installed version when it contains at least one valid table. + /// + public bool DetermineHasInstalledVersion() { - // v8 = kill versions older than 7 - - //If (ValidTables.Count == 0) database is empty and we return -> new Version(0, 0, 0); - if (ValidTables.Count == 0) - return new Version(0, 0, 0); - - // FIXME - but the whole detection is borked really - return new Version(8, 0, 0); - - //If Errors is empty or if TableDefinitions tables + columns correspond to valid tables + columns then we're at current version - if (Errors.Any() == false || - (TableDefinitions.All(x => ValidTables.Contains(x.Name)) - && TableDefinitions.SelectMany(definition => definition.Columns).All(x => ValidColumns.Contains(x.Name)))) - return UmbracoVersion.Current; - - //If Errors contains umbracoApp or umbracoAppTree its pre-6.0.0 -> new Version(4, 10, 0); - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoApp") || x.Item2.InvariantEquals("umbracoAppTree")))) - { - //If Errors contains umbracoUser2app or umbracoAppTree foreignkey to umbracoApp exists its pre-4.8.0 -> new Version(4, 7, 0); - if (Errors.Any(x => - x.Item1.Equals("Constraint") - && (x.Item2.InvariantContains("umbracoUser2app_umbracoApp") - || x.Item2.InvariantContains("umbracoAppTree_umbracoApp")))) - { - return new Version(4, 7, 0); - } - - return new Version(4, 8, 0); - } - - //if the error is for umbracoServer - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoServer")))) - { - return new Version(6, 0, 0); - } - - //if the error indicates a problem with the column cmsMacroProperty.macroPropertyType then it is not version 7 - // since these columns get removed in v7 - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMacroProperty,macroPropertyType")))) - { - //if the error is for this IX_umbracoNodeTrashed which is added in 6.2 AND in 7.1 but we do not have the above columns - // then it must mean that we aren't on 6.2 so must be 6.1 - if (Errors.Any(x => x.Item1.Equals("Index") && (x.Item2.InvariantEquals("IX_umbracoNodeTrashed")))) - { - return new Version(6, 1, 0); - } - else - { - //if there are no errors for that index, then the person must have 6.2 installed - return new Version(6, 2, 0); - } - } - - //if the error indicates a problem with the constraint FK_cms-OBSOLETE-Content_cmsContentType_nodeId then it is not version 7.2 - // since this gets added in 7.2.0 so it must be the previous version - if (Errors.Any(x => x.Item1.Equals("Constraint") && (x.Item2.InvariantEquals("FK_cms-OBSOLETE-Content_cmsContentType_nodeId")))) - { - return new Version(7, 0, 0); - } - - //if the error is for umbracoAccess it must be the previous version to 7.3 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoAccess")))) - { - return new Version(7, 2, 0); - } - - //if the error is for cms-OBSOLETE-PropertyData.dataDecimal it must be the previous version to 7.4 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cms-OBSOLETE-PropertyData,dataDecimal")))) - { - return new Version(7, 3, 0); - } - - //if the error is for umbracoRedirectUrl it must be the previous version to 7.5 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoRedirectUrl")))) - { - return new Version(7, 4, 0); - } - - //if the error indicates a problem with the column cmsMacroProperty.uniquePropertyId then it is not version 7.6 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMacroProperty,uniquePropertyId")))) - { - return new Version(7, 5, 0); - } - - //if the error is for umbracoUserGroup it must be the previous version to 7.7 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoUserStartNode")))) - { - return new Version(7, 6, 0); - } - - //if the error is for cmsMedia it must be the previous version to 7.8 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Table") && (x.Item2.InvariantEquals("umbracoMedia")))) - { - return new Version(7, 7, 0); - } - - //if the error is for isSensitive column it must be the previous version to 7.9 since that is when it is added - if (Errors.Any(x => x.Item1.Equals("Column") && (x.Item2.InvariantEquals("cmsMemberType,isSensitive")))) - { - return new Version(7, 8, 0); - } - - return UmbracoVersion.Current; + return ValidTables.Count > 0; } /// @@ -200,9 +102,9 @@ namespace Umbraco.Core.Migrations.Install sb.AppendLine(" "); } - if (_sqlSyntax is MySqlSyntaxProvider) + if (_isMySql) { - sb.AppendLine("Please note that the constraints could not be validated because the current dataprovider is MySql."); + sb.AppendLine("Please note that the constraints could not be validated because the current data provider is MySql."); } return sb.ToString(); diff --git a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs index b8f1fab918..2c875d6afc 100644 --- a/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs +++ b/src/Umbraco.Tests/Persistence/SchemaValidationTest.cs @@ -26,7 +26,6 @@ namespace Umbraco.Tests.Persistence // Assert Assert.That(result.Errors.Count, Is.EqualTo(0)); - Assert.AreEqual(result.DetermineInstalledVersion(), UmbracoVersion.Current); } } } diff --git a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs index 387360163a..81b1aac217 100644 --- a/src/Umbraco.Web/Install/Controllers/InstallApiController.cs +++ b/src/Umbraco.Web/Install/Controllers/InstallApiController.cs @@ -41,7 +41,7 @@ namespace Umbraco.Web.Install.Controllers public bool PostValidateDatabaseConnection(DatabaseModel model) { - var canConnect = _databaseBuilder.CheckConnection(model.DatabaseType.ToString(), model.ConnectionString, model.Server, model.DatabaseName, model.Login, model.Password, model.IntegratedAuth); + var canConnect = _databaseBuilder.CanConnect(model.DatabaseType.ToString(), model.ConnectionString, model.Server, model.DatabaseName, model.Login, model.Password, model.IntegratedAuth); return canConnect; } diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs index a54b64733f..2fe6c0ceda 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseConfigureStep.cs @@ -1,7 +1,6 @@ using System; using System.Configuration; using Umbraco.Core; -using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Migrations.Install; using Umbraco.Web.Install.Models; @@ -29,7 +28,7 @@ namespace Umbraco.Web.Install.InstallSteps database = new DatabaseModel(); } - if (_databaseBuilder.CheckConnection(database.DatabaseType.ToString(), database.ConnectionString, database.Server, database.DatabaseName, database.Login, database.Password, database.IntegratedAuth) == false) + if (_databaseBuilder.CanConnect(database.DatabaseType.ToString(), database.ConnectionString, database.Server, database.DatabaseName, database.Login, database.Password, database.IntegratedAuth) == false) { throw new InstallException("Could not connect to the database"); } @@ -79,8 +78,7 @@ namespace Umbraco.Web.Install.InstallSteps try { //Since a connection string was present we verify the db can connect and query - var result = _databaseBuilder.ValidateDatabaseSchema(); - result.DetermineInstalledVersion(); + _ = _databaseBuilder.ValidateSchema(); return false; } catch (Exception ex) diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs index c4cad38072..a9daee6e95 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseInstallStep.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.Install.InstallSteps if (_runtime.Level == RuntimeLevel.Run) throw new Exception("Umbraco is already configured!"); - var result = _databaseBuilder.CreateDatabaseSchemaAndData(); + var result = _databaseBuilder.CreateSchemaAndData(); if (result.Success == false) { diff --git a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs index c078caf906..8283eb6bef 100644 --- a/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/DatabaseUpgradeStep.cs @@ -63,18 +63,10 @@ namespace Umbraco.Web.Install.InstallSteps if (_databaseBuilder.IsConnectionStringConfigured(databaseSettings)) { - //Since a connection string was present we verify whether this is an upgrade or an empty db - var result = _databaseBuilder.ValidateDatabaseSchema(); - - var determinedVersion = result.DetermineInstalledVersion(); - if (determinedVersion.Equals(new Version(0, 0, 0))) - { - //Fresh install - return false; - } - - //Upgrade - return true; + // a connection string was present, determine whether this is an install/upgrade + // return true (upgrade) if there is an installed version, else false (install) + var result = _databaseBuilder.ValidateSchema(); + return result.DetermineHasInstalledVersion(); } //no connection string configured, probably a fresh install From 792bf4003710a88fdfb0f54dbf18ae16049b9f98 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 18 Dec 2018 10:44:59 +0100 Subject: [PATCH 09/23] Rework for #3866 --- src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index ccf2365deb..ef6b3b720b 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -610,7 +610,7 @@ namespace Umbraco.Core.Migrations.Install public class Result { /// - /// Gets or sets ... fixme + /// Gets or sets a value indicating whether an upgrade is required. /// public bool RequiresUpgrade { get; set; } @@ -625,7 +625,7 @@ namespace Umbraco.Core.Migrations.Install public bool Success { get; set; } /// - /// Gets or sets ... fixme + /// Gets or sets an install progress pseudo-percentage. /// public string Percentage { get; set; } } From 9eecf9898e7e3b9b7f1081f00bdaec8fd680334c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Dec 2018 13:24:52 +0100 Subject: [PATCH 10/23] rebind keyboard shortcuts when infinite editors closes --- .../src/common/services/editor.service.js | 58 ++++++++++++++++++- 1 file changed, 55 insertions(+), 3 deletions(-) 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 0dbd27b7a5..5985cc99b1 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 @@ -78,8 +78,9 @@ (function () { "use strict"; - function editorService(eventsService) { + function editorService(eventsService, keyboardService) { + let editorsKeyboardShorcuts = []; var editors = []; /** @@ -120,6 +121,12 @@ */ function open(editor) { + /* keyboard shortcuts will be overwritten by the new infinite editor + so we need to store the shortcuts for the current editor so they can be rebound + when the infinite editor closes + */ + storeKeyboardShortcuts(); + // set flag so we know when the editor is open in "infinie mode" editor.infiniteMode = true; @@ -142,9 +149,9 @@ * Method to close the latest opened editor */ function close() { - var length = editors.length; - var closedEditor = editors[length - 1]; + // close last opened editor + const closedEditor = editors[editors.length - 1]; editors.splice(-1, 1); var args = { @@ -152,7 +159,12 @@ editor: closedEditor }; + // emit event to let components know an editor has been removed eventsService.emit("appState.editors.close", args); + + // rebind keyboard shortcuts for the new editor in focus + rebindKeyboardShortcuts(); + } /** @@ -652,6 +664,46 @@ open(editor); } + /////////////////////// + + /** + * @ngdoc method + * @name umbraco.services.editorService#storeKeyboardShortcuts + * @methodOf umbraco.services.editorService + * + * @description + * Internal method to keep track of keyboard shortcuts registered + * to each editor so they can be rebound when an editor closes + * + */ + function storeKeyboardShortcuts() { + const shortcuts = angular.copy(keyboardService.keyboardEvent); + editorsKeyboardShorcuts.push(shortcuts); + } + + /** + * @ngdoc method + * @name umbraco.services.editorService#rebindKeyboardShortcuts + * @methodOf umbraco.services.editorService + * + * @description + * Internal method to rebind keyboard shortcuts for the editor in focus + * + */ + function rebindKeyboardShortcuts() { + // find the shortcuts from the previous editor + const lastSetOfShortcutsIndex = editorsKeyboardShorcuts.length - 1; + var lastSetOfShortcuts = editorsKeyboardShorcuts[lastSetOfShortcutsIndex]; + + // rebind shortcuts + for (let [key, value] of Object.entries(lastSetOfShortcuts)) { + keyboardService.bind(key, value.callback, value.opt); + } + + // remove the shortcuts from the collection + editorsKeyboardShorcuts.splice(lastSetOfShortcutsIndex, 1); + } + var service = { getEditors: getEditors, getNumberOfEditors: getNumberOfEditors, From 88d328a4e962cf0d9a77298a35d6e2e981d63109 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Dec 2018 13:40:37 +0100 Subject: [PATCH 11/23] unbind all keyboard shortcuts from the underlaying editor so only keyboard shortcuts from the open editor works --- .../src/common/services/editor.service.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 5985cc99b1..541cc9aba3 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 @@ -125,7 +125,7 @@ so we need to store the shortcuts for the current editor so they can be rebound when the infinite editor closes */ - storeKeyboardShortcuts(); + unbindKeyboardShortcuts(); // set flag so we know when the editor is open in "infinie mode" editor.infiniteMode = true; @@ -676,9 +676,15 @@ * to each editor so they can be rebound when an editor closes * */ - function storeKeyboardShortcuts() { + function unbindKeyboardShortcuts() { const shortcuts = angular.copy(keyboardService.keyboardEvent); editorsKeyboardShorcuts.push(shortcuts); + + // unbind the current shortcuts because we only want to + // shortcuts from the newly opened editor working + for (let [key, value] of Object.entries(shortcuts)) { + keyboardService.unbind(key); + } } /** From abb4ab6b0aba36d1ab2cacf5215afab610c86586 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 18 Dec 2018 21:56:06 +0100 Subject: [PATCH 12/23] fix open template/open doctype buttons --- .../content/umbcontentnodeinfo.directive.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index 31e847f0f6..5da37ff64e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -21,14 +21,11 @@ scope.isInfiniteMode = editorService.getNumberOfEditors() > 0 ? true : false; userService.getCurrentUser().then(function(user){ - // only allow change of media type if user has access to the settings sections - angular.forEach(user.sections, function(section){ - if(section.alias === "settings" && !scope.isInfiniteMode) { - scope.allowChangeDocumentType = true; - scope.allowChangeTemplate = true; - } - }); - }); + // only allow change of media type if user has access to the settings sections + const hasAccessToSettings = user.allowedSections.indexOf("settings") !== -1 ? true : false; + scope.allowChangeDocumentType = hasAccessToSettings; + scope.allowChangeTemplate = hasAccessToSettings; + }); var keys = [ "general_deleted", From 0ad66c488bede675355bf7d5984cecb3b1d36728 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 19 Dec 2018 22:06:04 +1100 Subject: [PATCH 13/23] Long live Operathor --- .../Editors/TemplateQueryController.cs | 32 +++++++++---------- .../{Operathor.cs => Operator.cs} | 2 +- .../{OperathorTerm.cs => OperatorTerm.cs} | 12 +++---- .../Models/TemplateQuery/QueryCondition.cs | 20 ++++++------ src/Umbraco.Web/Umbraco.Web.csproj | 4 +-- 5 files changed, 35 insertions(+), 35 deletions(-) rename src/Umbraco.Web/Models/TemplateQuery/{Operathor.cs => Operator.cs} (90%) rename src/Umbraco.Web/Models/TemplateQuery/{OperathorTerm.cs => OperatorTerm.cs} (56%) diff --git a/src/Umbraco.Web/Editors/TemplateQueryController.cs b/src/Umbraco.Web/Editors/TemplateQueryController.cs index 0d0438138a..3122390047 100644 --- a/src/Umbraco.Web/Editors/TemplateQueryController.cs +++ b/src/Umbraco.Web/Editors/TemplateQueryController.cs @@ -18,26 +18,26 @@ namespace Umbraco.Web.Editors [JsonCamelCaseFormatter] public class TemplateQueryController : UmbracoAuthorizedJsonController { - private IEnumerable Terms + private IEnumerable Terms { get { - return new List() + return new List() { - new OperathorTerm(Services.TextService.Localize("template/is"), Operathor.Equals, new [] {"string"}), - new OperathorTerm(Services.TextService.Localize("template/isNot"), Operathor.NotEquals, new [] {"string"}), - new OperathorTerm(Services.TextService.Localize("template/before"), Operathor.LessThan, new [] {"datetime"}), - new OperathorTerm(Services.TextService.Localize("template/beforeIncDate"), Operathor.LessThanEqualTo, new [] {"datetime"}), - new OperathorTerm(Services.TextService.Localize("template/after"), Operathor.GreaterThan, new [] {"datetime"}), - new OperathorTerm(Services.TextService.Localize("template/afterIncDate"), Operathor.GreaterThanEqualTo, new [] {"datetime"}), - new OperathorTerm(Services.TextService.Localize("template/equals"), Operathor.Equals, new [] {"int"}), - new OperathorTerm(Services.TextService.Localize("template/doesNotEqual"), Operathor.NotEquals, new [] {"int"}), - new OperathorTerm(Services.TextService.Localize("template/contains"), Operathor.Contains, new [] {"string"}), - new OperathorTerm(Services.TextService.Localize("template/doesNotContain"), Operathor.NotContains, new [] {"string"}), - new OperathorTerm(Services.TextService.Localize("template/greaterThan"), Operathor.GreaterThan, new [] {"int"}), - new OperathorTerm(Services.TextService.Localize("template/greaterThanEqual"), Operathor.GreaterThanEqualTo, new [] {"int"}), - new OperathorTerm(Services.TextService.Localize("template/lessThan"), Operathor.LessThan, new [] {"int"}), - new OperathorTerm(Services.TextService.Localize("template/lessThanEqual"), Operathor.LessThanEqualTo, new [] {"int"}) + new OperatorTerm(Services.TextService.Localize("template/is"), Operator.Equals, new [] {"string"}), + new OperatorTerm(Services.TextService.Localize("template/isNot"), Operator.NotEquals, new [] {"string"}), + new OperatorTerm(Services.TextService.Localize("template/before"), Operator.LessThan, new [] {"datetime"}), + new OperatorTerm(Services.TextService.Localize("template/beforeIncDate"), Operator.LessThanEqualTo, new [] {"datetime"}), + new OperatorTerm(Services.TextService.Localize("template/after"), Operator.GreaterThan, new [] {"datetime"}), + new OperatorTerm(Services.TextService.Localize("template/afterIncDate"), Operator.GreaterThanEqualTo, new [] {"datetime"}), + new OperatorTerm(Services.TextService.Localize("template/equals"), Operator.Equals, new [] {"int"}), + new OperatorTerm(Services.TextService.Localize("template/doesNotEqual"), Operator.NotEquals, new [] {"int"}), + new OperatorTerm(Services.TextService.Localize("template/contains"), Operator.Contains, new [] {"string"}), + new OperatorTerm(Services.TextService.Localize("template/doesNotContain"), Operator.NotContains, new [] {"string"}), + new OperatorTerm(Services.TextService.Localize("template/greaterThan"), Operator.GreaterThan, new [] {"int"}), + new OperatorTerm(Services.TextService.Localize("template/greaterThanEqual"), Operator.GreaterThanEqualTo, new [] {"int"}), + new OperatorTerm(Services.TextService.Localize("template/lessThan"), Operator.LessThan, new [] {"int"}), + new OperatorTerm(Services.TextService.Localize("template/lessThanEqual"), Operator.LessThanEqualTo, new [] {"int"}) }; } } diff --git a/src/Umbraco.Web/Models/TemplateQuery/Operathor.cs b/src/Umbraco.Web/Models/TemplateQuery/Operator.cs similarity index 90% rename from src/Umbraco.Web/Models/TemplateQuery/Operathor.cs rename to src/Umbraco.Web/Models/TemplateQuery/Operator.cs index 561caec362..135c43507e 100644 --- a/src/Umbraco.Web/Models/TemplateQuery/Operathor.cs +++ b/src/Umbraco.Web/Models/TemplateQuery/Operator.cs @@ -1,6 +1,6 @@ namespace Umbraco.Web.Models.TemplateQuery { - public enum Operathor + public enum Operator { Equals = 1, NotEquals = 2, diff --git a/src/Umbraco.Web/Models/TemplateQuery/OperathorTerm.cs b/src/Umbraco.Web/Models/TemplateQuery/OperatorTerm.cs similarity index 56% rename from src/Umbraco.Web/Models/TemplateQuery/OperathorTerm.cs rename to src/Umbraco.Web/Models/TemplateQuery/OperatorTerm.cs index c14e1854aa..086f0ff818 100644 --- a/src/Umbraco.Web/Models/TemplateQuery/OperathorTerm.cs +++ b/src/Umbraco.Web/Models/TemplateQuery/OperatorTerm.cs @@ -2,24 +2,24 @@ namespace Umbraco.Web.Models.TemplateQuery { - public class OperathorTerm + public class OperatorTerm { - public OperathorTerm() + public OperatorTerm() { Name = "is"; - Operathor = Operathor.Equals; + Operator = Operator.Equals; AppliesTo = new [] { "string" }; } - public OperathorTerm(string name, Operathor operathor, IEnumerable appliesTo) + public OperatorTerm(string name, Operator @operator, IEnumerable appliesTo) { Name = name; - Operathor = operathor; + Operator = @operator; AppliesTo = appliesTo; } public string Name { get; set; } - public Operathor Operathor { get; set; } + public Operator Operator { get; set; } public IEnumerable AppliesTo { get; set; } } } diff --git a/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs b/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs index 8ba943756f..9c5f2c80c0 100644 --- a/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs +++ b/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs @@ -4,7 +4,7 @@ { public PropertyModel Property { get; set; } - public OperathorTerm Term { get; set; } + public OperatorTerm Term { get; set; } public string ConstraintValue { get; set; } } @@ -53,30 +53,30 @@ } - switch (condition.Term.Operathor) + switch (condition.Term.Operator) { - case Operathor.Equals: + case Operator.Equals: operand = " == "; break; - case Operathor.NotEquals: + case Operator.NotEquals: operand = " != "; break; - case Operathor.GreaterThan: + case Operator.GreaterThan: operand = " > "; break; - case Operathor.GreaterThanEqualTo: + case Operator.GreaterThanEqualTo: operand = " >= "; break; - case Operathor.LessThan: + case Operator.LessThan: operand = " < "; break; - case Operathor.LessThanEqualTo: + case Operator.LessThanEqualTo: operand = " <= "; break; - case Operathor.Contains: + case Operator.Contains: value = string.Format("{0}{1}.Contains({2})", prefix, condition.Property.Alias, constraintValue); break; - case Operathor.NotContains: + case Operator.NotContains: value = string.Format("!{0}{1}.Contains({2})", prefix, condition.Property.Alias, constraintValue); break; default : diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 699c985af3..c7e8b0d109 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -685,8 +685,8 @@ - - + + From f72474822574554786dbd56994bb648c4d5dd538 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 19 Dec 2018 23:27:47 +1100 Subject: [PATCH 14/23] No more IUserService.SavePassword - passwords are managed with Identity. --- src/Umbraco.Core/Services/IUserService.cs | 10 -------- .../Services/Implement/UserService.cs | 24 ------------------- .../Editors/TemplateQueryController.cs | 1 + 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/Umbraco.Core/Services/IUserService.cs b/src/Umbraco.Core/Services/IUserService.cs index cb2d90aa63..a926ce32aa 100644 --- a/src/Umbraco.Core/Services/IUserService.cs +++ b/src/Umbraco.Core/Services/IUserService.cs @@ -90,16 +90,6 @@ namespace Umbraco.Core.Services string[] userGroups = null, string filter = null); - /// - /// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method - /// - /// - /// This method exists so that Umbraco developers can use one entry point to create/update users if they choose to. - /// - /// The user to save the password for - /// The password to save - void SavePassword(IUser user, string password); - /// /// Deletes or disables a User /// diff --git a/src/Umbraco.Core/Services/Implement/UserService.cs b/src/Umbraco.Core/Services/Implement/UserService.cs index 44358caa84..188c6feb04 100644 --- a/src/Umbraco.Core/Services/Implement/UserService.cs +++ b/src/Umbraco.Core/Services/Implement/UserService.cs @@ -227,30 +227,6 @@ namespace Umbraco.Core.Services.Implement Save(membershipUser); } - [Obsolete("ASP.NET Identity APIs like the BackOfficeUserManager should be used to manage passwords, this will not work with correct security practices because you would need the existing password")] - [EditorBrowsable(EditorBrowsableState.Never)] - public void SavePassword(IUser user, string password) - { - if (user == null) throw new ArgumentNullException(nameof(user)); - - var provider = MembershipProviderExtensions.GetUsersMembershipProvider(); - - if (provider.IsUmbracoMembershipProvider() == false) - throw new NotSupportedException("When using a non-Umbraco membership provider you must change the user password by using the MembershipProvider.ChangePassword method"); - - provider.ChangePassword(user.Username, "", password); - - //go re-fetch the member and update the properties that may have changed - var result = GetByUsername(user.Username); - if (result != null) - { - //should never be null but it could have been deleted by another thread. - user.RawPasswordValue = result.RawPasswordValue; - user.LastPasswordChangeDate = result.LastPasswordChangeDate; - user.UpdateDate = result.UpdateDate; - } - } - /// /// Deletes or disables a User /// diff --git a/src/Umbraco.Web/Editors/TemplateQueryController.cs b/src/Umbraco.Web/Editors/TemplateQueryController.cs index 3122390047..00e124cb29 100644 --- a/src/Umbraco.Web/Editors/TemplateQueryController.cs +++ b/src/Umbraco.Web/Editors/TemplateQueryController.cs @@ -67,6 +67,7 @@ namespace Umbraco.Web.Editors sb.Append("Model.Root()"); + //fixme: This timer thing is not correct, it's definitely not timing the resulting query, the timer really isn't important and might as well be removed var timer = new Stopwatch(); timer.Start(); From cf56dbd34e43628c9b1bbc15489e048e54c96800 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 19 Dec 2018 13:43:58 +0100 Subject: [PATCH 15/23] add more docs for infinite editing - how to create a custom infinite editor --- .../src/common/services/editor.service.js | 114 +++++++++++++++--- 1 file changed, 99 insertions(+), 15 deletions(-) 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 541cc9aba3..0d6432b01f 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 @@ -5,29 +5,29 @@ * @description * Added in Umbraco 8.0. Application-wide service for handling infinite editing. * + * * + * +

Open a build-in infinite editor (media picker)

Markup example

-    
- - - +
+

Controller example

     (function () {
-
         "use strict";
 
-        function Controller() {
+        function MediaPickerController(editorService) {
 
             var vm = this;
 
-            vm.open = open;
+            vm.openMediaPicker = openMediaPicker;
 
-            function open() {
+            function openMediaPicker() {
                 var mediaPickerOptions = {
                     multiPicker: true,
                     submit: function(model) {
@@ -36,22 +36,29 @@
                     close: function() {
                         editorService.close();
                     }
-                }
+                };
                 editorService.mediaPicker(mediaPickerOptions);
             };
         }
 
-        angular.module("umbraco").controller("My.Controller", Controller);
+        angular.module("umbraco").controller("My.MediaPickerController", MediaPickerController);
     })();
 
-

Custom view example

+

Building a custom infinite editor

+

Open the custom infinite editor (Markup)

+
+    
+ +
+
+ +

Open the custom infinite editor (Controller)

     (function () {
-
         "use strict";
 
-        function Controller() {
+        function Controller(editorService) {
 
             var vm = this;
 
@@ -59,14 +66,15 @@
 
             function open() {
                 var options = {
-                    view: "path/to/view.html"
+                    title: "My custom infinite editor",
+                    view: "path/to/view.html",
                     submit: function(model) {
                         editorService.close();
                     },
                     close: function() {
                         editorService.close();
                     }
-                }
+                };
                 editorService.open(options);
             };
         }
@@ -74,7 +82,83 @@
         angular.module("umbraco").controller("My.Controller", Controller);
     })();
 
+ +

The custom infinite editor view

+When building a custom infinite editor view you can use the same components as a normal editor ({@link umbraco.directives.directive:umbEditorView umbEditorView}). +
+    
+ + + + + + + + + + {{model | json}} + + + + + + + + + + + + + + + +
+
+ +

The custom infinite editor controller

+
+    (function () {
+        "use strict";
+
+        function InfiniteEditorController($scope) {
+
+            var vm = this;
+
+            vm.submit = submit;
+            vm.close = close;
+
+            function submit() {
+                if($scope.model.submit) {
+                    $scope.model.submit($scope.model);
+                }
+            }
+
+            function close() {
+                if($scope.model.close) {
+                    $scope.model.close();
+                }
+            }
+
+        }
+
+        angular.module("umbraco").controller("My.InfiniteEditorController", InfiniteEditorController);
+    })();
+
*/ + (function () { "use strict"; From b81f2512cb8a5c91210b4098848364549b2a142e Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Wed, 19 Dec 2018 15:01:18 +0100 Subject: [PATCH 16/23] Fix the disappearing preview/save/publish buttons in listviews (#3906) --- .../components/content/edit.controller.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index f1e2150579..8564cf2c43 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -24,16 +24,19 @@ $scope.page.hideActionsMenu = infiniteMode ? true : false; $scope.page.hideChangeVariant = infiniteMode ? true : false; $scope.allowOpen = true; + $scope.app = null; function init(content) { - - // set first app to active - content.apps[0].active = true; + if (!$scope.app) { + // set first app to active + content.apps[0].active = true; + $scope.app = content.apps[0]; + } if (infiniteMode) { createInfiniteModeButtons(content); } else { - createButtons(content, content.apps[0]); + createButtons(content); } editorState.set($scope.content); @@ -146,11 +149,11 @@ * @param {any} content the content node * @param {any} app the active content app */ - function createButtons(content, app) { + function createButtons(content) { // only create the save/publish/preview buttons if the // content app is "Conent" - if (app && app.alias !== "umbContent" && app.alias !== "umbInfo") { + if ($scope.app && $scope.app.alias !== "umbContent" && $scope.app.alias !== "umbInfo") { $scope.defaultButton = null; $scope.subButtons = null; $scope.page.showSaveButton = false; @@ -899,7 +902,8 @@ * @param {any} app */ $scope.appChanged = function (app) { - createButtons($scope.content, app); + $scope.app = app; + createButtons($scope.content); }; // methods for infinite editing From 7b804e27ad2a6c7d90f6e78a2c7d7fdfba0972d7 Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Fri, 14 Dec 2018 12:20:04 +0000 Subject: [PATCH 17/23] Removes umbraco.aspx --- .../Configurations/GlobalSettingsTests.cs | 3 +- .../CoreThings/UriExtensionsTests.cs | 6 +-- .../Routing/UmbracoModuleTests.cs | 3 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 8 ---- src/Umbraco.Web.UI/Umbraco/config/lang/de.xml | 4 +- src/Umbraco.Web.UI/Umbraco/umbraco.aspx | 2 - src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs | 19 --------- .../Umbraco/umbraco.aspx.designer.cs | 15 ------- src/Umbraco.Web.UI/default.aspx | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 3 -- .../umbraco/Default.aspx.cs | 39 ------------------- 11 files changed, 7 insertions(+), 97 deletions(-) delete mode 100644 src/Umbraco.Web.UI/Umbraco/umbraco.aspx delete mode 100644 src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/umbraco.aspx.designer.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/Default.aspx.cs diff --git a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs index ebba8bc1cc..34fb2add8b 100644 --- a/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs +++ b/src/Umbraco.Tests/Configurations/GlobalSettingsTests.cs @@ -52,8 +52,7 @@ namespace Umbraco.Tests.Configurations SystemDirectories.Root = rootPath; Assert.AreEqual(outcome, UmbracoConfig.For.GlobalSettings().GetUmbracoMvcArea()); } - - [TestCase("/umbraco/umbraco.aspx")] + [TestCase("/umbraco/editContent.aspx")] [TestCase("/install/default.aspx")] [TestCase("/install/")] diff --git a/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs b/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs index 7f00bed123..f253d44973 100644 --- a/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs +++ b/src/Umbraco.Tests/CoreThings/UriExtensionsTests.cs @@ -32,8 +32,7 @@ namespace Umbraco.Tests.CoreThings [TestCase("http://www.domain.com/umbraco/test/test.js", "", true)] [TestCase("http://www.domain.com/umbrac", "", false)] [TestCase("http://www.domain.com/test", "", false)] - [TestCase("http://www.domain.com/test/umbraco", "", false)] - [TestCase("http://www.domain.com/test/umbraco.aspx", "", false)] + [TestCase("http://www.domain.com/test/umbraco", "", false)] [TestCase("http://www.domain.com/Umbraco/restServices/blah", "", true)] [TestCase("http://www.domain.com/Umbraco/Backoffice/blah", "", true)] [TestCase("http://www.domain.com/Umbraco/anything", "", true)] @@ -62,8 +61,7 @@ namespace Umbraco.Tests.CoreThings [TestCase("http://www.domain.com/install/test/test.js", true)] [TestCase("http://www.domain.com/instal", false)] [TestCase("http://www.domain.com/umbraco", false)] - [TestCase("http://www.domain.com/umbraco/umbraco", false)] - [TestCase("http://www.domain.com/test/umbraco.aspx", false)] + [TestCase("http://www.domain.com/umbraco/umbraco", false)] public void Is_Installer_Request(string input, bool expected) { var source = new Uri(input); diff --git a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs index 5f42c8d3ae..69533c3c77 100644 --- a/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs +++ b/src/Umbraco.Tests/Routing/UmbracoModuleTests.cs @@ -62,8 +62,7 @@ namespace Umbraco.Tests.Routing // do not test for /base here as it's handled before EnsureUmbracoRoutablePage is called [TestCase("/umbraco_client/Tree/treeIcons.css", false)] - [TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", false)] - [TestCase("/umbraco/umbraco.aspx", false)] + [TestCase("/umbraco_client/Tree/Themes/umbraco/style.css?cdv=37", false)] [TestCase("/umbraco/editContent.aspx", false)] [TestCase("/install/default.aspx", false)] [TestCase("/install/?installStep=license", false)] diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 5751e9155c..b4a020deea 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -218,14 +218,6 @@ - - - umbraco.aspx - ASPXCodeBehind - - - umbraco.aspx - diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml index b2296b1ccf..0edabebb76 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/de.xml @@ -881,7 +881,7 @@ das Dokument '%1%' wurde von '%2%' zur Übersetzung in '%5%' freigegeben. Zum Bearbeiten verwenden Sie bitte diesen Link: http://%3%/translation/details.aspx?id=%4%. -Sie können sich auch alle anstehenden Übersetzungen gesammelt im Umbraco-Verwaltungsbereich anzeigen lassen: http://%3%/Umbraco.aspx +Sie können sich auch alle anstehenden Übersetzungen gesammelt im Umbraco-Verwaltungsbereich anzeigen lassen: http://%3%/umbraco Einen schönen Tag wünscht Ihr freundlicher Umbraco-Robot @@ -977,4 +977,4 @@ Ihr freundlicher Umbraco-Robot Ihr Verlauf Sitzung läuft ab in - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx b/src/Umbraco.Web.UI/Umbraco/umbraco.aspx deleted file mode 100644 index 6e70513afd..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx +++ /dev/null @@ -1,2 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="umbraco.aspx.cs" Inherits="Umbraco.Web.UI.Umbraco.umbraco" %> - diff --git a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs b/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs deleted file mode 100644 index b70378bb01..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; -using Umbraco.Core.Configuration; - -namespace Umbraco.Web.UI.Umbraco -{ - public partial class umbraco : System.Web.UI.Page - { - protected void Page_Load(object sender, EventArgs e) - { - Response.Status = "301 Moved Permanently"; - Response.AddHeader("Location", UmbracoConfig.For.GlobalSettings().Path); - } - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.designer.cs b/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.designer.cs deleted file mode 100644 index c9a577fb34..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/umbraco.aspx.designer.cs +++ /dev/null @@ -1,15 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Umbraco.Web.UI.Umbraco { - - - public partial class umbraco { - } -} diff --git a/src/Umbraco.Web.UI/default.aspx b/src/Umbraco.Web.UI/default.aspx index 75b0e5d28c..a41d1eccf7 100644 --- a/src/Umbraco.Web.UI/default.aspx +++ b/src/Umbraco.Web.UI/default.aspx @@ -1,2 +1,2 @@ -<%@ Page language="c#" Codebehind="default.aspx.cs" AutoEventWireup="True" Inherits="umbraco.UmbracoDefault" trace="true" validateRequest="false" %> +<%@ Page language="c#" AutoEventWireup="True" Inherits="umbraco.UmbracoDefault" trace="true" validateRequest="false" %> diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index c7e8b0d109..ea3ff32220 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1166,9 +1166,6 @@ ASPXCodeBehind - - ASPXCodeBehind - ASPXCodeBehind diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/Default.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/Default.aspx.cs deleted file mode 100644 index f1a05c1185..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/Default.aspx.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using System.Collections; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Web; -using System.Web.Mvc; -using System.Web.SessionState; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Web.UI.HtmlControls; - -namespace umbraco -{ - /// - /// Summary description for _Default. - /// - public partial class _Default : System.Web.UI.Page - { - protected void Page_Load(object sender, System.EventArgs e) - { - //var mvcHandler = new MvcHandler() - //Server.TransferRequest(); - //Server.Transfer("~/Umbraco/Default"); - //Server.Transfer("umbraco.aspx"); - // Put user code to initialize the page here - } - - /// - /// Form1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlForm Form1; - - } -} From b087b862e8ed82cb03c9a3d05f420f23cb23c663 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 26 Nov 2018 08:56:13 +0100 Subject: [PATCH 18/23] Make Nested Content support variant doctypes --- .../PropertyEditors/NestedContentPropertyEditor.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs index 07c5aac5bb..74c8744ead 100644 --- a/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/NestedContentPropertyEditor.cs @@ -175,13 +175,17 @@ namespace Umbraco.Web.PropertyEditors { // create a temp property with the value var tempProp = new Property(propType); - tempProp.SetValue(propValues[propAlias] == null ? null : propValues[propAlias].ToString()); + // if the property varies by culture, make sure we save using the current culture + var propCulture = propType.VariesByCulture() || propType.VariesByCultureAndSegment() + ? culture + : null; + tempProp.SetValue(propValues[propAlias] == null ? null : propValues[propAlias].ToString(), propCulture); // convert that temp property, and store the converted value var propEditor = _propertyEditors[propType.PropertyEditorAlias]; var tempConfig = dataTypeService.GetDataType(propType.DataTypeId).Configuration; var valEditor = propEditor.GetValueEditor(tempConfig); - var convValue = valEditor.ToEditor(tempProp, dataTypeService); + var convValue = valEditor.ToEditor(tempProp, dataTypeService, propCulture); propValues[propAlias] = convValue == null ? null : JToken.FromObject(convValue); } catch (InvalidOperationException) From c79f557e946598cb48c54bcbea61afc0c8d8d2d1 Mon Sep 17 00:00:00 2001 From: Thomas Morris Date: Fri, 14 Dec 2018 15:57:34 +0000 Subject: [PATCH 19/23] Remove ClientRedirect.aspx --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 1 - .../Umbraco/ClientRedirect.aspx | 64 ------------------- 2 files changed, 65 deletions(-) delete mode 100644 src/Umbraco.Web.UI/Umbraco/ClientRedirect.aspx diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index b4a020deea..8e76894e7a 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -213,7 +213,6 @@ - diff --git a/src/Umbraco.Web.UI/Umbraco/ClientRedirect.aspx b/src/Umbraco.Web.UI/Umbraco/ClientRedirect.aspx deleted file mode 100644 index 2a10d4d344..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/ClientRedirect.aspx +++ /dev/null @@ -1,64 +0,0 @@ -<%@ Page Language="C#" AutoEventWireup="true" Inherits="Umbraco.Web.UI.Pages.UmbracoEnsuredPage" %> -<%-- - This page is required because we cannot reload the angular app with a changed Hash since it just detects the hash and doesn't reload. - So this is used purely for a full reload of an angular app with a changed hash. ---%> - - - - Redirecting... - - - - Redirecting... - - From 65f7e44338118520193feb881ca1f535f32ee7de Mon Sep 17 00:00:00 2001 From: Tristan Thompson Date: Fri, 14 Dec 2018 13:11:36 +0000 Subject: [PATCH 20/23] Remove/Replace endPreview.aspx with MVC endpoint --- .../UmbracoSettings/ContentElement.cs | 2 +- .../UmbracoSettings/ContentElementTests.cs | 2 +- .../UmbracoSettings/umbracoSettings.config | 2 +- .../src/preview/preview.controller.js | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 1 - src/Umbraco.Web.UI/Umbraco/endPreview.aspx | 3 -- .../config/umbracoSettings.Release.config | 2 +- .../config/umbracoSettings.config | 2 +- src/Umbraco.Web/Editors/PreviewController.cs | 18 ++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 3 -- .../umbraco/endPreview.aspx.cs | 36 ------------------- 11 files changed, 24 insertions(+), 49 deletions(-) delete mode 100644 src/Umbraco.Web.UI/Umbraco/endPreview.aspx delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/endPreview.aspx.cs diff --git a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs index d2236bab70..91627edb8b 100644 --- a/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs +++ b/src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs @@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings { internal class ContentElement : UmbracoConfigurationElement, IContentSection { - private const string DefaultPreviewBadge = @"In Preview Mode - click to end"; + private const string DefaultPreviewBadge = @"In Preview Mode - click to end"; [ConfigurationProperty("imaging")] internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"]; diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs index f1ac463305..962d6d13a9 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/ContentElementTests.cs @@ -143,7 +143,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings [Test] public void PreviewBadge() { - Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"In Preview Mode - click to end"); + Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"In Preview Mode - click to end"); } [Test] public void ResolveUrlsFromTextString() diff --git a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config index a436dad9f5..4c64485503 100644 --- a/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config +++ b/src/Umbraco.Tests/Configurations/UmbracoSettings/umbracoSettings.config @@ -77,7 +77,7 @@ In Preview Mode - click to end + In Preview Mode - click to end ]]> diff --git a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config index 42c8b01e24..df6fe953fe 100644 --- a/src/Umbraco.Web.UI/config/umbracoSettings.Release.config +++ b/src/Umbraco.Web.UI/config/umbracoSettings.Release.config @@ -41,7 +41,7 @@ In Preview Mode - click to end + In Preview Mode - click to end ]]> In Preview Mode - click to end + In Preview Mode - click to end ]]> diff --git a/src/Umbraco.Web/Editors/PreviewController.cs b/src/Umbraco.Web/Editors/PreviewController.cs index 6a91d20ae0..6e119d68d9 100644 --- a/src/Umbraco.Web/Editors/PreviewController.cs +++ b/src/Umbraco.Web/Editors/PreviewController.cs @@ -88,5 +88,23 @@ namespace Umbraco.Web.Editors // if (string.IsNullOrEmpty(editor)) throw new ArgumentNullException(nameof(editor)); // return View(_globalSettings.Path.EnsureEndsWith('/') + "Views/Preview/" + editor.Replace(".html", string.Empty) + ".cshtml"); //} + + public ActionResult End(string redir = null) + { + var previewToken = Request.GetPreviewCookieValue(); + var service = Current.PublishedSnapshotService; + service.ExitPreview(previewToken); + + System.Web.HttpContext.Current.ExpireCookie(Constants.Web.PreviewCookieName); + + if (Uri.IsWellFormedUriString(redir, UriKind.Relative) + && redir.StartsWith("//") == false + && Uri.TryCreate(redir, UriKind.Relative, out Uri url)) + { + return Redirect(url.ToString()); + } + + return Redirect("/"); + } } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index ea3ff32220..d64e3dcd81 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -525,9 +525,6 @@ - - ASPXCodeBehind - diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/endPreview.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/endPreview.aspx.cs deleted file mode 100644 index 822f346705..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/endPreview.aspx.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Web; -using System.Web.UI; -using Umbraco.Core; -using Umbraco.Web; -using Umbraco.Web.Composing; -using Umbraco.Web.PublishedCache; - -namespace umbraco.presentation -{ - public class endPreview : Page - { - protected void Page_Load(object sender, EventArgs e) - { - var request = (new HttpRequestWrapper(Request)); - - var previewToken = request.GetPreviewCookieValue(); - var service = Current.PublishedSnapshotService; - service.ExitPreview(previewToken); - - HttpContext.Current.ExpireCookie(Constants.Web.PreviewCookieName); - - var redir = Request.QueryString["redir"]; - Uri url = null; - - if (Uri.IsWellFormedUriString(redir, UriKind.Relative) == false - || redir.StartsWith("//") - || Uri.TryCreate(redir, UriKind.Relative, out url) == false) - { - Response.Redirect("/", true); - } - - Response.Redirect(url.ToString(), true); - } - } -} From 6365f910bc577aa971313d33e1f6750e67761906 Mon Sep 17 00:00:00 2001 From: Gregory Dove <35264602+g-dove@users.noreply.github.com> Date: Wed, 19 Dec 2018 14:58:06 +0000 Subject: [PATCH 21/23] Better Validation Options (#3882) --- .../propertysettings/propertysettings.controller.js | 4 ++-- .../infiniteeditors/propertysettings/propertysettings.html | 2 +- src/Umbraco.Web.UI/Umbraco/config/lang/en.xml | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js index 7239fd22e7..89987a3f27 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.controller.js @@ -17,7 +17,7 @@ vm.showValidationPattern = false; vm.focusOnPatternField = false; vm.focusOnMandatoryField = false; - vm.selectedValidationType = {}; + vm.selectedValidationType = null; vm.validationTypes = []; vm.labels = {}; @@ -238,4 +238,4 @@ angular.module("umbraco").controller("Umbraco.Editors.PropertySettingsController", PropertySettingsEditor); -})(); \ No newline at end of file +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html index 610af28cb8..df5bbe8ca5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/propertysettings/propertysettings.html @@ -90,7 +90,7 @@