From ec24ebf93c67db5214c4cde2a9cb0c9508713b61 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Tue, 11 Dec 2018 17:00:43 +0100 Subject: [PATCH 001/213] Fix media type copying and move media type service unit tests to a separate class --- src/Umbraco.Core/Models/ContentType.cs | 3 + src/Umbraco.Core/Models/ContentTypeBase.cs | 4 +- src/Umbraco.Core/Models/MediaType.cs | 26 +-- ...peServiceBaseOfTRepositoryTItemTService.cs | 4 +- .../Services/ContentTypeServiceTests.cs | 116 +---------- .../Services/MediaTypeServiceTests.cs | 195 ++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 7 files changed, 209 insertions(+), 140 deletions(-) create mode 100644 src/Umbraco.Tests/Services/MediaTypeServiceTests.cs diff --git a/src/Umbraco.Core/Models/ContentType.cs b/src/Umbraco.Core/Models/ContentType.cs index e6439acade..4b9831682c 100644 --- a/src/Umbraco.Core/Models/ContentType.cs +++ b/src/Umbraco.Core/Models/ContentType.cs @@ -160,5 +160,8 @@ namespace Umbraco.Core.Models return result; } + + /// + IContentType IContentType.DeepCloneWithResetIdentities(string newAlias) => (IContentType)DeepCloneWithResetIdentities(newAlias); } } diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index caa63d7526..79c2d4218b 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -492,9 +492,9 @@ namespace Umbraco.Core.Models } } - public IContentType DeepCloneWithResetIdentities(string alias) + public ContentTypeBase DeepCloneWithResetIdentities(string alias) { - var clone = (ContentType)DeepClone(); + var clone = (ContentTypeBase)DeepClone(); clone.Alias = alias; clone.Key = Guid.Empty; foreach (var propertyGroup in clone.PropertyGroups) diff --git a/src/Umbraco.Core/Models/MediaType.cs b/src/Umbraco.Core/Models/MediaType.cs index 4ae2fd190c..83e1acfbc0 100644 --- a/src/Umbraco.Core/Models/MediaType.cs +++ b/src/Umbraco.Core/Models/MediaType.cs @@ -44,29 +44,7 @@ namespace Umbraco.Core.Models /// public override bool IsPublishing => IsPublishingConst; - /// - /// Creates a deep clone of the current entity with its identity/alias and it's property identities reset - /// - /// - public new IMediaType DeepCloneWithResetIdentities(string alias) - { - var clone = (MediaType)DeepClone(); - clone.Alias = alias; - clone.Key = Guid.Empty; - foreach (var propertyGroup in clone.PropertyGroups) - { - propertyGroup.ResetIdentity(); - propertyGroup.ResetDirtyProperties(false); - } - foreach (var propertyType in clone.PropertyTypes) - { - propertyType.ResetIdentity(); - propertyType.ResetDirtyProperties(false); - } - - clone.ResetIdentity(); - clone.ResetDirtyProperties(false); - return clone; - } + /// + IMediaType IMediaType.DeepCloneWithResetIdentities(string newAlias) => (IMediaType)DeepCloneWithResetIdentities(newAlias); } } diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index b74abc03f7..feff81978c 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -594,7 +594,7 @@ namespace Umbraco.Core.Services.Implement //var originalb = (ContentTypeCompositionBase)original; // but we *know* it has to be a ContentTypeCompositionBase anyways var originalb = (ContentTypeCompositionBase) (object) original; - var clone = (TItem) originalb.DeepCloneWithResetIdentities(alias); + var clone = (TItem) (object) originalb.DeepCloneWithResetIdentities(alias); clone.Name = name; @@ -645,7 +645,7 @@ namespace Umbraco.Core.Services.Implement //var copyingb = (ContentTypeCompositionBase) copying; // but we *know* it has to be a ContentTypeCompositionBase anyways var copyingb = (ContentTypeCompositionBase) (object)copying; - copy = (TItem) copyingb.DeepCloneWithResetIdentities(alias); + copy = (TItem) (object) copyingb.DeepCloneWithResetIdentities(alias); copy.Name = copy.Name + " (copy)"; // might not be unique diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index bc0854bdb7..30067b3c5a 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -376,46 +376,6 @@ namespace Umbraco.Tests.Services Assert.IsNull(doc2.GetValue("title", "en-US")); } - [Test] - public void Deleting_Media_Type_With_Hierarchy_Of_Media_Items_Moves_Orphaned_Media_To_Recycle_Bin() - { - IMediaType contentType1 = MockedContentTypes.CreateSimpleMediaType("test1", "Test1"); - ServiceContext.MediaTypeService.Save(contentType1); - IMediaType contentType2 = MockedContentTypes.CreateSimpleMediaType("test2", "Test2"); - ServiceContext.MediaTypeService.Save(contentType2); - IMediaType contentType3 = MockedContentTypes.CreateSimpleMediaType("test3", "Test3"); - ServiceContext.MediaTypeService.Save(contentType3); - - var contentTypes = new[] { contentType1, contentType2, contentType3 }; - var parentId = -1; - - var ids = new List(); - - for (int i = 0; i < 2; i++) - { - for (var index = 0; index < contentTypes.Length; index++) - { - var contentType = contentTypes[index]; - var contentItem = MockedMedia.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); - ServiceContext.MediaService.Save(contentItem); - parentId = contentItem.Id; - - ids.Add(contentItem.Id); - } - } - - //delete the first content type, all other content of different content types should be in the recycle bin - ServiceContext.MediaTypeService.Delete(contentTypes[0]); - - var found = ServiceContext.MediaService.GetByIds(ids); - - Assert.AreEqual(4, found.Count()); - foreach (var content in found) - { - Assert.IsTrue(content.Trashed); - } - } - [Test] public void Deleting_Content_Type_With_Hierarchy_Of_Content_Items_Moves_Orphaned_Content_To_Recycle_Bin() { @@ -460,60 +420,6 @@ namespace Umbraco.Tests.Services } } - [Test] - public void Deleting_Media_Types_With_Hierarchy_Of_Media_Items_Doesnt_Raise_Trashed_Event_For_Deleted_Items() - { - MediaService.Trashed += MediaServiceOnTrashed; - - try - { - IMediaType contentType1 = MockedContentTypes.CreateSimpleMediaType("test1", "Test1"); - ServiceContext.MediaTypeService.Save(contentType1); - IMediaType contentType2 = MockedContentTypes.CreateSimpleMediaType("test2", "Test2"); - ServiceContext.MediaTypeService.Save(contentType2); - IMediaType contentType3 = MockedContentTypes.CreateSimpleMediaType("test3", "Test3"); - ServiceContext.MediaTypeService.Save(contentType3); - - var contentTypes = new[] { contentType1, contentType2, contentType3 }; - var parentId = -1; - - var ids = new List(); - - for (int i = 0; i < 2; i++) - { - for (var index = 0; index < contentTypes.Length; index++) - { - var contentType = contentTypes[index]; - var contentItem = MockedMedia.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); - ServiceContext.MediaService.Save(contentItem); - parentId = contentItem.Id; - - ids.Add(contentItem.Id); - } - } - - foreach (var contentType in contentTypes.Reverse()) - { - ServiceContext.MediaTypeService.Delete(contentType); - } - } - finally - { - MediaService.Trashed -= MediaServiceOnTrashed; - } - } - - private void MediaServiceOnTrashed(IMediaService sender, MoveEventArgs e) - { - foreach (var item in e.MoveInfoCollection) - { - //if this item doesn't exist then Fail! - var exists = ServiceContext.MediaService.GetById(item.Entity.Id); - if (exists == null) - Assert.Fail("The item doesn't exist"); - } - } - [Test] public void Deleting_Content_Types_With_Hierarchy_Of_Content_Items_Doesnt_Raise_Trashed_Event_For_Deleted_Items_1() { @@ -1078,12 +984,13 @@ namespace Umbraco.Tests.Services var metaContentType = MockedContentTypes.CreateMetaContentType(); service.Save(metaContentType); - var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType); + var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", metaContentType) as IContentType; service.Save(simpleContentType); var categoryId = simpleContentType.Id; // Act var sut = simpleContentType.DeepCloneWithResetIdentities("newcategory"); + Assert.IsNotNull(sut); service.Save(sut); // Assert @@ -1115,11 +1022,12 @@ namespace Umbraco.Tests.Services var parentContentType2 = MockedContentTypes.CreateSimpleContentType("parent2", "Parent2", null, true); service.Save(parentContentType2); - var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", parentContentType1, true); + var simpleContentType = MockedContentTypes.CreateSimpleContentType("category", "Category", parentContentType1, true) as IContentType; service.Save(simpleContentType); // Act var clone = simpleContentType.DeepCloneWithResetIdentities("newcategory"); + Assert.IsNotNull(clone); clone.RemoveContentType("parent1"); clone.AddContentType(parentContentType2); clone.ParentId = parentContentType2.Id; @@ -2068,22 +1976,6 @@ namespace Umbraco.Tests.Services Assert.IsNull(contentType2.Description); } - [Test] - public void Empty_Description_Is_Always_Null_After_Saving_Media_Type() - { - var service = ServiceContext.MediaTypeService; - var mediaType = MockedContentTypes.CreateSimpleMediaType("mediaType", "Media Type"); - mediaType.Description = null; - service.Save(mediaType); - - var mediaType2 = MockedContentTypes.CreateSimpleMediaType("mediaType2", "Media Type 2"); - mediaType2.Description = string.Empty; - service.Save(mediaType2); - - Assert.IsNull(mediaType.Description); - Assert.IsNull(mediaType2.Description); - } - [Test] public void Variations_In_Compositions() { diff --git a/src/Umbraco.Tests/Services/MediaTypeServiceTests.cs b/src/Umbraco.Tests/Services/MediaTypeServiceTests.cs new file mode 100644 index 0000000000..915dc5ceec --- /dev/null +++ b/src/Umbraco.Tests/Services/MediaTypeServiceTests.cs @@ -0,0 +1,195 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using NUnit.Framework; +using Umbraco.Core.Events; +using Umbraco.Core.Models; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Implement; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Tests.Testing; + +namespace Umbraco.Tests.Services +{ + [TestFixture] + [Apartment(ApartmentState.STA)] + [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] + public class MediaTypeServiceTests : TestWithSomeContentBase + { + [Test] + public void Empty_Description_Is_Always_Null_After_Saving_Media_Type() + { + var mediaType = MockedContentTypes.CreateSimpleMediaType("mediaType", "Media Type"); + mediaType.Description = null; + ServiceContext.MediaTypeService.Save(mediaType); + + var mediaType2 = MockedContentTypes.CreateSimpleMediaType("mediaType2", "Media Type 2"); + mediaType2.Description = string.Empty; + ServiceContext.MediaTypeService.Save(mediaType2); + + Assert.IsNull(mediaType.Description); + Assert.IsNull(mediaType2.Description); + } + + [Test] + public void Deleting_Media_Type_With_Hierarchy_Of_Media_Items_Moves_Orphaned_Media_To_Recycle_Bin() + { + IMediaType contentType1 = MockedContentTypes.CreateSimpleMediaType("test1", "Test1"); + ServiceContext.MediaTypeService.Save(contentType1); + IMediaType contentType2 = MockedContentTypes.CreateSimpleMediaType("test2", "Test2"); + ServiceContext.MediaTypeService.Save(contentType2); + IMediaType contentType3 = MockedContentTypes.CreateSimpleMediaType("test3", "Test3"); + ServiceContext.MediaTypeService.Save(contentType3); + + var contentTypes = new[] { contentType1, contentType2, contentType3 }; + var parentId = -1; + + var ids = new List(); + + for (int i = 0; i < 2; i++) + { + for (var index = 0; index < contentTypes.Length; index++) + { + var contentType = contentTypes[index]; + var contentItem = MockedMedia.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); + ServiceContext.MediaService.Save(contentItem); + parentId = contentItem.Id; + + ids.Add(contentItem.Id); + } + } + + //delete the first content type, all other content of different content types should be in the recycle bin + ServiceContext.MediaTypeService.Delete(contentTypes[0]); + + var found = ServiceContext.MediaService.GetByIds(ids); + + Assert.AreEqual(4, found.Count()); + foreach (var content in found) + { + Assert.IsTrue(content.Trashed); + } + } + + [Test] + public void Deleting_Media_Types_With_Hierarchy_Of_Media_Items_Doesnt_Raise_Trashed_Event_For_Deleted_Items() + { + MediaService.Trashed += MediaServiceOnTrashed; + + try + { + IMediaType contentType1 = MockedContentTypes.CreateSimpleMediaType("test1", "Test1"); + ServiceContext.MediaTypeService.Save(contentType1); + IMediaType contentType2 = MockedContentTypes.CreateSimpleMediaType("test2", "Test2"); + ServiceContext.MediaTypeService.Save(contentType2); + IMediaType contentType3 = MockedContentTypes.CreateSimpleMediaType("test3", "Test3"); + ServiceContext.MediaTypeService.Save(contentType3); + + var contentTypes = new[] { contentType1, contentType2, contentType3 }; + var parentId = -1; + + var ids = new List(); + + for (int i = 0; i < 2; i++) + { + for (var index = 0; index < contentTypes.Length; index++) + { + var contentType = contentTypes[index]; + var contentItem = MockedMedia.CreateSimpleMedia(contentType, "MyName_" + index + "_" + i, parentId); + ServiceContext.MediaService.Save(contentItem); + parentId = contentItem.Id; + + ids.Add(contentItem.Id); + } + } + + foreach (var contentType in contentTypes.Reverse()) + { + ServiceContext.MediaTypeService.Delete(contentType); + } + } + finally + { + MediaService.Trashed -= MediaServiceOnTrashed; + } + } + + private void MediaServiceOnTrashed(IMediaService sender, MoveEventArgs e) + { + foreach (var item in e.MoveInfoCollection) + { + //if this item doesn't exist then Fail! + var exists = ServiceContext.MediaService.GetById(item.Entity.Id); + if (exists == null) + Assert.Fail("The item doesn't exist"); + } + } + + [Test] + public void Can_Copy_MediaType_By_Performing_Clone() + { + // Arrange + var mediaType = MockedContentTypes.CreateImageMediaType("Image2") as IMediaType; + ServiceContext.MediaTypeService.Save(mediaType); + + // Act + var sut = mediaType.DeepCloneWithResetIdentities("Image2_2"); + Assert.IsNotNull(sut); + ServiceContext.MediaTypeService.Save(sut); + + // Assert + Assert.That(sut.HasIdentity, Is.True); + Assert.AreEqual(mediaType.ParentId, sut.ParentId); + Assert.AreEqual(mediaType.Level, sut.Level); + Assert.AreEqual(mediaType.PropertyTypes.Count(), sut.PropertyTypes.Count()); + Assert.AreNotEqual(mediaType.Id, sut.Id); + Assert.AreNotEqual(mediaType.Key, sut.Key); + Assert.AreNotEqual(mediaType.Path, sut.Path); + Assert.AreNotEqual(mediaType.SortOrder, sut.SortOrder); + Assert.AreNotEqual(mediaType.PropertyTypes.First(x => x.Alias.Equals("umbracoFile")).Id, sut.PropertyTypes.First(x => x.Alias.Equals("umbracoFile")).Id); + Assert.AreNotEqual(mediaType.PropertyGroups.First(x => x.Name.Equals("Media")).Id, sut.PropertyGroups.First(x => x.Name.Equals("Media")).Id); + } + + [Test] + public void Can_Copy_MediaType_To_New_Parent_By_Performing_Clone() + { + // Arrange + var parentMediaType1 = MockedContentTypes.CreateSimpleMediaType("parent1", "Parent1"); + ServiceContext.MediaTypeService.Save(parentMediaType1); + var parentMediaType2 = MockedContentTypes.CreateSimpleMediaType("parent2", "Parent2", null, true); + ServiceContext.MediaTypeService.Save(parentMediaType2); + var mediaType = MockedContentTypes.CreateImageMediaType("Image2") as IMediaType; + ServiceContext.MediaTypeService.Save(mediaType); + + // Act + var clone = mediaType.DeepCloneWithResetIdentities("newcategory"); + Assert.IsNotNull(clone); + clone.RemoveContentType("parent1"); + clone.AddContentType(parentMediaType2); + clone.ParentId = parentMediaType2.Id; + ServiceContext.MediaTypeService.Save(clone); + + // Assert + Assert.That(clone.HasIdentity, Is.True); + + var clonedMediaType = ServiceContext.MediaTypeService.Get(clone.Id); + var originalMediaType = ServiceContext.MediaTypeService.Get(mediaType.Id); + + Assert.That(clonedMediaType.CompositionAliases().Any(x => x.Equals("parent2")), Is.True); + Assert.That(clonedMediaType.CompositionAliases().Any(x => x.Equals("parent1")), Is.False); + + Assert.AreEqual(clonedMediaType.Path, "-1," + parentMediaType2.Id + "," + clonedMediaType.Id); + Assert.AreEqual(clonedMediaType.PropertyTypes.Count(), originalMediaType.PropertyTypes.Count()); + + Assert.AreNotEqual(clonedMediaType.ParentId, originalMediaType.ParentId); + Assert.AreEqual(clonedMediaType.ParentId, parentMediaType2.Id); + + Assert.AreNotEqual(clonedMediaType.Id, originalMediaType.Id); + Assert.AreNotEqual(clonedMediaType.Key, originalMediaType.Key); + Assert.AreNotEqual(clonedMediaType.Path, originalMediaType.Path); + + Assert.AreNotEqual(clonedMediaType.PropertyTypes.First(x => x.Alias.StartsWith("umbracoFile")).Id, originalMediaType.PropertyTypes.First(x => x.Alias.StartsWith("umbracoFile")).Id); + Assert.AreNotEqual(clonedMediaType.PropertyGroups.First(x => x.Name.StartsWith("Media")).Id, originalMediaType.PropertyGroups.First(x => x.Name.StartsWith("Media")).Id); + } + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index 7147cc8453..1286248b86 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -132,6 +132,7 @@ + From 862d5227587039969f3f06c52acad9a7c9d170c9 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 14 Jan 2019 22:53:19 +0100 Subject: [PATCH 002/213] Fix the styling of the search box on the redirect url management dashboard --- .../src/views/dashboard/content/redirecturls.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/content/redirecturls.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/content/redirecturls.html index 837c24cb0c..a06984f31e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/content/redirecturls.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/content/redirecturls.html @@ -29,7 +29,7 @@ - From 8aaaf4439abf7f5b57bc7a3fb4444118e8855d47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 17 Jan 2019 10:12:28 +0100 Subject: [PATCH 003/213] Changed UI for resizable handler --- .../src/less/application/grid.less | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/application/grid.less b/src/Umbraco.Web.UI.Client/src/less/application/grid.less index a7b4bd0011..073d1b5721 100644 --- a/src/Umbraco.Web.UI.Client/src/less/application/grid.less +++ b/src/Umbraco.Web.UI.Client/src/less/application/grid.less @@ -41,9 +41,9 @@ body { #mainwrapper { position: absolute; - top: 0; - left: 0; - right: 0; + top: 0; + left: 0; + right: 0; bottom: 0; margin: 0; } @@ -56,10 +56,10 @@ body.umb-drawer-is-visible #mainwrapper{ position: absolute; top: 0px; bottom: 0px; - right: 0px; + right: 0px; left: 0px; z-index: 10; - margin: 0 + margin: 0; } #umb-notifications-wrapper { @@ -151,17 +151,23 @@ body.umb-drawer-is-visible #mainwrapper{ } .ui-resizable-e { - cursor: e-resize; - width: 4px; + cursor: col-resize; + width: 10px; right: -5px; top: 0; bottom: 0; - background-color: @gray-10; - border: solid 1px @purple-l3; - border-top: none; - border-bottom: none; position:absolute; z-index:9999 !important; + + &:hover::after { + content: ''; + position: absolute; + background-color: @gray-8; + top: 0; + bottom: 0; + width: 1px; + right: 5px; + } } @media (min-width: 1101px) { From d6c2fec5d20d4e3f8c69cb1b90d18ca45b060526 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 17 Jan 2019 10:16:04 +0100 Subject: [PATCH 004/213] Added UI hover for expansion panel --- .../src/less/components/html/umb-expansion-panel.less | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less index 26347c8501..2d1cbd10ff 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less @@ -13,6 +13,10 @@ cursor: pointer; justify-content: space-between; color: @black; + + &:hover .umb-expansion-panel__expand { + color: @gray-6; + } } .umb-expansion-panel__expand { @@ -22,4 +26,4 @@ .umb-expansion-panel__content { padding: 20px; border-top: 1px solid @gray-9; -} \ No newline at end of file +} From 4bf17c8a4e29e5ccac9f337c3aa525a3333e4cce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Fri, 18 Jan 2019 13:19:16 +0100 Subject: [PATCH 005/213] V8 UI Color adjustments --- src/Umbraco.Web.UI.Client/src/less/buttons.less | 4 ++-- .../src/less/components/editor.less | 15 ++++++++------- .../less/components/html/umb-expansion-panel.less | 2 +- src/Umbraco.Web.UI.Client/src/less/forms.less | 5 +++-- .../src/less/property-editors.less | 9 +++------ src/Umbraco.Web.UI.Client/src/less/variables.less | 5 +++-- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/buttons.less b/src/Umbraco.Web.UI.Client/src/less/buttons.less index 0b21864127..ca048ccc92 100644 --- a/src/Umbraco.Web.UI.Client/src/less/buttons.less +++ b/src/Umbraco.Web.UI.Client/src/less/buttons.less @@ -233,7 +233,7 @@ input[type="button"] { // outlined .btn-outline { - border: 1px solid @gray-8; + border: 1px solid @inputBorder; background: @white; color: @black; padding: 5px 13px; @@ -242,7 +242,7 @@ input[type="button"] { .btn-outline:hover, .btn-outline:focus, .btn-outline:active { - border-color: @gray-7; + border-color: @inputBorderFocus; background: transparent; color: @black; } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor.less b/src/Umbraco.Web.UI.Client/src/less/components/editor.less index d699193c24..b91ad239dc 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor.less @@ -88,8 +88,7 @@ } input.umb-editor-header__name-input { - border-color: transparent; - background-color: @white; + font-size: 15px; color: @black; margin-bottom: 0; @@ -98,11 +97,13 @@ input.umb-editor-header__name-input { height: 32px; line-height: 32px; width: 100%; - padding: 0 10px; - background: @white; - border: 1px solid @gray-8; - &:hover { - border-color: @turquoise-d1; + padding-left: 10px; + + background-color: @white; + border: 1px solid @inputBorder; + + &:focus { + border-color: @inputBorderFocus; } } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less index 26347c8501..3612bf6958 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/html/umb-expansion-panel.less @@ -13,6 +13,7 @@ cursor: pointer; justify-content: space-between; color: @black; + border-bottom: 1px solid @gray-9; } .umb-expansion-panel__expand { @@ -21,5 +22,4 @@ .umb-expansion-panel__content { padding: 20px; - border-top: 1px solid @gray-9; } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/less/forms.less b/src/Umbraco.Web.UI.Client/src/less/forms.less index e3350b4956..81f3298783 100644 --- a/src/Umbraco.Web.UI.Client/src/less/forms.less +++ b/src/Umbraco.Web.UI.Client/src/less/forms.less @@ -243,11 +243,12 @@ input[type="color"], .uneditable-input { background-color: @inputBackground; border: 1px solid @inputBorder; + .transition(~"border linear .2s, box-shadow linear .2s"); // Focus state &:focus { - border-color: none; + border-color: @inputBorderFocus; outline: 0; outline: none \9; /* IE6-9 */ } @@ -817,4 +818,4 @@ legend + .control-group { /* User/group selector */ .group-selector .group-selector-list { float: left; } .group-selector .group-selector-list div { height: 24px; } -.group-selector .group-selector-buttons { float: left; margin: 24px 16px; } +.group-selector .group-selector-buttons { float: left; margin: 24px 16px; } \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 3ec8c383da..e6d3ab90e4 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -4,12 +4,9 @@ // Container styles // -------------------------------------------------- .umb-property-editor { - @media (max-width: 800px) { - width: 100%; - } - @media (min-width: 800px) { - min-width:66.6%; - } + + width: 100%; + max-width: 800px; &-pull { float:left; diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index 513c645365..97d33096e6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -278,7 +278,8 @@ // Forms // ------------------------- @inputBackground: @white; -@inputBorder: @gray-7; +@inputBorder: @gray-8; +@inputBorderFocus: @gray-7; @inputBorderRadius: 0; @inputDisabledBackground: @gray-10; @formActionsBackground: @gray-9; @@ -517,4 +518,4 @@ // SORTABLE // -------------------------------------------------- @sortableHelperBg: @turquoise-l2; -@sortablePlaceholderBg : @turquoise; +@sortablePlaceholderBg : @turquoise; \ No newline at end of file From 60d86354f391067606dfe3080edf7a1cd2f22c4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Mon, 21 Jan 2019 09:46:00 +0100 Subject: [PATCH 006/213] Media Picker adjustments --- src/Umbraco.Web.UI.Client/src/less/main.less | 3 +- .../src/less/property-editors.less | 41 +++++++++++++++---- .../src/less/variables.less | 3 +- .../mediapicker/mediapicker.html | 2 +- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 12a13e11ed..43bc87ed0f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -120,7 +120,7 @@ h5.-black { margin: 20px; } .umb-control-group { - border-bottom: 1px solid @gray-10; + border-bottom: 1px solid @gray-11; padding-bottom: 20px; margin-bottom: 15px !important; } @@ -671,4 +671,3 @@ input[type=checkbox]:checked + .input-label--small { width: 1px !important; overflow: hidden; } - diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index e6d3ab90e4..210178e0a6 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -4,9 +4,12 @@ // Container styles // -------------------------------------------------- .umb-property-editor { - - width: 100%; - max-width: 800px; + @media (max-width: 800px) { + width: 100%; + } + @media (min-width: 800px) { + min-width:66.6%; + } &-pull { float:left; @@ -227,6 +230,18 @@ // // Media picker // -------------------------------------------------- + +.umb-mediapicker > div { + border: 1px solid @inputBorder; +} +.umb-mediapicker-single > div { + width:144px; +} +.umb-mediapicker-multi > div { + width:100%; +} + + .umb-mediapicker .add-link { display: flex; justify-content:center; @@ -327,19 +342,28 @@ justify-content: center; align-items: center; flex-wrap: wrap; - padding: 2px; + padding: 5px; margin: 5px; background: @white; - border: 1px solid @gray-10; + //border: 1px solid @gray-10; max-width: 100%; } +.umb-mediapicker { + + .umb-sortable-thumbnails li { + border:none; + } + +} + .umb-mediapicker .umb-sortable-thumbnails li { flex-direction: column; - margin: 0 0 5px 5px; - padding: 5px; } +/*.umb-mediapicker .umb-sortable-thumbnails li.add-wrapper { + padding: 0px; +}*/ .umb-sortable-thumbnails li:hover a { display: flex; @@ -442,6 +466,9 @@ align-items: center; margin-left: 5px; text-decoration: none; + + //border-color: @inputBorder; + .box-shadow(0 1px 2px rgba(0,0,0,0.25)); } .umb-sortable-thumbnails .umb-sortable-thumbnails__action.-red { diff --git a/src/Umbraco.Web.UI.Client/src/less/variables.less b/src/Umbraco.Web.UI.Client/src/less/variables.less index 97d33096e6..c9cd0f701c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/variables.less +++ b/src/Umbraco.Web.UI.Client/src/less/variables.less @@ -88,6 +88,7 @@ @gray-8: #D8D7D9; @gray-9: #E9E9EB; @gray-10: #F3F3F5; +@gray-11: #F6F6F7; // Additional Icon Colours @@ -518,4 +519,4 @@ // SORTABLE // -------------------------------------------------- @sortableHelperBg: @turquoise-l2; -@sortablePlaceholderBg : @turquoise; \ No newline at end of file +@sortablePlaceholderBg : @turquoise; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html index 4e85668c05..d2b923b17c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.html @@ -1,4 +1,4 @@ -
+

From ad026e25d71218a624a356ea06d8bda35394bf68 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 22 Jan 2019 09:31:47 +0100 Subject: [PATCH 007/213] Cleanup trees --- .../Editors/BackOfficeServerVariables.cs | 70 ++++++++-------- .../Mvc/PluginControllerAttribute.cs | 20 +++-- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 12 +-- .../Search/SearchableTreeCollection.cs | 2 +- src/Umbraco.Web/Services/ITreeService.cs | 33 +++----- src/Umbraco.Web/Services/TreeService.cs | 57 ++++--------- .../Trees/ApplicationTreeController.cs | 2 +- .../Trees/ContentBlueprintTreeController.cs | 4 +- .../Trees/ContentTypeTreeController.cs | 4 +- src/Umbraco.Web/Trees/CoreTreeAttribute.cs | 13 +-- .../Trees/DataTypeTreeController.cs | 6 +- .../Trees/DictionaryTreeController.cs | 4 +- src/Umbraco.Web/Trees/FilesTreeController.cs | 9 +- src/Umbraco.Web/Trees/ITree.cs | 9 +- .../Trees/LanguageTreeController.cs | 4 +- src/Umbraco.Web/Trees/MacrosTreeController.cs | 4 +- .../Trees/MediaTypeTreeController.cs | 4 +- .../Trees/MemberGroupTreeController.cs | 2 +- src/Umbraco.Web/Trees/MemberTreeController.cs | 2 +- .../Trees/MemberTypeTreeController.cs | 4 +- .../Trees/PackagesTreeController.cs | 2 +- .../Trees/PartialViewMacrosTreeController.cs | 4 +- .../Trees/PartialViewsTreeController.cs | 4 +- .../Trees/RelationTypeTreeController.cs | 4 +- .../Trees/ScriptsTreeController.cs | 4 +- .../Trees/StylesheetsTreeController.cs | 4 +- .../Trees/TemplatesTreeController.cs | 4 +- src/Umbraco.Web/Trees/Tree.cs | 31 ++++--- src/Umbraco.Web/Trees/TreeAttribute.cs | 83 +++++++++---------- src/Umbraco.Web/Trees/TreeCollection.cs | 12 +-- .../Trees/TreeCollectionBuilder.cs | 50 +++++++++-- src/Umbraco.Web/Trees/TreeController.cs | 52 ++++++------ src/Umbraco.Web/Trees/TreeControllerBase.cs | 23 ++--- src/Umbraco.Web/Trees/UserTreeController.cs | 2 +- src/Umbraco.Web/TypeLoaderExtensions.cs | 29 ++----- .../UI/Pages/UmbracoEnsuredPage.cs | 2 +- .../Filters/UmbracoTreeAuthorizeAttribute.cs | 2 +- 37 files changed, 277 insertions(+), 300 deletions(-) diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 40891efe9e..d8d580dcd0 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -3,6 +3,7 @@ using System.Collections; using System.Collections.Generic; using System.Configuration; using System.Linq; +using System.Runtime.Serialization; using System.Web; using System.Web.Configuration; using System.Web.Mvc; @@ -348,7 +349,10 @@ namespace Umbraco.Web.Editors { "umbracoPlugins", new Dictionary { - {"trees", GetTreePluginsMetaData()} + // for each tree that is [PluginController], get + // alias -> areaName + // so that routing (route.js) can look for views + { "trees", GetPluginTrees().ToArray() } } }, { @@ -389,43 +393,41 @@ namespace Umbraco.Web.Editors return defaultVals; } - private IEnumerable> GetTreePluginsMetaData() + private class PluginTree { - var treeTypes = TreeControllerTypes.Value; - //get all plugin trees with their attributes - var treesWithAttributes = treeTypes.Select(x => new - { - tree = x, - attributes = - x.GetCustomAttributes(false) - }).ToArray(); - - var pluginTreesWithAttributes = treesWithAttributes - //don't resolve any tree decorated with CoreTreeAttribute - .Where(x => x.attributes.All(a => (a is CoreTreeAttribute) == false)) - //we only care about trees with the PluginControllerAttribute - .Where(x => x.attributes.Any(a => a is PluginControllerAttribute)) - .ToArray(); - - return (from p in pluginTreesWithAttributes - let treeAttr = p.attributes.OfType().Single() - let pluginAttr = p.attributes.OfType().Single() - select new Dictionary - { - {"alias", treeAttr.TreeAlias}, {"packageFolder", pluginAttr.AreaName} - }).ToArray(); + [DataMember(Name = "alias")] + public string Alias { get; set; } + [DataMember(Name = "packageFolder")] + public string PackageFolder { get; set; } } - /// - /// A lazy reference to all tree controller types - /// - /// - /// We are doing this because if we constantly resolve the tree controller types from the PluginManager it will re-scan and also re-log that - /// it's resolving which is unecessary and annoying. - /// - private static readonly Lazy> TreeControllerTypes - = new Lazy>(() => Current.TypeLoader.GetAttributedTreeControllers().ToArray()); // todo inject + private IEnumerable GetPluginTrees() + { + // used to be (cached) + //var treeTypes = Current.TypeLoader.GetAttributedTreeControllers(); + // + // ie inheriting from TreeController and marked with TreeAttribute + // + // do this instead + // inheriting from TreeControllerBase and marked with TreeAttribute + var trees = Current.Factory.GetInstance(); + + foreach (var tree in trees) + { + var treeType = tree.TreeControllerType; + + // exclude anything marked with CoreTreeAttribute + var coreTree = treeType.GetCustomAttribute(false); + if (coreTree != null) continue; + + // exclude anything not marked with PluginControllerAttribute + var pluginController = treeType.GetCustomAttribute(false); + if (pluginController == null) continue; + + yield return new PluginTree { Alias = tree.TreeAlias, PackageFolder = pluginController.AreaName }; + } + } /// /// Returns the server variables regarding the application state diff --git a/src/Umbraco.Web/Mvc/PluginControllerAttribute.cs b/src/Umbraco.Web/Mvc/PluginControllerAttribute.cs index 6c8b8f19ee..332f1fd2a9 100644 --- a/src/Umbraco.Web/Mvc/PluginControllerAttribute.cs +++ b/src/Umbraco.Web/Mvc/PluginControllerAttribute.cs @@ -4,23 +4,27 @@ using System.Linq; namespace Umbraco.Web.Mvc { /// - /// An attribute applied to a plugin controller that requires that it is routed to its own area + /// Indicates that a controller is a plugin tree controller and should be routed to its own area. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class PluginControllerAttribute : Attribute { - public string AreaName { get; private set; } - + /// + /// Initializes a new instance of the class. + /// + /// public PluginControllerAttribute(string areaName) { - //validate this, only letters and digits allowed. - if (areaName.Any(c => !Char.IsLetterOrDigit(c))) - { - throw new FormatException("The areaName specified " + areaName + " can only contains letters and digits"); - } + // validate this, only letters and digits allowed. + if (areaName.Any(c => !char.IsLetterOrDigit(c))) + throw new FormatException($"Invalid area name \"{areaName}\": the area name can only contains letters and digits."); AreaName = areaName; } + /// + /// Gets the name of the area. + /// + public string AreaName { get; } } } diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 1a0bf8d1b0..2dda1a793c 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -203,14 +203,10 @@ namespace Umbraco.Web.Runtime .Append(); // register back office trees - foreach (var treeControllerType in umbracoApiControllerTypes - .Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))) - { - var attribute = treeControllerType.GetCustomAttribute(false); - if (attribute == null) continue; - var tree = new Tree(attribute.SortOrder, attribute.ApplicationAlias, attribute.TreeAlias, attribute.TreeTitle, treeControllerType, attribute.IsSingleNodeTree); - composition.WithCollectionBuilder().Trees.Add(tree); - } + // the collection builder only accepts types inheriting from TreeControllerBase + // and will filter out those that are not attributed with TreeAttribute + composition.WithCollectionBuilder() + .AddTreeControllers(umbracoApiControllerTypes.Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))); } } } diff --git a/src/Umbraco.Web/Search/SearchableTreeCollection.cs b/src/Umbraco.Web/Search/SearchableTreeCollection.cs index 032782b466..8f7c6ece0b 100644 --- a/src/Umbraco.Web/Search/SearchableTreeCollection.cs +++ b/src/Umbraco.Web/Search/SearchableTreeCollection.cs @@ -32,7 +32,7 @@ namespace Umbraco.Web.Search var found = searchableTrees.FirstOrDefault(x => x.TreeAlias.InvariantEquals(appTree.TreeAlias)); if (found != null) { - dictionary[found.TreeAlias] = new SearchableApplicationTree(appTree.ApplicationAlias, appTree.TreeAlias, found); + dictionary[found.TreeAlias] = new SearchableApplicationTree(appTree.SectionAlias, appTree.TreeAlias, found); } } return dictionary; diff --git a/src/Umbraco.Web/Services/ITreeService.cs b/src/Umbraco.Web/Services/ITreeService.cs index 96787086c6..691e5a6370 100644 --- a/src/Umbraco.Web/Services/ITreeService.cs +++ b/src/Umbraco.Web/Services/ITreeService.cs @@ -1,41 +1,32 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Models; -using Umbraco.Core.Models.ContentEditing; -using Umbraco.Web.Models.ContentEditing; +using System.Collections.Generic; using Umbraco.Web.Trees; namespace Umbraco.Web.Services { + /// + /// Represents a service which manages section trees. + /// public interface ITreeService { /// - /// Gets an ApplicationTree by it's tree alias. + /// Gets a tree. /// /// The tree alias. - /// An ApplicationTree instance Tree GetByAlias(string treeAlias); /// - /// Gets all applicationTrees registered in umbraco from the umbracoAppTree table.. + /// Gets all trees. /// - /// Returns a ApplicationTree Array IEnumerable GetAll(); - + /// - /// Gets the application tree for the applcation with the specified alias + /// Gets all trees for a section. /// - /// The application alias. - /// Returns a ApplicationTree Array - IEnumerable GetTrees(string sectionAlias); - + IEnumerable GetBySection(string sectionAlias); + /// - /// Gets the grouped application trees for the application with the specified alias + /// Gets all trees for a section, grouped. /// - /// - /// - IDictionary> GetGroupedTrees(string sectionAlias); + IDictionary> GetBySectionGrouped(string sectionAlias); } - } diff --git a/src/Umbraco.Web/Services/TreeService.cs b/src/Umbraco.Web/Services/TreeService.cs index f58dce59bc..c697a89a62 100644 --- a/src/Umbraco.Web/Services/TreeService.cs +++ b/src/Umbraco.Web/Services/TreeService.cs @@ -6,65 +6,38 @@ using Umbraco.Web.Trees; namespace Umbraco.Web.Services { + /// + /// Implements . + /// internal class TreeService : ITreeService { private readonly TreeCollection _treeCollection; - private readonly Lazy>> _groupedTrees; + /// + /// Initializes a new instance of the class. + /// + /// public TreeService(TreeCollection treeCollection) { _treeCollection = treeCollection; - _groupedTrees = new Lazy>>(InitGroupedTrees); } /// - public Tree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(t => t.TreeAlias == treeAlias); + public Tree GetByAlias(string treeAlias) => _treeCollection.FirstOrDefault(x => x.TreeAlias == treeAlias); /// public IEnumerable GetAll() => _treeCollection; /// - public IEnumerable GetTrees(string sectionAlias) - => GetAll().Where(x => x.ApplicationAlias.InvariantEquals(sectionAlias)).OrderBy(x => x.SortOrder).ToList(); + public IEnumerable GetBySection(string sectionAlias) + => _treeCollection.Where(x => x.SectionAlias.InvariantEquals(sectionAlias)).OrderBy(x => x.SortOrder).ToList(); - public IDictionary> GetGroupedTrees(string sectionAlias) + /// + public IDictionary> GetBySectionGrouped(string sectionAlias) { - var result = new Dictionary>(); - var foundTrees = GetTrees(sectionAlias).ToList(); - foreach(var treeGroup in _groupedTrees.Value) - { - List resultGroup = null; - foreach(var tree in foundTrees) - { - foreach(var treeAliasInGroup in treeGroup) - { - if (tree.TreeAlias != treeAliasInGroup) continue; - - if (resultGroup == null) resultGroup = new List(); - resultGroup.Add(tree); - } - } - if (resultGroup != null) - result[treeGroup.Key ?? string.Empty] = resultGroup; //key cannot be null so make empty string - } - return result; + return GetBySection(sectionAlias).GroupBy(x => x.TreeGroup).ToDictionary( + x => x.Key ?? "", + x => (IEnumerable) x.ToArray()); } - - /// - /// Creates a group of all tree groups and their tree aliases - /// - /// - /// - /// Used to initialize the field - /// - private IReadOnlyCollection> InitGroupedTrees() - { - var result = GetAll() - .Select(x => (treeAlias: x.TreeAlias, treeGroup: x.TreeControllerType.GetCustomAttribute(false)?.TreeGroup)) - .GroupBy(x => x.treeGroup, x => x.treeAlias) - .ToList(); - return result; - } - } } diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs index 2541221537..75ae623580 100644 --- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs +++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs @@ -60,7 +60,7 @@ namespace Umbraco.Web.Trees if (string.IsNullOrEmpty(application)) throw new HttpResponseException(HttpStatusCode.NotFound); //find all tree definitions that have the current application alias - var groupedTrees = _treeService.GetGroupedTrees(application); + var groupedTrees = _treeService.GetBySectionGrouped(application); var allTrees = groupedTrees.Values.SelectMany(x => x).ToList(); if (string.IsNullOrEmpty(tree) == false || allTrees.Count == 1) diff --git a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs index cce40eb047..e3ecef2a0d 100644 --- a/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentBlueprintTreeController.cs @@ -18,9 +18,9 @@ namespace Umbraco.Web.Trees /// This authorizes based on access to the content section even though it exists in the settings /// [UmbracoApplicationAuthorize(Constants.Applications.Content)] - [Tree(Constants.Applications.Settings, Constants.Trees.ContentBlueprints, null, sortOrder: 12)] + [Tree(Constants.Applications.Settings, Constants.Trees.ContentBlueprints, SortOrder = 12, TreeGroup = Constants.Trees.Groups.Settings)] [PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] public class ContentBlueprintTreeController : TreeController { diff --git a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs index 3c6b9c782c..a7544f71d2 100644 --- a/src/Umbraco.Web/Trees/ContentTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/ContentTypeTreeController.cs @@ -15,9 +15,9 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.DocumentTypes)] - [Tree(Constants.Applications.Settings, Constants.Trees.DocumentTypes, null, sortOrder: 0)] + [Tree(Constants.Applications.Settings, Constants.Trees.DocumentTypes, SortOrder = 0, TreeGroup = Constants.Trees.Groups.Settings)] [Mvc.PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] public class ContentTypeTreeController : TreeController, ISearchableTree { protected override TreeNode CreateRootNode(FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/CoreTreeAttribute.cs b/src/Umbraco.Web/Trees/CoreTreeAttribute.cs index 1b485aea6a..2d6ffe6a15 100644 --- a/src/Umbraco.Web/Trees/CoreTreeAttribute.cs +++ b/src/Umbraco.Web/Trees/CoreTreeAttribute.cs @@ -3,19 +3,12 @@ namespace Umbraco.Web.Trees { /// - /// Indicates that a tree is a core tree and shouldn't be treated as a plugin tree + /// Indicates that a tree is a core tree and should not be treated as a plugin tree. /// /// - /// This ensures that umbraco will look in the umbraco folders for views for this tree + /// This ensures that umbraco will look in the umbraco folders for views for this tree. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] internal class CoreTreeAttribute : Attribute - { - public string TreeGroup { get; set; } - - public CoreTreeAttribute() - { - - } - } + { } } diff --git a/src/Umbraco.Web/Trees/DataTypeTreeController.cs b/src/Umbraco.Web/Trees/DataTypeTreeController.cs index 8b38bee865..c3b2fd631e 100644 --- a/src/Umbraco.Web/Trees/DataTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/DataTypeTreeController.cs @@ -17,9 +17,9 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.DataTypes)] - [Tree(Constants.Applications.Settings, Constants.Trees.DataTypes, null, sortOrder:3)] + [Tree(Constants.Applications.Settings, Constants.Trees.DataTypes, SortOrder = 3, TreeGroup = Constants.Trees.Groups.Settings)] [PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] public class DataTypeTreeController : TreeController, ISearchableTree { protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) @@ -121,7 +121,7 @@ namespace Umbraco.Web.Trees }); if (container.HasChildren == false) - { + { //can delete data type menu.Items.Add(Services.TextService, opensDialog: true); } diff --git a/src/Umbraco.Web/Trees/DictionaryTreeController.cs b/src/Umbraco.Web/Trees/DictionaryTreeController.cs index 6c8f576732..6f8d4f547d 100644 --- a/src/Umbraco.Web/Trees/DictionaryTreeController.cs +++ b/src/Umbraco.Web/Trees/DictionaryTreeController.cs @@ -17,8 +17,8 @@ namespace Umbraco.Web.Trees // dictionary items in templates, even when we dont have authorization to manage the dictionary items )] [Mvc.PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] - [Tree(Constants.Applications.Translation, Constants.Trees.Dictionary, null)] + [CoreTree] + [Tree(Constants.Applications.Translation, Constants.Trees.Dictionary, TreeGroup = Constants.Trees.Groups.Settings)] public class DictionaryTreeController : TreeController { protected override TreeNode CreateRootNode(FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/FilesTreeController.cs b/src/Umbraco.Web/Trees/FilesTreeController.cs index 947522747d..7e326870e3 100644 --- a/src/Umbraco.Web/Trees/FilesTreeController.cs +++ b/src/Umbraco.Web/Trees/FilesTreeController.cs @@ -1,14 +1,13 @@ -using Umbraco.Core; -using Umbraco.Core.IO; +using Umbraco.Core.IO; using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { - [CoreTree(TreeGroup = Constants.Trees.Groups.Templating)] - [Tree(Constants.Applications.Settings, "files", "Files", "icon-folder", "icon-folder", sortOrder: 13, initialize: false)] + // this is not a section tree - do not mark with [Tree] + [CoreTree] public class FilesTreeController : FileSystemTreeController { - protected override IFileSystem FileSystem => new PhysicalFileSystem("~/"); // fixme inject + protected override IFileSystem FileSystem => new PhysicalFileSystem("~/"); private static readonly string[] ExtensionsStatic = { "*" }; diff --git a/src/Umbraco.Web/Trees/ITree.cs b/src/Umbraco.Web/Trees/ITree.cs index 867beda20e..3427e4c40e 100644 --- a/src/Umbraco.Web/Trees/ITree.cs +++ b/src/Umbraco.Web/Trees/ITree.cs @@ -1,7 +1,7 @@ namespace Umbraco.Web.Trees { //fixme - we don't really use this, it is nice to have the treecontroller, attribute and ApplicationTree streamlined to implement this but it's not used - //leave as internal for now, maybe we'll use in the future, means we could pass around ITree + //leave as internal for now, maybe we'll use in the future, means we could pass around ITree internal interface ITree { /// @@ -13,7 +13,12 @@ /// /// Gets the section alias. /// - string ApplicationAlias { get; } + string SectionAlias { get; } + + /// + /// Gets the tree group. + /// + string TreeGroup { get; } /// /// Gets the tree alias. diff --git a/src/Umbraco.Web/Trees/LanguageTreeController.cs b/src/Umbraco.Web/Trees/LanguageTreeController.cs index 5b0ed8701f..ac2c0571e0 100644 --- a/src/Umbraco.Web/Trees/LanguageTreeController.cs +++ b/src/Umbraco.Web/Trees/LanguageTreeController.cs @@ -7,9 +7,9 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Languages)] - [Tree(Constants.Applications.Settings, Constants.Trees.Languages, null, sortOrder: 11)] + [Tree(Constants.Applications.Settings, Constants.Trees.Languages, SortOrder = 11, TreeGroup = Constants.Trees.Groups.Settings)] [PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] public class LanguageTreeController : TreeController { protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/MacrosTreeController.cs b/src/Umbraco.Web/Trees/MacrosTreeController.cs index 0300dbd6c6..77b13416ff 100644 --- a/src/Umbraco.Web/Trees/MacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/MacrosTreeController.cs @@ -12,9 +12,9 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Macros)] - [Tree(Constants.Applications.Settings, Constants.Trees.Macros, "Macros", sortOrder: 4)] + [Tree(Constants.Applications.Settings, Constants.Trees.Macros, TreeTitle = "Macros", SortOrder = 4, TreeGroup = Constants.Trees.Groups.Settings)] [PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] public class MacrosTreeController : TreeController { protected override TreeNode CreateRootNode(FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/MediaTypeTreeController.cs b/src/Umbraco.Web/Trees/MediaTypeTreeController.cs index b93c1ac9e3..4a5ace0aeb 100644 --- a/src/Umbraco.Web/Trees/MediaTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/MediaTypeTreeController.cs @@ -16,9 +16,9 @@ using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.MediaTypes)] - [Tree(Constants.Applications.Settings, Constants.Trees.MediaTypes, null, sortOrder:1)] + [Tree(Constants.Applications.Settings, Constants.Trees.MediaTypes, SortOrder = 1, TreeGroup = Constants.Trees.Groups.Settings)] [Mvc.PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] public class MediaTypeTreeController : TreeController, ISearchableTree { protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/MemberGroupTreeController.cs b/src/Umbraco.Web/Trees/MemberGroupTreeController.cs index 9c8c8ea4e0..ea2412e4bd 100644 --- a/src/Umbraco.Web/Trees/MemberGroupTreeController.cs +++ b/src/Umbraco.Web/Trees/MemberGroupTreeController.cs @@ -8,7 +8,7 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.MemberGroups)] - [Tree(Constants.Applications.Members, Constants.Trees.MemberGroups, null, sortOrder: 1)] + [Tree(Constants.Applications.Members, Constants.Trees.MemberGroups, SortOrder = 1)] [Mvc.PluginController("UmbracoTrees")] [CoreTree] public class MemberGroupTreeController : MemberTypeAndGroupTreeControllerBase diff --git a/src/Umbraco.Web/Trees/MemberTreeController.cs b/src/Umbraco.Web/Trees/MemberTreeController.cs index d1219da466..03c68dd67a 100644 --- a/src/Umbraco.Web/Trees/MemberTreeController.cs +++ b/src/Umbraco.Web/Trees/MemberTreeController.cs @@ -26,7 +26,7 @@ namespace Umbraco.Web.Trees Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members)] - [Tree(Constants.Applications.Members, Constants.Trees.Members, null, sortOrder: 0)] + [Tree(Constants.Applications.Members, Constants.Trees.Members, SortOrder = 0)] [PluginController("UmbracoTrees")] [CoreTree] [SearchableTree("searchResultFormatter", "configureMemberResult")] diff --git a/src/Umbraco.Web/Trees/MemberTypeTreeController.cs b/src/Umbraco.Web/Trees/MemberTypeTreeController.cs index 7bf04010f2..3a72460963 100644 --- a/src/Umbraco.Web/Trees/MemberTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/MemberTypeTreeController.cs @@ -7,9 +7,9 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Trees { - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] [UmbracoTreeAuthorize(Constants.Trees.MemberTypes)] - [Tree(Constants.Applications.Settings, Constants.Trees.MemberTypes, null, sortOrder: 2)] + [Tree(Constants.Applications.Settings, Constants.Trees.MemberTypes, SortOrder = 2, TreeGroup = Constants.Trees.Groups.Settings)] public class MemberTypeTreeController : MemberTypeAndGroupTreeControllerBase { protected override TreeNode CreateRootNode(FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/PackagesTreeController.cs b/src/Umbraco.Web/Trees/PackagesTreeController.cs index 68b67f9fe2..9b1bf98823 100644 --- a/src/Umbraco.Web/Trees/PackagesTreeController.cs +++ b/src/Umbraco.Web/Trees/PackagesTreeController.cs @@ -8,7 +8,7 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Packages)] - [Tree(Constants.Applications.Packages, Constants.Trees.Packages, null, sortOrder: 0, isSingleNodeTree: true)] + [Tree(Constants.Applications.Packages, Constants.Trees.Packages, SortOrder = 0, IsSingleNodeTree = true)] [PluginController("UmbracoTrees")] [CoreTree] public class PackagesTreeController : TreeController diff --git a/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs b/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs index c874b01244..dc107ad303 100644 --- a/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs @@ -10,10 +10,10 @@ namespace Umbraco.Web.Trees /// /// Tree for displaying partial view macros in the developer app /// - [Tree(Constants.Applications.Settings, Constants.Trees.PartialViewMacros, null, sortOrder: 8)] + [Tree(Constants.Applications.Settings, Constants.Trees.PartialViewMacros, SortOrder = 8, TreeGroup = Constants.Trees.Groups.Templating)] [UmbracoTreeAuthorize(Constants.Trees.PartialViewMacros)] [PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Templating)] + [CoreTree] public class PartialViewMacrosTreeController : PartialViewsTreeController { protected override IFileSystem FileSystem => Current.FileSystems.MacroPartialsFileSystem; diff --git a/src/Umbraco.Web/Trees/PartialViewsTreeController.cs b/src/Umbraco.Web/Trees/PartialViewsTreeController.cs index a7aa8f134e..60805d4dac 100644 --- a/src/Umbraco.Web/Trees/PartialViewsTreeController.cs +++ b/src/Umbraco.Web/Trees/PartialViewsTreeController.cs @@ -10,10 +10,10 @@ namespace Umbraco.Web.Trees /// /// Tree for displaying partial views in the settings app /// - [Tree(Constants.Applications.Settings, Constants.Trees.PartialViews, null, sortOrder: 7)] + [Tree(Constants.Applications.Settings, Constants.Trees.PartialViews, SortOrder = 7, TreeGroup = Constants.Trees.Groups.Templating)] [UmbracoTreeAuthorize(Constants.Trees.PartialViews)] [PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Templating)] + [CoreTree] public class PartialViewsTreeController : FileSystemTreeController { protected override IFileSystem FileSystem => Current.FileSystems.PartialViewsFileSystem; diff --git a/src/Umbraco.Web/Trees/RelationTypeTreeController.cs b/src/Umbraco.Web/Trees/RelationTypeTreeController.cs index 1888044d8d..82e07c5226 100644 --- a/src/Umbraco.Web/Trees/RelationTypeTreeController.cs +++ b/src/Umbraco.Web/Trees/RelationTypeTreeController.cs @@ -9,9 +9,9 @@ using Umbraco.Web.Actions; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.RelationTypes)] - [Tree(Constants.Applications.Settings, Constants.Trees.RelationTypes, null, sortOrder: 5)] + [Tree(Constants.Applications.Settings, Constants.Trees.RelationTypes, SortOrder = 5, TreeGroup = Constants.Trees.Groups.Settings)] [Mvc.PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Settings)] + [CoreTree] public class RelationTypeTreeController : TreeController { protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/ScriptsTreeController.cs b/src/Umbraco.Web/Trees/ScriptsTreeController.cs index cd56cc4790..bb002c7dda 100644 --- a/src/Umbraco.Web/Trees/ScriptsTreeController.cs +++ b/src/Umbraco.Web/Trees/ScriptsTreeController.cs @@ -5,8 +5,8 @@ using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { - [CoreTree(TreeGroup = Constants.Trees.Groups.Templating)] - [Tree(Constants.Applications.Settings, Constants.Trees.Scripts, "Scripts", "icon-folder", "icon-folder", sortOrder: 10)] + [CoreTree] + [Tree(Constants.Applications.Settings, Constants.Trees.Scripts, TreeTitle = "Scripts", IconOpen = "icon-folder", IconClosed = "icon-folder", SortOrder = 10, TreeGroup = Constants.Trees.Groups.Templating)] public class ScriptsTreeController : FileSystemTreeController { protected override IFileSystem FileSystem => Current.FileSystems.ScriptsFileSystem; // fixme inject diff --git a/src/Umbraco.Web/Trees/StylesheetsTreeController.cs b/src/Umbraco.Web/Trees/StylesheetsTreeController.cs index 548e8ae928..b47c225b2f 100644 --- a/src/Umbraco.Web/Trees/StylesheetsTreeController.cs +++ b/src/Umbraco.Web/Trees/StylesheetsTreeController.cs @@ -4,8 +4,8 @@ using Umbraco.Web.Composing; namespace Umbraco.Web.Trees { - [CoreTree(TreeGroup = Constants.Trees.Groups.Templating)] - [Tree(Constants.Applications.Settings, Constants.Trees.Stylesheets, "Stylesheets", "icon-folder", "icon-folder", sortOrder: 9)] + [CoreTree] + [Tree(Constants.Applications.Settings, Constants.Trees.Stylesheets, TreeTitle = "Stylesheets", IconOpen = "icon-folder", IconClosed = "icon-folder", SortOrder = 9, TreeGroup = Constants.Trees.Groups.Templating)] public class StylesheetsTreeController : FileSystemTreeController { protected override IFileSystem FileSystem => Current.FileSystems.StylesheetsFileSystem; // fixme inject diff --git a/src/Umbraco.Web/Trees/TemplatesTreeController.cs b/src/Umbraco.Web/Trees/TemplatesTreeController.cs index c074f828d4..5db8c4b7cb 100644 --- a/src/Umbraco.Web/Trees/TemplatesTreeController.cs +++ b/src/Umbraco.Web/Trees/TemplatesTreeController.cs @@ -16,9 +16,9 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Templates)] - [Tree(Constants.Applications.Settings, Constants.Trees.Templates, null, sortOrder:6)] + [Tree(Constants.Applications.Settings, Constants.Trees.Templates, SortOrder = 6, TreeGroup = Constants.Trees.Groups.Templating)] [PluginController("UmbracoTrees")] - [CoreTree(TreeGroup = Constants.Trees.Groups.Templating)] + [CoreTree] public class TemplatesTreeController : TreeController, ISearchableTree { protected override TreeNode CreateRootNode(FormDataCollection queryStrings) diff --git a/src/Umbraco.Web/Trees/Tree.cs b/src/Umbraco.Web/Trees/Tree.cs index 39f5cec1eb..b0a24e3b2b 100644 --- a/src/Umbraco.Web/Trees/Tree.cs +++ b/src/Umbraco.Web/Trees/Tree.cs @@ -1,46 +1,44 @@ using System; using System.Diagnostics; using Umbraco.Core.Services; -using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { - [DebuggerDisplay("Tree - {TreeAlias} ({ApplicationAlias})")] + [DebuggerDisplay("Tree - {TreeAlias} ({SectionAlias})")] public class Tree : ITree { - public Tree(int sortOrder, string applicationAlias, string alias, string title, Type treeControllerType, bool isSingleNodeTree) + public Tree(int sortOrder, string applicationAlias, string group, string alias, string title, Type treeControllerType, bool isSingleNodeTree) { SortOrder = sortOrder; - ApplicationAlias = applicationAlias; + SectionAlias = applicationAlias; + TreeGroup = group; TreeAlias = alias; TreeTitle = title; TreeControllerType = treeControllerType; IsSingleNodeTree = isSingleNodeTree; } - + /// - /// - /// Gets or sets the sort order. - /// public int SortOrder { get; set; } - /// - /// Gets the application alias. - /// - public string ApplicationAlias { get; set; } + /// + public string SectionAlias { get; set; } + + /// + public string TreeGroup { get; } /// public string TreeAlias { get; } /// - /// - /// Gets or sets the tree title (fallback if the tree alias isn't localized) - /// - /// The title. public string TreeTitle { get; set; } + /// public bool IsSingleNodeTree { get; } + /// + /// Gets the tree controller type. + /// public Type TreeControllerType { get; } internal static string GetRootNodeDisplayName(ITree tree, ILocalizedTextService textService) @@ -64,6 +62,5 @@ namespace Umbraco.Web.Trees return label; } - } } diff --git a/src/Umbraco.Web/Trees/TreeAttribute.cs b/src/Umbraco.Web/Trees/TreeAttribute.cs index dd63f8c172..bfd7b53f4a 100644 --- a/src/Umbraco.Web/Trees/TreeAttribute.cs +++ b/src/Umbraco.Web/Trees/TreeAttribute.cs @@ -1,10 +1,9 @@ using System; -using Umbraco.Web.Models.Trees; namespace Umbraco.Web.Trees { /// - /// Identifies an application tree + /// Identifies a section tree. /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class TreeAttribute : Attribute, ITree @@ -12,54 +11,50 @@ namespace Umbraco.Web.Trees /// /// Initializes a new instance of the class. /// - /// The app alias. - /// - public TreeAttribute(string appAlias, - string treeAlias) : this(appAlias, treeAlias, null) + public TreeAttribute(string sectionAlias, string treeAlias) { - } - - /// - /// Initializes a new instance of the class. - /// - /// The app alias. - /// - /// - /// The icon closed. - /// The icon open. - /// if set to true [initialize]. - /// The sort order. - /// Flag to define if this tree is a single node tree (will never contain child nodes, full screen app) - public TreeAttribute(string appAlias, - string treeAlias, - string treeTitle, - string iconClosed = "icon-folder", - string iconOpen = "icon-folder-open", - bool initialize = true, - int sortOrder = 0, - bool isSingleNodeTree = false) - { - ApplicationAlias = appAlias; + SectionAlias = sectionAlias; TreeAlias = treeAlias; - TreeTitle = treeTitle; - IconClosed = iconClosed; - IconOpen = iconOpen; - Initialize = initialize; - SortOrder = sortOrder; - IsSingleNodeTree = isSingleNodeTree; } - public string ApplicationAlias { get; } - public string TreeAlias { get; } - public string TreeTitle { get; } - public string IconClosed { get; } - public string IconOpen { get; } - public bool Initialize { get; } - public int SortOrder { get; } + /// + /// Gets the section alias. + /// + public string SectionAlias { get; } /// - /// Flag to define if this tree is a single node tree (will never contain child nodes, full screen app) + /// Gets the tree alias. /// - public bool IsSingleNodeTree { get; } + public string TreeAlias { get; } + + /// + /// Gets or sets the tree title. + /// + public string TreeTitle { get; set; } + + /// + /// Gets or sets the group of the tree. + /// + public string TreeGroup { get; set; } + + /// + /// Gets or sets the tree icon when closed. + /// + public string IconClosed { get; set; } = "icon-folder"; + + /// + /// Gets or sets the tree icon when open. + /// + public string IconOpen { get; set; } = "icon-folder-open"; + + /// + /// Gets or sets the tree sort order. + /// + public int SortOrder { get; set; } + + /// + /// Gets or sets a value indicating whether the tree is a single-node tree (no child nodes, full screen app). + /// + public bool IsSingleNodeTree { get; set; } } } diff --git a/src/Umbraco.Web/Trees/TreeCollection.cs b/src/Umbraco.Web/Trees/TreeCollection.cs index a7bfe52295..76404d4ac5 100644 --- a/src/Umbraco.Web/Trees/TreeCollection.cs +++ b/src/Umbraco.Web/Trees/TreeCollection.cs @@ -1,15 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; using Umbraco.Core.Composing; -using Umbraco.Core.Models; -using Umbraco.Core.Models.ContentEditing; -using Umbraco.Web.Models.ContentEditing; namespace Umbraco.Web.Trees { + /// + /// Represents the collection of section trees. + /// public class TreeCollection : BuilderCollectionBase { public TreeCollection(IEnumerable items) diff --git a/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs index ae2675bac9..ad2a99a6c7 100644 --- a/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs +++ b/src/Umbraco.Web/Trees/TreeCollectionBuilder.cs @@ -1,17 +1,55 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using Umbraco.Core; using Umbraco.Core.Composing; namespace Umbraco.Web.Trees { + // todo + // this is a weird collection builder because it actually contains trees, not types + // and it does not really rely on DI to instantiate anything - but meh + // can we have trees that don't have a controller, or something? looks like, no + // and then, we should not register trees here, and only create them when creating + // the collection! + + /// + /// Builds a . + /// public class TreeCollectionBuilder : ICollectionBuilder { - /// - /// expose the list of trees which developers can manipulate before the collection is created - /// - public List Trees { get; } = new List(); + private readonly List _trees = new List(); - public TreeCollection CreateCollection(IFactory factory) => new TreeCollection(Trees); + public TreeCollection CreateCollection(IFactory factory) => new TreeCollection(_trees); public void RegisterWith(IRegister register) => register.Register(CreateCollection, Lifetime.Singleton); + + public void AddTreeController() + where TController : TreeControllerBase + => AddTreeController(typeof(TController)); + + public void AddTreeController(Type controllerType) + { + if (!typeof(TreeControllerBase).IsAssignableFrom(controllerType)) + throw new ArgumentException($"Type {controllerType} does not inherit from {typeof(TreeControllerBase).FullName}."); + + var attribute = controllerType.GetCustomAttribute(false); + if (attribute == null) return; // todo - shouldn't we throw or at least log? + var tree = new Tree(attribute.SortOrder, attribute.SectionAlias, attribute.TreeGroup, attribute.TreeAlias, attribute.TreeTitle, controllerType, attribute.IsSingleNodeTree); + _trees.Add(tree); + } + + public void AddTreeControllers(IEnumerable controllerTypes) + { + foreach (var controllerType in controllerTypes) + AddTreeController(controllerType); + } + + // todo - do we want to support this? + public void AddTree(Tree tree) + => _trees.Add(tree); + + // todo - do we want to support this? + public void AddTrees(IEnumerable tree) + => _trees.AddRange(tree); } } diff --git a/src/Umbraco.Web/Trees/TreeController.cs b/src/Umbraco.Web/Trees/TreeController.cs index 733c526331..bc9345eb1d 100644 --- a/src/Umbraco.Web/Trees/TreeController.cs +++ b/src/Umbraco.Web/Trees/TreeController.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Concurrent; -using System.Linq; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; @@ -15,53 +14,50 @@ namespace Umbraco.Web.Trees /// public abstract class TreeController : TreeControllerBase { - private TreeAttribute _attribute; + private static readonly ConcurrentDictionary TreeAttributeCache = new ConcurrentDictionary(); - protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + private readonly TreeAttribute _treeAttribute; + + protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) { - Initialize(); + _treeAttribute = GetTreeAttribute(); } protected TreeController() { - Initialize(); + _treeAttribute = GetTreeAttribute(); } /// public override string RootNodeDisplayName => Tree.GetRootNodeDisplayName(this, Services.TextService); /// - public override string TreeAlias => _attribute.TreeAlias; - /// - public override string TreeTitle => _attribute.TreeTitle; - /// - public override string ApplicationAlias => _attribute.ApplicationAlias; - /// - public override int SortOrder => _attribute.SortOrder; - /// - public override bool IsSingleNodeTree => _attribute.IsSingleNodeTree; + public override string TreeGroup => _treeAttribute.TreeGroup; - private void Initialize() - { - _attribute = GetTreeAttribute(); - } + /// + public override string TreeAlias => _treeAttribute.TreeAlias; - private static readonly ConcurrentDictionary TreeAttributeCache = new ConcurrentDictionary(); + /// + public override string TreeTitle => _treeAttribute.TreeTitle; + + /// + public override string SectionAlias => _treeAttribute.SectionAlias; + + /// + public override int SortOrder => _treeAttribute.SortOrder; + + /// + public override bool IsSingleNodeTree => _treeAttribute.IsSingleNodeTree; private TreeAttribute GetTreeAttribute() { return TreeAttributeCache.GetOrAdd(GetType(), type => { - //Locate the tree attribute - var treeAttributes = type - .GetCustomAttributes(false) - .ToArray(); - - if (treeAttributes.Length == 0) + var treeAttribute = type.GetCustomAttribute(false); + if (treeAttribute == null) throw new InvalidOperationException("The Tree controller is missing the " + typeof(TreeAttribute).FullName + " attribute"); - - //assign the properties of this object to those of the metadata attribute - return treeAttributes[0]; + return treeAttribute; }); } } diff --git a/src/Umbraco.Web/Trees/TreeControllerBase.cs b/src/Umbraco.Web/Trees/TreeControllerBase.cs index d06d768f2d..e2e9c21c66 100644 --- a/src/Umbraco.Web/Trees/TreeControllerBase.cs +++ b/src/Umbraco.Web/Trees/TreeControllerBase.cs @@ -2,7 +2,6 @@ using System.Globalization; using System.Linq; using System.Net.Http.Formatting; -using System.Web.Http.Routing; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; @@ -19,7 +18,7 @@ using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Trees { /// - /// A base controller reference for non-attributed trees (un-registered). + /// A base controller reference for non-attributed trees (un-registered). /// /// /// Developers should generally inherit from TreeController. @@ -28,13 +27,11 @@ namespace Umbraco.Web.Trees public abstract class TreeControllerBase : UmbracoAuthorizedApiController, ITree { protected TreeControllerBase() - { - } - - protected TreeControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) - { - } + { } + protected TreeControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) + : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) + { } /// /// The method called to render the contents of the tree structure @@ -62,14 +59,21 @@ namespace Umbraco.Web.Trees /// public abstract string RootNodeDisplayName { get; } + /// + public abstract string TreeGroup { get; } + /// public abstract string TreeAlias { get; } + /// public abstract string TreeTitle { get; } + /// - public abstract string ApplicationAlias { get; } + public abstract string SectionAlias { get; } + /// public abstract int SortOrder { get; } + /// public abstract bool IsSingleNodeTree { get; } @@ -402,5 +406,4 @@ namespace Umbraco.Web.Trees handler?.Invoke(instance, e); } } - } diff --git a/src/Umbraco.Web/Trees/UserTreeController.cs b/src/Umbraco.Web/Trees/UserTreeController.cs index 95f041cac5..91078b2be8 100644 --- a/src/Umbraco.Web/Trees/UserTreeController.cs +++ b/src/Umbraco.Web/Trees/UserTreeController.cs @@ -7,7 +7,7 @@ using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Trees { [UmbracoTreeAuthorize(Constants.Trees.Users)] - [Tree(Constants.Applications.Users, Constants.Trees.Users, null, sortOrder: 0, isSingleNodeTree: true)] + [Tree(Constants.Applications.Users, Constants.Trees.Users, SortOrder = 0, IsSingleNodeTree = true)] [PluginController("UmbracoTrees")] [CoreTree] public class UserTreeController : TreeController diff --git a/src/Umbraco.Web/TypeLoaderExtensions.cs b/src/Umbraco.Web/TypeLoaderExtensions.cs index 4d09783ca9..1cf8bc124c 100644 --- a/src/Umbraco.Web/TypeLoaderExtensions.cs +++ b/src/Umbraco.Web/TypeLoaderExtensions.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using Umbraco.Core.Media; using Umbraco.Web.Mvc; -using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Umbraco.Core.Composing; @@ -10,29 +8,20 @@ using Umbraco.Core.Composing; namespace Umbraco.Web { /// - /// Extension methods for the PluginTypemgr + /// Provides extension methods for the class. /// public static class TypeLoaderExtensions { /// - /// Returns all available TreeApiController's in application that are attribute with TreeAttribute + /// Gets all types implementing . /// - /// - /// - internal static IEnumerable GetAttributedTreeControllers(this TypeLoader mgr) - { - return mgr.GetTypesWithAttribute(); - } + internal static IEnumerable GetSurfaceControllers(this TypeLoader typeLoader) + => typeLoader.GetTypes(); - internal static IEnumerable GetSurfaceControllers(this TypeLoader mgr) - { - return mgr.GetTypes(); - } - - internal static IEnumerable GetUmbracoApiControllers(this TypeLoader mgr) - { - return mgr.GetTypes(); - } - + /// + /// Gets all types implementing . + /// + internal static IEnumerable GetUmbracoApiControllers(this TypeLoader typeLoader) + => typeLoader.GetTypes(); } } diff --git a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs index cafdfb0e04..f1b2cda368 100644 --- a/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs +++ b/src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.UI.Pages .GetByAlias(treeAuth.TreeAlias); if (treeByAlias != null) { - CurrentApp = treeByAlias.ApplicationAlias; + CurrentApp = treeByAlias.SectionAlias; } } } diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs index 5ad3da7f4d..1bea963ee1 100644 --- a/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/Filters/UmbracoTreeAuthorizeAttribute.cs @@ -44,7 +44,7 @@ namespace Umbraco.Web.WebApi.Filters var apps = _treeAliases.Select(x => Current.TreeService .GetByAlias(x)) .WhereNotNull() - .Select(x => x.ApplicationAlias) + .Select(x => x.SectionAlias) .Distinct() .ToArray(); From e651d5917a69ec874c9242026203d169eca6c9f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Tue, 22 Jan 2019 14:38:10 +0100 Subject: [PATCH 008/213] Finds and set the active ContentApp when running init, fixing the issue of retuning to a node after editing the DocType in infinity editing. Fixes #4185 --- .../components/content/edit.controller.js | 63 +++++--- .../src/views/media/edit.html | 2 +- .../src/views/media/media.edit.controller.js | 139 ++++++++++++------ .../src/views/mediatypes/edit.controller.js | 5 +- 4 files changed, 143 insertions(+), 66 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 89c8b541d1..ecaf8b3ad3 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 @@ -26,20 +26,43 @@ $scope.allowOpen = true; $scope.app = null; - function init(content) { - if (!$scope.app) { - // set first app to active + function init() { + + var content = $scope.content; + + // we need to check wether an app is present in the current data, if not we will present the default app. + var isAppPresent = false; + + // on first init, we dont have any apps. but if we are re-initializing, we do, but ... + if ($scope.app) { + + // lets check if it still exists as part of our apps array. (if not we have made a change to our docType, even just a re-save of the docType it will turn into new Apps.) + _.forEach(content.apps, function(app) { + if (app === $scope.app) { + isAppPresent = true; + } + }); + + // if we did reload our DocType, but still have the same app we will try to find it by the alias. + if (isAppPresent === false) { + _.forEach(content.apps, function(app) { + if (app.alias === $scope.app.alias) { + isAppPresent = true; + app.active = true; + $scope.appChanged(app); + } + }); + } + + } + + // if we still dont have a app, lets show the first one: + if (isAppPresent === false) { content.apps[0].active = true; - $scope.app = content.apps[0]; + $scope.appChanged(content.apps[0]); } - - if (infiniteMode) { - createInfiniteModeButtons(content); - } else { - createButtons(content); - } - - editorState.set($scope.content); + + editorState.set(content); //We fetch all ancestors of the node to generate the footer breadcrumb navigation if (!$scope.page.isNew) { @@ -129,7 +152,7 @@ "/content/content/edit/" + data.parentId; } - init($scope.content); + init(); syncTreeNode($scope.content, $scope.content.path, true); @@ -337,7 +360,7 @@ showNotifications: args.showNotifications }).then(function (data) { //success - init($scope.content); + init(); syncTreeNode($scope.content, data.path); eventsService.emit("content.saved", { content: $scope.content, action: args.action }); @@ -439,7 +462,7 @@ $scope.content = data; - init($scope.content); + init(); resetLastListPageNumber($scope.content); @@ -478,7 +501,7 @@ .then(function (data) { formHelper.resetForm({ scope: $scope }); contentEditingHelper.reBindChangedProperties($scope.content, data); - init($scope.content); + init(); syncTreeNode($scope.content, data.path); $scope.page.buttonGroupState = "success"; eventsService.emit("content.unpublished", { content: $scope.content }); @@ -915,8 +938,14 @@ * @param {any} app */ $scope.appChanged = function (app) { + $scope.app = app; - createButtons($scope.content); + + if (infiniteMode) { + createInfiniteModeButtons($scope.content); + } else { + createButtons($scope.content); + } }; // methods for infinite editing diff --git a/src/Umbraco.Web.UI.Client/src/views/media/edit.html b/src/Umbraco.Web.UI.Client/src/views/media/edit.html index be1219f052..35f9a6f7ff 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/media/edit.html @@ -14,7 +14,7 @@ hide-description="true" hide-alias="true" navigation="content.apps" - on-select-navigation-item="appChanged(app)"> + on-select-navigation-item="appChanged(item)"> diff --git a/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js index 19932887fd..af7184c82f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/media/media.edit.controller.js @@ -6,7 +6,10 @@ * @description * The controller for the media editor */ -function mediaEditController($scope, $routeParams, $q, appState, mediaResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, editorState, umbRequestHelper, $http, eventsService) { +function mediaEditController($scope, $routeParams, $q, appState, mediaResource, + entityResource, navigationService, notificationsService, angularHelper, + serverValidationManager, contentEditingHelper, fileManager, formHelper, + editorState, umbRequestHelper, $http, eventsService) { var evts = []; var nodeId = null; @@ -41,7 +44,90 @@ function mediaEditController($scope, $routeParams, $q, appState, mediaResource, $scope.page.listViewPath = null; $scope.page.saveButtonState = "init"; $scope.page.submitButtonLabel = "Save"; + $scope.app = null; + if (create) { + + $scope.page.loading = true; + + mediaResource.getScaffold(nodeId, $routeParams.doctype) + .then(function (data) { + $scope.content = data; + + init(); + + $scope.page.loading = false; + + }); + } + else { + $scope.page.loading = true; + loadMedia() + .then(function(){ + $scope.page.loading = false; + }); + } + + function init() { + + var content = $scope.content; + + // we need to check wether an app is present in the current data, if not we will present the default app. + var isAppPresent = false; + + // on first init, we dont have any apps. but if we are re-initializing, we do, but ... + if ($scope.app) { + + // lets check if it still exists as part of our apps array. (if not we have made a change to our docType, even just a re-save of the docType it will turn into new Apps.) + _.forEach(content.apps, function(app) { + if (app === $scope.app) { + isAppPresent = true; + } + }); + + // if we did reload our DocType, but still have the same app we will try to find it by the alias. + if (isAppPresent === false) { + _.forEach(content.apps, function(app) { + if (app.alias === $scope.app.alias) { + isAppPresent = true; + app.active = true; + $scope.appChanged(app); + } + }); + } + + } + + // if we still dont have a app, lets show the first one: + if (isAppPresent === false) { + content.apps[0].active = true; + $scope.appChanged(content.apps[0]); + } + + + editorState.set($scope.content); + + bindEvents(); + + } + + function bindEvents() { + //bindEvents can be called more than once and we don't want to have multiple bound events + for (var e in evts) { + eventsService.unsubscribe(evts[e]); + } + + evts.push(eventsService.on("editors.mediaType.saved", function(name, args) { + // if this media item uses the updated media type we need to reload the media item + if(args && args.mediaType && args.mediaType.key === $scope.content.contentType.key) { + $scope.page.loading = true; + loadMedia().then(function() { + $scope.page.loading = false; + }); + } + })); + } + /** Syncs the content item to it's tree node - this occurs on first load and after saving */ function syncTreeNode(content, path, initialLoad) { @@ -68,45 +154,6 @@ function mediaEditController($scope, $routeParams, $q, appState, mediaResource, }); } } - - if (create) { - - $scope.page.loading = true; - - mediaResource.getScaffold(nodeId, $routeParams.doctype) - .then(function (data) { - $scope.content = data; - - editorState.set($scope.content); - - init(); - - $scope.page.loading = false; - - }); - } - else { - $scope.page.loading = true; - loadMedia() - .then(function(){ - $scope.page.loading = false; - }); - } - - function init() { - - if (!$scope.app) { - // set first app to active - $scope.content.apps[0].active = true; - $scope.app = $scope.content.apps[0]; - } - - // setup infinite mode - if(infiniteMode) { - $scope.page.submitButtonLabel = "Save and Close"; - } - - } $scope.save = function () { @@ -212,14 +259,12 @@ function mediaEditController($scope, $routeParams, $q, appState, mediaResource, $scope.appChanged = function (app) { $scope.app = app; - } - - evts.push(eventsService.on("editors.mediaType.saved", function(name, args) { - // if this media item uses the updated media type we need to reload the media item - if(args && args.mediaType && args.mediaType.key === $scope.content.contentType.key) { - loadMedia(); + + // setup infinite mode + if(infiniteMode) { + $scope.page.submitButtonLabel = "Save and Close"; } - })); + } //ensure to unregister from all events! $scope.$on('$destroy', function () { diff --git a/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js index c8aba53cf5..0740f7866f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/mediatypes/edit.controller.js @@ -9,7 +9,10 @@ (function () { "use strict"; - function MediaTypesEditController($scope, $routeParams, mediaTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) { + function MediaTypesEditController($scope, $routeParams, mediaTypeResource, + dataTypeResource, editorState, contentEditingHelper, formHelper, + navigationService, iconHelper, contentTypeHelper, notificationsService, + $filter, $q, localizationService, overlayHelper, eventsService) { var vm = this; var evts = []; From d8f0af1a94d14fc9b79882e11be4bddcf79b3fb1 Mon Sep 17 00:00:00 2001 From: Bjarne Fyrstenborg Date: Tue, 22 Jan 2019 20:37:47 +0100 Subject: [PATCH 009/213] Fix plural localization --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index b4ab08422e..3223478dd7 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -1458,9 +1458,9 @@ Mange hilsner fra Umbraco robotten Makroer Medietyper Medlemmer - Medlemsgruppe + Medlemsgrupper Roller - Medlemstype + Medlemstyper Dokumenttyper Relationstyper Pakker From 832ec68140026c8256af00ac5991a36356ba25aa Mon Sep 17 00:00:00 2001 From: Paul Seal Date: Mon, 21 Jan 2019 23:38:38 +0000 Subject: [PATCH 010/213] - tls check to check if the site is set up to use at least TLS 1.2 for outgoing connections. - added translations for all languages which have a healthcheck section in the language file. --- .../Umbraco/config/lang/zh_tw.xml | 5 +- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 3 ++ .../umbraco/config/lang/en_us.xml | 3 ++ src/Umbraco.Web.UI/umbraco/config/lang/es.xml | 3 ++ src/Umbraco.Web.UI/umbraco/config/lang/fr.xml | 3 ++ src/Umbraco.Web.UI/umbraco/config/lang/nl.xml | 3 ++ src/Umbraco.Web.UI/umbraco/config/lang/pl.xml | 3 ++ src/Umbraco.Web.UI/umbraco/config/lang/ru.xml | 3 ++ src/Umbraco.Web.UI/umbraco/config/lang/zh.xml | 3 ++ .../HealthCheck/Checks/Security/TlsCheck.cs | 51 +++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 11 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web/HealthCheck/Checks/Security/TlsCheck.cs diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml index 16387728b1..ba30581267 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/zh_tw.xml @@ -1331,6 +1331,9 @@ SMTP伺服器 %0% : %1% 無法連接。請確認在Web.config 檔案中 system.net/mailsettings 設定正確。 %0%。]]> %0%。]]> + + 您的網站設置為使用TLS 1.2或更高版本進行傳出連接。 + 來自您網站的傳出連接通過舊協議提供。您應該考慮將其更新為使用TLS 1.2或更高版本。 停止網址追蹤器 @@ -1350,4 +1353,4 @@ 轉址追蹤器已開啟。 啟動轉址追蹤器錯誤,更多資訊請參閱您的紀錄檔。 - \ No newline at end of file + diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 7d3bfa7c99..06a7fbb109 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -2206,6 +2206,9 @@ To manage your website, simply open the Umbraco back office and start adding con %0%.]]>

Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

%2%]]>
Umbraco Health Check Status: %0% + + Your website is set up to use TLS 1.2 or greater for outgoing connections. + Outgoing connections from your website are being served over an old protocol. You should consider updating it to use TLS 1.2 or higher. Disable URL tracker diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index 0a1756038f..766d2eec9e 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -2199,6 +2199,9 @@ To manage your website, simply open the Umbraco back office and start adding con %0%.]]>

Results of the scheduled Umbraco Health Checks run on %0% at %1% are as follows:

%2%]]>
Umbraco Health Check Status: %0% + + Your website is set up to use TLS 1.2 or greater for outgoing connections. + Outgoing connections from your website are being served over an old protocol. You should consider updating it to use TLS 1.2 or higher. Disable URL tracker diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml index ba0027aef0..607050c235 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml @@ -1856,6 +1856,9 @@ %0%.]]>

Los resultados de los Chequeos de Salud de Umbraco programados para ejecutarse el %0% a las %1% son:

%2%]]>
Status de los Chequeos de Salud de Umbraco: %0% + + Su sitio web está configurado para usar TLS 1.2 o superior para las conexiones salientes. + Las conexiones salientes de su sitio web están siendo servidas a través de un protocolo antiguo. Deberías considerar actualizarlo para usar TLS 1.2 o superior. Desactivar URL tracker diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml index fd2b4c53a8..dab9f49120 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml @@ -2170,6 +2170,9 @@ Pour gérer votre site, ouvrez simplement le backoffice Umbraco et commencez à %0%.]]>

Les résultats de l'exécution du Umbraco Health Checks planifiée le %0% à %1% sont les suivants :

%2%]]>
Statut du Umbraco Health Check: %0% + + Votre site Web est configuré pour utiliser TLS version 1.2 ou supérieure pour les connexions sortantes. + Les connexions sortantes de votre site Web sont servies via un ancien protocole. Vous devriez envisager de le mettre à jour pour utiliser TLS 1.2 ou supérieur. Désactiver URL tracker diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml index 26b057e49f..4680d0dfc5 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml @@ -1623,6 +1623,9 @@ Om een vertalingstaak te sluiten, ga aub naar het detailoverzicht en klik op de %0%.]]> %0%.]]> + + Uw website is ingesteld om TLS 1.2 of hoger te gebruiken voor uitgaande verbindingen. + Uitgaande verbindingen van uw website worden via een oud protocol bediend. U zou moeten overwegen om het bij te werken om TLS 1.2 of hoger te gebruiken. URL tracker uitzetten diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml index 9affa43727..bb36628757 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml @@ -1674,6 +1674,9 @@ Naciśnij przycisk instaluj, aby zainstalować bazę danych Umb %0%.]]> %0%.]]> + + Twoja strona internetowa jest skonfigurowana do używania protokołu TLS 1.2 lub nowszego dla połączeń wychodzących. + Połączenia wychodzące z Twojej witryny są obsługiwane przez stary protokół. Należy rozważyć zaktualizowanie go do korzystania z TLS w wersji 1.2 lub nowszej. Wyłącz śledzenie URL diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index fd33e647ad..37a4613d43 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -870,6 +870,9 @@ %0%.]]>

Зафиксированы следующие результаты автоматической проверки состояния Umbraco по расписанию, запущенной на %0% в %1%:

%2%]]>
Результат проверки состояния Umbraco: %0% + + Ваш веб-сайт настроен на использование TLS 1.2 или выше для исходящих соединений. + Исходящие соединения с вашего сайта обслуживаются по старому протоколу. Вы должны рассмотреть возможность его обновления для использования TLS 1.2 или выше. перейти к diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml index a918b78f95..471925ccd5 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml @@ -1598,6 +1598,9 @@ The SMTP server configured with host '%0%' and port '%1%' could not be reached. Please check to ensure the SMTP settings in the Web.config file system.net/mailsettings are correct. %0%.]]> %0%.]]> + + 您的网站设置为使用TLS 1.2或更高版本进行传出连接。 + 来自您网站的传出连接通过旧协议提供。您应该考虑将其更新为使用TLS 1.2或更高版本。 禁用 url 跟踪程序 diff --git a/src/Umbraco.Web/HealthCheck/Checks/Security/TlsCheck.cs b/src/Umbraco.Web/HealthCheck/Checks/Security/TlsCheck.cs new file mode 100644 index 0000000000..8d41965395 --- /dev/null +++ b/src/Umbraco.Web/HealthCheck/Checks/Security/TlsCheck.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Net; +using Umbraco.Core.Services; + +namespace Umbraco.Web.HealthCheck.Checks.Security +{ + [HealthCheck("6D7D4E11-758E-4697-BA72-7E02A530CBD4", + "TLS Check", + Description = "Checks that your site is set up to use at least TLS 1.2 for outgoing connections.", + Group = "Security")] + public class TlsCheck : HealthCheck + { + private readonly ILocalizedTextService _textService; + + public TlsCheck(HealthCheckContext healthCheckContext) : base(healthCheckContext) + { + _textService = healthCheckContext.ApplicationContext.Services.TextService; + } + + public override IEnumerable GetStatus() + { + return new[] { CheckTls() }; + } + + public override HealthCheckStatus ExecuteAction(HealthCheckAction action) + { + throw new InvalidOperationException("TlsCheck has no executable actions"); + } + + public HealthCheckStatus CheckTls() + { + bool success = (int)ServicePointManager.SecurityProtocol >= (int)SecurityProtocolType.Tls12; + + string message = success + ? _textService.Localize("healthcheck/tlsHealthCheckSuccess") + : _textService.Localize("healthcheck/tlsHealthCheckWarn"); + + var actions = new List(); + + return + new HealthCheckStatus(message) + { + ResultType = success + ? StatusResultType.Success + : StatusResultType.Warning, + Actions = actions + }; + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 1b668b06c8..a66e960e97 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -338,6 +338,7 @@ + From 9eb2b28232772532cc74686cd4d01efdf13905f6 Mon Sep 17 00:00:00 2001 From: Alkaersig Date: Thu, 17 Jan 2019 12:08:53 +0100 Subject: [PATCH 011/213] Added (Doctype) Name and Description to PublishedContentType --- .../Models/PublishedContent/PublishedContentType.cs | 10 ++++++++-- src/Umbraco.Tests/CodeFirst/StronglyTypedMapperTest.cs | 4 ++-- src/Umbraco.Tests/LibraryTests.cs | 2 +- .../Membership/DynamicMemberContentTests.cs | 2 +- .../PublishedContent/DynamicDocumentTestsBase.cs | 4 ++-- .../PublishedContent/PublishedContentDataTableTests.cs | 4 ++-- .../PublishedContent/PublishedContentMoreTests.cs | 6 +++--- .../PublishedContent/PublishedContentTestBase.cs | 4 ++-- .../PublishedContent/PublishedContentTestElements.cs | 8 ++++---- .../PublishedContent/PublishedContentTests.cs | 2 +- src/Umbraco.Tests/TestHelpers/BaseWebTest.cs | 2 +- src/Umbraco.Tests/Views/site1/template2.cshtml | 4 ++++ 12 files changed, 31 insertions(+), 21 deletions(-) create mode 100644 src/Umbraco.Tests/Views/site1/template2.cshtml diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs index 63164cf271..4ca32bb718 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs @@ -25,6 +25,8 @@ namespace Umbraco.Core.Models.PublishedContent { Id = contentType.Id; Alias = contentType.Alias; + Name = contentType.Name; + Description = contentType.Description; _compositionAliases = new HashSet(contentType.CompositionAliases(), StringComparer.InvariantCultureIgnoreCase); _propertyTypes = contentType.CompositionPropertyTypes .Select(x => new PublishedPropertyType(this, x)) @@ -33,10 +35,12 @@ namespace Umbraco.Core.Models.PublishedContent } // internal so it can be used for unit tests - internal PublishedContentType(int id, string alias, IEnumerable compositionAliases, IEnumerable propertyTypes) + internal PublishedContentType(int id, string alias, string name, string description, IEnumerable compositionAliases, IEnumerable propertyTypes) { Id = id; Alias = alias; + Name = name; + Description = description; _compositionAliases = new HashSet(compositionAliases, StringComparer.InvariantCultureIgnoreCase); _propertyTypes = propertyTypes.ToArray(); foreach (var propertyType in _propertyTypes) @@ -46,7 +50,7 @@ namespace Umbraco.Core.Models.PublishedContent // create detached content type - ie does not match anything in the DB internal PublishedContentType(string alias, IEnumerable compositionAliases, IEnumerable propertyTypes) - : this(0, alias, compositionAliases, propertyTypes) + : this(0, alias, string.Empty, string.Empty, compositionAliases, propertyTypes) { } private void InitializeIndexes() @@ -63,6 +67,8 @@ namespace Umbraco.Core.Models.PublishedContent public int Id { get; private set; } public string Alias { get; private set; } + public string Name { get; private set; } + public string Description { get; private set; } public HashSet CompositionAliases { get { return _compositionAliases; } } #endregion diff --git a/src/Umbraco.Tests/CodeFirst/StronglyTypedMapperTest.cs b/src/Umbraco.Tests/CodeFirst/StronglyTypedMapperTest.cs index 5fe2efaa2c..6f64ef8b69 100644 --- a/src/Umbraco.Tests/CodeFirst/StronglyTypedMapperTest.cs +++ b/src/Umbraco.Tests/CodeFirst/StronglyTypedMapperTest.cs @@ -83,7 +83,7 @@ namespace Umbraco.Tests.CodeFirst new PublishedPropertyType("articleDate", 0, "?"), new PublishedPropertyType("pageTitle", 0, "?"), }; - var type = new AutoPublishedContentType(0, "anything", propertyTypes); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", propertyTypes); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; Debug.Print("INIT STRONG {0}", PublishedContentType.Get(PublishedItemType.Content, "anything") @@ -148,4 +148,4 @@ namespace Umbraco.Tests.CodeFirst } #endregion } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests/LibraryTests.cs b/src/Umbraco.Tests/LibraryTests.cs index 086395f456..42e218835c 100644 --- a/src/Umbraco.Tests/LibraryTests.cs +++ b/src/Umbraco.Tests/LibraryTests.cs @@ -43,7 +43,7 @@ namespace Umbraco.Tests // AutoPublishedContentType will auto-generate other properties new PublishedPropertyType("content", 0, "?"), }; - var type = new AutoPublishedContentType(0, "anything", propertyTypes); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", propertyTypes); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; Debug.Print("INIT LIB {0}", PublishedContentType.Get(PublishedItemType.Content, "anything") diff --git a/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs b/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs index 4c1272550d..7bfe75f9aa 100644 --- a/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs +++ b/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs @@ -41,7 +41,7 @@ namespace Umbraco.Tests.Membership new PublishedPropertyType("bodyText", 0, "?"), new PublishedPropertyType("author", 0, "?") }; - var type = new AutoPublishedContentType(0, "anything", propertyTypes); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", propertyTypes); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; } diff --git a/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs b/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs index 07787d8e2c..fd736f0700 100644 --- a/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs +++ b/src/Umbraco.Tests/PublishedContent/DynamicDocumentTestsBase.cs @@ -50,7 +50,7 @@ namespace Umbraco.Tests.PublishedContent new PublishedPropertyType("creatorName", 0, "?"), new PublishedPropertyType("blah", 0, "?"), // ugly error when that one is missing... }; - var type = new AutoPublishedContentType(0, "anything", propertyTypes); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", propertyTypes); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; } @@ -729,4 +729,4 @@ namespace Umbraco.Tests.PublishedContent return s.Contains(val.ToString()); } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs index 8efe6efd72..c57bacad29 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -24,7 +24,7 @@ namespace Umbraco.Tests.PublishedContent // need to specify a custom callback for unit tests // AutoPublishedContentTypes generates properties automatically - var type = new AutoPublishedContentType(0, "anything", new PublishedPropertyType[] {}); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", new PublishedPropertyType[] {}); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; // need to specify a different callback for testing @@ -251,4 +251,4 @@ namespace Umbraco.Tests.PublishedContent } } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs index 1c83691d04..1f2f43de8b 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentMoreTests.cs @@ -234,9 +234,9 @@ namespace Umbraco.Tests.PublishedContent new PublishedPropertyType("prop1", 1, "?"), }; - var contentType1 = new PublishedContentType(1, "ContentType1", Enumerable.Empty(), props); - var contentType2 = new PublishedContentType(2, "ContentType2", Enumerable.Empty(), props); - var contentType2s = new PublishedContentType(3, "ContentType2Sub", Enumerable.Empty(), props); + var contentType1 = new PublishedContentType(1, "ContentType1", "ContentType1", "ContentType1", Enumerable.Empty(), props); + var contentType2 = new PublishedContentType(2, "ContentType2", "ContentType2", "ContentType2", Enumerable.Empty(), props); + var contentType2s = new PublishedContentType(3, "ContentType2Sub", "ContentType2Sub", "ContentType2Sub", Enumerable.Empty(), props); cache.Add(new SolidPublishedContent(contentType1) { diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs index 789d9f7218..c0fff5f8da 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestBase.cs @@ -29,7 +29,7 @@ namespace Umbraco.Tests.PublishedContent // AutoPublishedContentType will auto-generate other properties new PublishedPropertyType("content", 0, Constants.PropertyEditors.TinyMCEAlias), }; - var type = new AutoPublishedContentType(0, "anything", propertyTypes); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", propertyTypes); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; var rCtx = GetRoutingContext("/test", 1234); @@ -65,4 +65,4 @@ namespace Umbraco.Tests.PublishedContent UmbracoContext.Current = null; } } -} \ No newline at end of file +} diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTestElements.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTestElements.cs index 82115d670e..2ebc8c2e4b 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTestElements.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTestElements.cs @@ -354,12 +354,12 @@ namespace Umbraco.Tests.PublishedContent { private static readonly PublishedPropertyType Default = new PublishedPropertyType("*", 0, "?"); - public AutoPublishedContentType(int id, string alias, IEnumerable propertyTypes) - : base(id, alias, Enumerable.Empty(), propertyTypes) + public AutoPublishedContentType(int id, string alias, string name, string description, IEnumerable propertyTypes) + : base(id, alias, name, description, Enumerable.Empty(), propertyTypes) { } - public AutoPublishedContentType(int id, string alias, IEnumerable compositionAliases, IEnumerable propertyTypes) - : base(id, alias, compositionAliases, propertyTypes) + public AutoPublishedContentType(int id, string alias, string name, string description, IEnumerable compositionAliases, IEnumerable propertyTypes) + : base(id, alias, name, description, compositionAliases, propertyTypes) { } public override PublishedPropertyType GetPropertyType(string alias) diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index 5ec34ea781..4358f5de47 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -49,7 +49,7 @@ namespace Umbraco.Tests.PublishedContent new PublishedPropertyType("testRecursive", 0, "?"), }; var compositionAliases = new[] { "MyCompositionAlias" }; - var type = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", compositionAliases, propertyTypes); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; } diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs index dfc6317d32..c7fe2d0168 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs @@ -15,7 +15,7 @@ namespace Umbraco.Tests.TestHelpers // need to specify a custom callback for unit tests // AutoPublishedContentTypes generates properties automatically - var type = new AutoPublishedContentType(0, "anything", new PublishedPropertyType[] {}); + var type = new AutoPublishedContentType(0, "anything", "anything", "anything", new PublishedPropertyType[] {}); PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; } diff --git a/src/Umbraco.Tests/Views/site1/template2.cshtml b/src/Umbraco.Tests/Views/site1/template2.cshtml new file mode 100644 index 0000000000..3e82f2f0d2 --- /dev/null +++ b/src/Umbraco.Tests/Views/site1/template2.cshtml @@ -0,0 +1,4 @@ +@inherits Umbraco.Web.Mvc.UmbracoTemplatePage +@{ + Layout = null; +} \ No newline at end of file From 7acafe67a48f8b30cbeb75a965be616a1e228adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Alk=C3=A6rsig?= Date: Thu, 17 Jan 2019 13:23:35 +0100 Subject: [PATCH 012/213] Delete template2.cshtml Auto-generated test file --- src/Umbraco.Tests/Views/site1/template2.cshtml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/Umbraco.Tests/Views/site1/template2.cshtml diff --git a/src/Umbraco.Tests/Views/site1/template2.cshtml b/src/Umbraco.Tests/Views/site1/template2.cshtml deleted file mode 100644 index 3e82f2f0d2..0000000000 --- a/src/Umbraco.Tests/Views/site1/template2.cshtml +++ /dev/null @@ -1,4 +0,0 @@ -@inherits Umbraco.Web.Mvc.UmbracoTemplatePage -@{ - Layout = null; -} \ No newline at end of file From e871392405acb1ca475819b22fa8a49bc3fa694d Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 23 Jan 2019 07:54:45 +0100 Subject: [PATCH 013/213] Added IsPublished(culture) to IPublishedContent --- .../PublishedContent/IPublishedContent.cs | 8 ++++++-- .../PublishedContentWrapped.cs | 4 ++++ .../XmlPublishedContentInitBenchmarks.cs | 20 ++++++++++--------- .../Published/NestedContentTests.cs | 1 + .../PublishedContentDataTableTests.cs | 1 + .../SolidPublishedSnapshot.cs | 1 + .../TestHelpers/Stubs/TestPublishedContent.cs | 1 + .../Models/PublishedContentBase.cs | 2 ++ .../NuCache/PublishedContent.cs | 17 ++++++++++++++++ .../PublishedCache/PublishedMember.cs | 2 ++ .../DictionaryPublishedContent.cs | 2 ++ .../XmlPublishedCache/XmlPublishedContent.cs | 12 +++++++++-- src/Umbraco.Web/umbraco.presentation/page.cs | 5 +++++ 13 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs index c5fa0330f2..e50fb2c396 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContent.cs @@ -153,8 +153,12 @@ namespace Umbraco.Core.Models.PublishedContent ///
bool IsDraft(string culture = null); - // fixme/task - consider having an IsPublished flag too - // so that when IsDraft is true, we can check whether there is a published version? + /// + /// Gets a value indicating whether the content is published. + /// + /// + bool IsPublished(string culture = null); + #endregion diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs index 36755c8944..42ff16bae5 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentWrapped.cs @@ -111,6 +111,10 @@ namespace Umbraco.Core.Models.PublishedContent /// public virtual bool IsDraft(string culture = null) => _content.IsDraft(culture); + /// + public virtual bool IsPublished(string culture = null) => _content.IsPublished(culture); + + #endregion #region Tree diff --git a/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs index 751767f8e7..860dc0ac4b 100644 --- a/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs @@ -94,6 +94,7 @@ namespace Umbraco.Tests.Benchmarks Guid key, version; string name, urlName, writerName, creatorName, docTypeAlias, path; bool isDraft; + bool isPublished; DateTime createDate, updateDate; PublishedContentType publishedContentType; Dictionary properties; @@ -104,7 +105,7 @@ namespace Umbraco.Tests.Benchmarks OriginalInitializeNode(_xml10.DocumentElement, false, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType, out properties); } @@ -114,7 +115,7 @@ namespace Umbraco.Tests.Benchmarks OriginalInitializeNode(_xml100.DocumentElement, false, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType, out properties); } @@ -124,7 +125,7 @@ namespace Umbraco.Tests.Benchmarks OriginalInitializeNode(_xml1000.DocumentElement, false, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType, out properties); } @@ -134,7 +135,7 @@ namespace Umbraco.Tests.Benchmarks OriginalInitializeNode(_xml10000.DocumentElement, false, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out version, out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType, out properties); } @@ -144,7 +145,7 @@ namespace Umbraco.Tests.Benchmarks XmlPublishedContent.InitializeNode(null, _xml10.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out createDate, out updateDate, out level, out isDraft, out isPublished, out publishedContentType, out properties, GetPublishedContentType); } @@ -154,7 +155,7 @@ namespace Umbraco.Tests.Benchmarks XmlPublishedContent.InitializeNode(null, _xml100.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out createDate, out updateDate, out level, out isDraft, out isPublished,out publishedContentType, out properties, GetPublishedContentType); } @@ -164,7 +165,7 @@ namespace Umbraco.Tests.Benchmarks XmlPublishedContent.InitializeNode(null, _xml1000.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out createDate, out updateDate, out level, out isDraft, out isPublished,out publishedContentType, out properties, GetPublishedContentType); } @@ -174,7 +175,7 @@ namespace Umbraco.Tests.Benchmarks XmlPublishedContent.InitializeNode(null, _xml10000.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, - out createDate, out updateDate, out level, out isDraft, out publishedContentType, + out createDate, out updateDate, out level, out isDraft, out isPublished,out publishedContentType, out properties, GetPublishedContentType); } @@ -182,7 +183,7 @@ namespace Umbraco.Tests.Benchmarks internal static void OriginalInitializeNode(XmlNode xmlNode, bool legacy, bool isPreviewing, out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName, out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path, - out Guid version, out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, + out Guid version, out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, out bool isPublished, out PublishedContentType contentType, out Dictionary properties) { //initialize the out params with defaults: @@ -193,6 +194,7 @@ namespace Umbraco.Tests.Benchmarks name = writerName = urlName = creatorName = docTypeAlias = path = null; createDate = updateDate = default(DateTime); isDraft = false; + isPublished = true; contentType = null; properties = null; diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests/Published/NestedContentTests.cs index b5d6182c28..91810d6de1 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests/Published/NestedContentTests.cs @@ -262,6 +262,7 @@ namespace Umbraco.Tests.Published // ReSharper disable UnassignedGetOnlyAutoProperty public override PublishedItemType ItemType { get; } public override bool IsDraft(string culture = null) => false; + public override bool IsPublished(string culture = null) => true; 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 73f3cd1537..283ed1edd9 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentDataTableTests.cs @@ -217,6 +217,7 @@ namespace Umbraco.Tests.PublishedContent public Guid Version { get; set; } public int Level { get; set; } public bool IsDraft(string culture = null) => false; + public bool IsPublished(string culture = null) => true; public IEnumerable Properties { get; set; } diff --git a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs index f7077ecb3a..a838e06a9a 100644 --- a/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs +++ b/src/Umbraco.Tests/PublishedContent/SolidPublishedSnapshot.cs @@ -192,6 +192,7 @@ namespace Umbraco.Tests.PublishedContent public PublishedItemType ItemType { get { return PublishedItemType.Content; } } public bool IsDraft(string culture = null) => false; + public bool IsPublished(string culture = null) => true; #endregion diff --git a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs index 58c8e37cbf..a9abe96232 100644 --- a/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs +++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestPublishedContent.cs @@ -48,6 +48,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs public string GetUrl(string culture = null) => throw new NotSupportedException(); public PublishedItemType ItemType => ContentType.ItemType; public bool IsDraft(string culture = null) => false; + public bool IsPublished(string culture = null) => true; 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 c772f6ca85..12acb6b0c8 100644 --- a/src/Umbraco.Web/Models/PublishedContentBase.cs +++ b/src/Umbraco.Web/Models/PublishedContentBase.cs @@ -144,6 +144,8 @@ namespace Umbraco.Web.Models /// public abstract bool IsDraft(string culture = null); + public abstract bool IsPublished(string culture = null); + #endregion #region Tree diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index d1e1d63630..69c672ab98 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -293,6 +293,23 @@ namespace Umbraco.Web.PublishedCache.NuCache return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && cvar.IsDraft; } + public override bool IsPublished(string culture = null) + { + if (!ContentType.VariesByCulture()) + { + return _contentData.Published; + } + + // handle context culture + if (culture == null) + { + culture = VariationContextAccessor?.VariationContext?.Culture ?? ""; + } + + //If the current culture is not a draft, it must be the published version + return _contentData.CultureInfos.TryGetValue(culture, out var cvar) && !cvar.IsDraft; + } + #endregion #region Tree diff --git a/src/Umbraco.Web/PublishedCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/PublishedMember.cs index ef95b2846c..cbe2250920 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedMember.cs @@ -78,6 +78,8 @@ namespace Umbraco.Web.PublishedCache public override bool IsDraft(string culture = null) => false; + public override bool IsPublished(string culture = null) => true; + public override IPublishedContent Parent => null; public override IEnumerable Children => Enumerable.Empty(); diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs index 83bd84dab6..a395db1da5 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs @@ -179,6 +179,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public override bool IsDraft(string culture = null) => false; + public override bool IsPublished(string culture = null) => true; + public override IEnumerable Properties => _properties; public override IEnumerable Children => _getChildren.Value; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index 2b3bc39452..c3cf22559d 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -63,6 +63,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private int _sortOrder; private int _level; private bool _isDraft; + private bool _isPublished; public override IEnumerable Children { @@ -228,6 +229,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache return _isDraft; // bah } + public override bool IsPublished(string culture = null) + { + EnsureNodeInitialized(); + return _isPublished; + } + public override IEnumerable Properties { get @@ -280,7 +287,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache InitializeNode(this, _xmlNode, _isPreviewing, out _id, out _key, out _template, out _sortOrder, out _name, out _writerName, out _urlName, out _creatorName, out _creatorId, out _writerId, out _docTypeAlias, out _docTypeId, out _path, - out _createDate, out _updateDate, out _level, out _isDraft, out _contentType, out _properties, + out _createDate, out _updateDate, out _level, out _isDraft, out _isPublished, out _contentType, out _properties, _contentTypeCache.Get); _nodeInitialized = true; @@ -290,7 +297,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache internal static void InitializeNode(XmlPublishedContent node, XmlNode xmlNode, bool isPreviewing, out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName, out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path, - out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, + out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft,out bool isPublished, out PublishedContentType contentType, out Dictionary properties, Func getPublishedContentType) { @@ -302,6 +309,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache name = writerName = urlName = creatorName = docTypeAlias = path = null; createDate = updateDate = default(DateTime); isDraft = false; + isPublished = false; contentType = null; properties = null; diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index 7b591640b5..0c9b0c6ff3 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -469,6 +469,11 @@ namespace umbraco throw new NotImplementedException(); } + public bool IsPublished(string culture = null) + { + throw new NotImplementedException(); + } + public IPublishedContent Parent { get { return _parent; } From f10b35780cdd1a15a0030786eee69353e9558a47 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 23 Jan 2019 10:22:29 +0100 Subject: [PATCH 014/213] - Removed PostFilterParams - Handling of PostFilter using Expression trees --- .../src/common/resources/entity.resource.js | 15 +- src/Umbraco.Web/Editors/EntityController.cs | 131 ++++++++++++++---- .../Editors/TemplateQueryController.cs | 2 +- .../Models/TemplateQuery/OperatorFactory.cs | 32 +++++ .../Models/TemplateQuery/QueryCondition.cs | 12 +- src/Umbraco.Web/Umbraco.Web.csproj | 1 + 6 files changed, 147 insertions(+), 46 deletions(-) create mode 100644 src/Umbraco.Web/Models/TemplateQuery/OperatorFactory.cs diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js index f864696873..753d180880 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js @@ -254,22 +254,13 @@ function entityResource($q, $http, umbRequestHelper) { * * @param {string} type Object type name * @param {string} postFilter optional filter expression which will execute a dynamic where clause on the server - * @param {string} postFilterParams optional parameters for the postFilter expression * @returns {Promise} resourcePromise object containing the entity. * */ - getAll: function (type, postFilter, postFilterParams) { - + getAll: function (type, postFilter) { //need to build the query string manually - var query = "type=" + type + "&postFilter=" + (postFilter ? postFilter : ""); - if (postFilter && postFilterParams) { - var counter = 0; - _.each(postFilterParams, function(val, key) { - query += "&postFilterParams[" + counter + "].key=" + key + "&postFilterParams[" + counter + "].value=" + val; - counter++; - }); - } - + var query = "type=" + type + "&postFilter=" + (postFilter ? encodeURIComponent(postFilter) : ""); + return umbRequestHelper.resourcePromise( $http.get( umbRequestHelper.getApiUrl( diff --git a/src/Umbraco.Web/Editors/EntityController.cs b/src/Umbraco.Web/Editors/EntityController.cs index b25f3f5af1..19f7158c5d 100644 --- a/src/Umbraco.Web/Editors/EntityController.cs +++ b/src/Umbraco.Web/Editors/EntityController.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Net; using System.Web.Http; using AutoMapper; @@ -11,11 +10,10 @@ using Umbraco.Web.Mvc; using System.Linq; using System.Net.Http; using System.Net.Http.Formatting; +using System.Reflection; using Umbraco.Core.Models; -using Constants = Umbraco.Core.Constants; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using System.Web.Http.Controllers; -using Examine; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; @@ -24,12 +22,14 @@ using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Core.Xml; using Umbraco.Web.Models.Mapping; +using Umbraco.Web.Models.TemplateQuery; using Umbraco.Web.Search; using Umbraco.Web.Services; using Umbraco.Web.Trees; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; namespace Umbraco.Web.Editors { /// @@ -242,7 +242,7 @@ namespace Umbraco.Web.Editors }; } - + /// /// Gets an entity by a xpath query /// @@ -863,9 +863,15 @@ namespace Umbraco.Web.Editors } } - public IEnumerable GetAll(UmbracoEntityTypes type, string postFilter, [FromUri]IDictionary postFilterParams) + /// + /// + /// + /// The type of entity. + /// Optional filter - Format like: "BoolVariable==true&IntVariable>=6". Invalid filters are ignored. + /// + public IEnumerable GetAll(UmbracoEntityTypes type, string postFilter) { - return GetResultForAll(type, postFilter, postFilterParams); + return GetResultForAll(type, postFilter); } /// @@ -873,29 +879,28 @@ namespace Umbraco.Web.Editors /// /// /// A string where filter that will filter the results dynamically with linq - optional - /// the parameters to fill in the string where filter - optional /// - private IEnumerable GetResultForAll(UmbracoEntityTypes entityType, string postFilter = null, IDictionary postFilterParams = null) + private IEnumerable GetResultForAll(UmbracoEntityTypes entityType, string postFilter = null) { var objectType = ConvertToObjectType(entityType); if (objectType.HasValue) { //TODO: Should we order this by something ? var entities = Services.EntityService.GetAll(objectType.Value).WhereNotNull().Select(Mapper.Map); - return ExecutePostFilter(entities, postFilter, postFilterParams); + return ExecutePostFilter(entities, postFilter); } //now we need to convert the unknown ones switch (entityType) { case UmbracoEntityTypes.Template: var templates = Services.FileService.GetTemplates(); - var filteredTemplates = ExecutePostFilter(templates, postFilter, postFilterParams); + var filteredTemplates = ExecutePostFilter(templates, postFilter); return filteredTemplates.Select(Mapper.Map); case UmbracoEntityTypes.Macro: //Get all macros from the macro service var macros = Services.MacroService.GetAll().WhereNotNull().OrderBy(x => x.Name); - var filteredMacros = ExecutePostFilter(macros, postFilter, postFilterParams); + var filteredMacros = ExecutePostFilter(macros, postFilter); return filteredMacros.Select(Mapper.Map); case UmbracoEntityTypes.PropertyType: @@ -906,7 +911,7 @@ namespace Umbraco.Web.Editors .ToArray() .SelectMany(x => x.PropertyTypes) .DistinctBy(composition => composition.Alias); - var filteredPropertyTypes = ExecutePostFilter(propertyTypes, postFilter, postFilterParams); + var filteredPropertyTypes = ExecutePostFilter(propertyTypes, postFilter); return Mapper.Map, IEnumerable>(filteredPropertyTypes); case UmbracoEntityTypes.PropertyGroup: @@ -917,32 +922,32 @@ namespace Umbraco.Web.Editors .ToArray() .SelectMany(x => x.PropertyGroups) .DistinctBy(composition => composition.Name); - var filteredpropertyGroups = ExecutePostFilter(propertyGroups, postFilter, postFilterParams); + var filteredpropertyGroups = ExecutePostFilter(propertyGroups, postFilter); return Mapper.Map, IEnumerable>(filteredpropertyGroups); case UmbracoEntityTypes.User: var users = Services.UserService.GetAll(0, int.MaxValue, out _); - var filteredUsers = ExecutePostFilter(users, postFilter, postFilterParams); + var filteredUsers = ExecutePostFilter(users, postFilter); return Mapper.Map, IEnumerable>(filteredUsers); case UmbracoEntityTypes.Stylesheet: - if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0)) + if (!postFilter.IsNullOrWhiteSpace()) throw new NotSupportedException("Filtering on stylesheets is not currently supported"); return Services.FileService.GetStylesheets().Select(Mapper.Map); - + case UmbracoEntityTypes.Language: - if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0)) + if (!postFilter.IsNullOrWhiteSpace() ) throw new NotSupportedException("Filtering on languages is not currently supported"); return Services.LocalizationService.GetAllLanguages().Select(Mapper.Map); case UmbracoEntityTypes.DictionaryItem: - if (!postFilter.IsNullOrWhiteSpace() || (postFilterParams != null && postFilterParams.Count > 0)) - throw new NotSupportedException("Filtering on languages is not currently supported"); + if (!postFilter.IsNullOrWhiteSpace()) + throw new NotSupportedException("Filtering on dictionary items is not currently supported"); return GetAllDictionaryItems(); @@ -952,20 +957,90 @@ namespace Umbraco.Web.Editors } } - private IEnumerable ExecutePostFilter(IEnumerable entities, string postFilter, IDictionary postFilterParams) + private IEnumerable ExecutePostFilter(IEnumerable entities, string postFilter) { - // if a post filter is assigned then try to execute it - if (postFilter.IsNullOrWhiteSpace() == false) + if (postFilter.IsNullOrWhiteSpace()) return entities; + + var postFilterConditions = postFilter.Split('&'); + + foreach (var postFilterCondition in postFilterConditions) { - // fixme/task/critical - trouble is, we've killed the dynamic Where thing! - throw new NotImplementedException("oops"); - //return postFilterParams == null - // ? entities.AsQueryable().Where(postFilter).ToArray() - // : entities.AsQueryable().Where(postFilter, postFilterParams).ToArray(); + var queryCondition = BuildQueryCondition(postFilterCondition); + + if (queryCondition != null) + { + var whereClauseExpression = queryCondition.BuildCondition("x"); + + entities = entities.Where(whereClauseExpression.Compile()); + } + } return entities; } + private static QueryCondition BuildQueryCondition(string postFilter) + { + var postFilterParts = postFilter.Split(new[] + { + "=", + "==", + "!=", + "<>", + ">", + "<", + ">=", + "<=" + }, 2, StringSplitOptions.RemoveEmptyEntries); + + if (postFilterParts.Length != 2) + { + return null; + } + + var propertyName = postFilterParts[0]; + var constraintValue = postFilterParts[1]; + var stringOperator = postFilter.Substring(propertyName.Length, + postFilter.Length - propertyName.Length - constraintValue.Length); + Operator binaryOperator; + + try + { + binaryOperator = OperatorFactory.FromString(stringOperator); + } + catch (ArgumentException) + { + // unsupported operators are ignored + return null; + } + + var type = typeof(T); + var property = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance); + + if (property == null) + { + return null; + } + + var queryCondition = new QueryCondition() + { + Term = new OperatorTerm() + { + Operator = binaryOperator + }, + ConstraintValue = constraintValue, + Property = new PropertyModel() + { + Alias = propertyName, + Name = propertyName, + Type = property.PropertyType.Name + } + }; + + return queryCondition; + } + + + #region Methods to get all dictionary items private IEnumerable GetAllDictionaryItems() @@ -993,7 +1068,7 @@ namespace Umbraco.Web.Editors GetChildItemsForList(childItem, list); } - } + } #endregion } diff --git a/src/Umbraco.Web/Editors/TemplateQueryController.cs b/src/Umbraco.Web/Editors/TemplateQueryController.cs index 73ebdf3bc5..2483446ec2 100644 --- a/src/Umbraco.Web/Editors/TemplateQueryController.cs +++ b/src/Umbraco.Web/Editors/TemplateQueryController.cs @@ -118,7 +118,7 @@ namespace Umbraco.Web.Editors foreach (var condition in model.Filters.Where(x => !x.ConstraintValue.IsNullOrWhiteSpace())) { //x is passed in as the parameter alias for the linq where statement clause - var operation = condition.BuildCondition("x", contents, Properties); + var operation = condition.BuildCondition("x"); contents = contents.Where(operation.Compile()); queryExpression.Append(indent); diff --git a/src/Umbraco.Web/Models/TemplateQuery/OperatorFactory.cs b/src/Umbraco.Web/Models/TemplateQuery/OperatorFactory.cs new file mode 100644 index 0000000000..0b595723f1 --- /dev/null +++ b/src/Umbraco.Web/Models/TemplateQuery/OperatorFactory.cs @@ -0,0 +1,32 @@ +using System; + +namespace Umbraco.Web.Models.TemplateQuery +{ + public static class OperatorFactory + { + public static Operator FromString(string stringOperator) + { + if (stringOperator == null) throw new ArgumentNullException(nameof(stringOperator)); + + switch (stringOperator) + { + case "=": + case "==": + return Operator.Equals; + case "!=": + case "<>": + return Operator.NotEquals; + case "<": + return Operator.LessThan; + case "<=": + return Operator.LessThanEqualTo; + case ">": + return Operator.GreaterThan; + case ">=": + return Operator.GreaterThanEqualTo; + default: + throw new ArgumentException($"A operator cannot be created from the specified string '{stringOperator}'", nameof(stringOperator)); + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs b/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs index 009b568556..a58badcf2c 100644 --- a/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs +++ b/src/Umbraco.Web/Models/TemplateQuery/QueryCondition.cs @@ -18,11 +18,10 @@ namespace Umbraco.Web.Models.TemplateQuery private static Lazy StringContainsMethodInfo => new Lazy(() => typeof(string).GetMethod("Contains", new[] {typeof(string)})); - public static Expression> BuildCondition(this QueryCondition condition, - string parameterAlias, IEnumerable contents, IEnumerable properties) + public static Expression> BuildCondition(this QueryCondition condition, string parameterAlias) { object constraintValue; - switch (condition.Property.Type) + switch (condition.Property.Type.ToLowerInvariant()) { case "string": constraintValue = condition.ConstraintValue; @@ -30,12 +29,15 @@ namespace Umbraco.Web.Models.TemplateQuery case "datetime": constraintValue = DateTime.Parse(condition.ConstraintValue); break; + case "boolean": + constraintValue = Boolean.Parse(condition.ConstraintValue); + break; default: constraintValue = Convert.ChangeType(condition.ConstraintValue, typeof(int)); break; } - var parameterExpression = Expression.Parameter(typeof(IPublishedContent), parameterAlias); + var parameterExpression = Expression.Parameter(typeof(T), parameterAlias); var propertyExpression = Expression.Property(parameterExpression, condition.Property.Alias); var valueExpression = Expression.Constant(constraintValue); @@ -73,7 +75,7 @@ namespace Umbraco.Web.Models.TemplateQuery } var predicate = - Expression.Lambda>(bodyExpression.Reduce(), parameterExpression); + Expression.Lambda>(bodyExpression.Reduce(), parameterExpression); return predicate; } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 6736f7512b..d2913dd228 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -172,6 +172,7 @@ + From d2d852f0f3583f89336a3db4b53ad68d12303d45 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 23 Jan 2019 10:39:51 +0100 Subject: [PATCH 015/213] Handled "Method with optional parameter is hidden by overload" issues --- src/Umbraco.Web/PublishedContentExtensions.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 530c9bd9b4..f1e9e66e70 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -799,7 +799,7 @@ namespace Umbraco.Web return content.DescendantsOrSelf(false, p => p.Level >= level, culture); } - public static IEnumerable Descendants(this IPublishedContent content, string contentTypeAlias, string culture = null) + public static IEnumerable Descendants(this IPublishedContent content, string contentTypeAlias, string culture) { return content.DescendantsOrSelf(false, p => p.ContentType.Alias == contentTypeAlias, culture); } @@ -826,7 +826,7 @@ namespace Umbraco.Web return content.DescendantsOrSelf(true, p => p.Level >= level, culture); } - public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string contentTypeAlias, string culture = null) + public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string contentTypeAlias, string culture) { return content.DescendantsOrSelf(true, p => p.ContentType.Alias == contentTypeAlias, culture); } @@ -853,7 +853,7 @@ namespace Umbraco.Web return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.Level == level); } - public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias, string culture = null) + public static IPublishedContent Descendant(this IPublishedContent content, string contentTypeAlias, string culture) { return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias); } @@ -880,7 +880,7 @@ namespace Umbraco.Web return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.Level == level); } - public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias, string culture = null) + public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string contentTypeAlias, string culture) { return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.ContentType.Alias == contentTypeAlias); } @@ -1017,7 +1017,7 @@ namespace Umbraco.Web /// /// Gets the first child of the content, of a given content type. /// - public static IPublishedContent FirstChild(this IPublishedContent content, string alias, string culture = null) // fixme/task oops + public static IPublishedContent FirstChild(this IPublishedContent content, string alias, string culture) { return content.Children(culture,alias).FirstOrDefault(); } From ca76a5424a0c88c1ed997925e5d3105e772b5ecc Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 23 Jan 2019 12:34:41 +0100 Subject: [PATCH 016/213] Only allow local KeepAlive Pings requests --- .../Editors/KeepAliveController.cs | 7 ++----- .../Mvc/OnlyLocalRequestsAttribute.cs | 20 +++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 3 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Web/Mvc/OnlyLocalRequestsAttribute.cs diff --git a/src/Umbraco.Web/Editors/KeepAliveController.cs b/src/Umbraco.Web/Editors/KeepAliveController.cs index fa33abea44..b15621ee23 100644 --- a/src/Umbraco.Web/Editors/KeepAliveController.cs +++ b/src/Umbraco.Web/Editors/KeepAliveController.cs @@ -1,16 +1,13 @@ using System.Runtime.Serialization; using System.Web.Http; +using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; namespace Umbraco.Web.Editors { - // fixme/task - deal with this - // this is not authenticated, and therefore public, and therefore reveals we - // are running Umbraco - but, all requests should come from localhost really, - // so there should be a way to 404 when the request comes from the outside. - public class KeepAliveController : UmbracoApiController { + [OnlyLocalRequests] [HttpGet] public KeepAlivePingResult Ping() { diff --git a/src/Umbraco.Web/Mvc/OnlyLocalRequestsAttribute.cs b/src/Umbraco.Web/Mvc/OnlyLocalRequestsAttribute.cs new file mode 100644 index 0000000000..ed36e6e3df --- /dev/null +++ b/src/Umbraco.Web/Mvc/OnlyLocalRequestsAttribute.cs @@ -0,0 +1,20 @@ + +using System.Net; +using System.Net.Http; +using System.Web.Http; +using System.Web.Http.Controllers; +using System.Web.Http.Filters; + +namespace Umbraco.Web.Mvc +{ + public class OnlyLocalRequestsAttribute : ActionFilterAttribute + { + public override void OnActionExecuting(HttpActionContext actionContext) + { + if (!actionContext.Request.IsLocal()) + { + throw new HttpResponseException(HttpStatusCode.NotFound); + } + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 64a60d824a..7211ec8af9 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -172,6 +172,7 @@ + From f8b52a57c3cbdf99ab497b9018fb5c34073e085a Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 23 Jan 2019 14:16:42 +0100 Subject: [PATCH 017/213] Injecting Umbraco Context Accessor and not saving the url on the class --- .../PublishedContentCacheTests.cs | 7 ++-- .../PublishedMediaCacheTests.cs | 18 ++++++---- .../Published/NestedContentTests.cs | 7 ++-- .../PublishedContent/NuCacheTests.cs | 1 + .../PublishedContent/PublishedMediaTests.cs | 6 ++-- .../Scoping/ScopedNuCacheTests.cs | 1 + .../ContentTypeServiceVariantsTests.cs | 2 ++ .../TestHelpers/TestWithDatabaseBase.cs | 1 + .../Web/Mvc/UmbracoViewPageTests.cs | 8 +++-- .../Models/PublishedContentBase.cs | 34 +++++++++---------- .../PublishedCache/NuCache/ContentNode.cs | 29 +++++++++------- .../PublishedCache/NuCache/ContentNodeKit.cs | 9 +++-- .../PublishedCache/NuCache/ContentStore.cs | 19 +++++++---- .../PublishedCache/NuCache/MemberCache.cs | 14 +++++--- .../NuCache/PublishedContent.cs | 22 +++++++++--- .../PublishedCache/NuCache/PublishedMember.cs | 21 +++++++++--- .../NuCache/PublishedSnapshotService.cs | 14 ++++---- .../PublishedCache/PublishedMember.cs | 6 +++- .../DictionaryPublishedContent.cs | 4 ++- .../PublishedContentCache.cs | 7 ++-- .../XmlPublishedCache/PublishedMediaCache.cs | 9 +++-- .../XmlPublishedCache/PublishedMemberCache.cs | 15 ++++---- .../PublishedSnapshotService.cs | 18 ++++++---- .../XmlPublishedCache/XmlPublishedContent.cs | 22 ++++++++---- 24 files changed, 194 insertions(+), 100 deletions(-) diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs index 147a159d5f..e868e32b07 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedContentCacheTests.cs @@ -59,6 +59,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var umbracoSettings = Factory.GetInstance(); var globalSettings = Factory.GetInstance(); + var umbracoContextAccessor = Factory.GetInstance(); _xml = new XmlDocument(); _xml.LoadXml(GetXml()); @@ -66,9 +67,9 @@ namespace Umbraco.Tests.Cache.PublishedCache var appCache = new DictionaryAppCache(); var domainCache = new DomainCache(ServiceContext.DomainService, DefaultCultureAccessor); var publishedShapshot = new Umbraco.Web.PublishedCache.XmlPublishedCache.PublishedSnapshot( - new PublishedContentCache(xmlStore, domainCache, appCache, globalSettings, new SiteDomainHelper(), ContentTypesCache, null, null), - new PublishedMediaCache(xmlStore, ServiceContext.MediaService, ServiceContext.UserService, appCache, ContentTypesCache, Factory.GetInstance()), - new PublishedMemberCache(null, appCache, Current.Services.MemberService, ContentTypesCache), + new PublishedContentCache(xmlStore, domainCache, appCache, globalSettings, new SiteDomainHelper(), umbracoContextAccessor, ContentTypesCache, null, null), + new PublishedMediaCache(xmlStore, ServiceContext.MediaService, ServiceContext.UserService, appCache, ContentTypesCache, Factory.GetInstance(), umbracoContextAccessor), + new PublishedMemberCache(null, appCache, Current.Services.MemberService, ContentTypesCache, umbracoContextAccessor), domainCache); var publishedSnapshotService = new Mock(); publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny())).Returns(publishedShapshot); diff --git a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs index bd4f1610cd..07a6a6ee82 100644 --- a/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs +++ b/src/Umbraco.Tests/Cache/PublishedCache/PublishedMediaCacheTests.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; using Umbraco.Tests.PublishedContent; +using Umbraco.Web; namespace Umbraco.Tests.Cache.PublishedCache { @@ -26,6 +27,7 @@ namespace Umbraco.Tests.Cache.PublishedCache { private Dictionary _mediaTypes; + private IUmbracoContextAccessor _umbracoContextAccessor; protected override void Compose() { base.Compose(); @@ -33,6 +35,8 @@ namespace Umbraco.Tests.Cache.PublishedCache Composition.WithCollectionBuilder() .Clear() .Append(); + + _umbracoContextAccessor = Current.UmbracoContextAccessor; } protected override void Initialize() @@ -75,7 +79,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var mChild2 = MakeNewMedia("Child2", mType, user, mRoot2.Id); var ctx = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument) null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance()); var roots = cache.GetAtRoot(); Assert.AreEqual(2, roots.Count()); Assert.IsTrue(roots.Select(x => x.Id).ContainsAll(new[] {mRoot1.Id, mRoot2.Id})); @@ -93,7 +97,7 @@ namespace Umbraco.Tests.Cache.PublishedCache //var publishedMedia = PublishedMediaTests.GetNode(mRoot.Id, GetUmbracoContext("/test", 1234)); var umbracoContext = GetUmbracoContext("/test"); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), Current.Services.MediaService, Current.Services.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance()); var publishedMedia = cache.GetById(mRoot.Id); Assert.IsNotNull(publishedMedia); @@ -204,7 +208,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var result = new SearchResult("1234", 1, () => fields.ToDictionary(x => x.Key, x => new List { x.Value })); - var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); + var store = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance()); var doc = store.CreateFromCacheValues(store.ConvertFromSearchResult(result)); DoAssert(doc, 1234, key, null, 0, "/media/test.jpg", "Image", 23, "Shannon", "Shannon", 0, 0, "-1,1234", DateTime.Parse("2012-07-17T10:34:09"), DateTime.Parse("2012-07-16T10:34:09"), 2); @@ -220,7 +224,7 @@ namespace Umbraco.Tests.Cache.PublishedCache var xmlDoc = GetMediaXml(); ((XmlElement)xmlDoc.DocumentElement.FirstChild).SetAttribute("key", key.ToString()); var navigator = xmlDoc.SelectSingleNode("/root/Image").CreateNavigator(); - var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); + var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance()); var doc = cache.CreateFromCacheValues(cache.ConvertFromXPathNavigator(navigator, true)); DoAssert(doc, 2000, key, null, 2, "image1", "Image", 23, "Shannon", "Shannon", 33, 33, "-1,2000", DateTime.Parse("2012-06-12T14:13:17"), DateTime.Parse("2012-07-20T18:50:43"), 1); @@ -319,7 +323,8 @@ namespace Umbraco.Tests.Cache.PublishedCache // no xpath null, // not from examine - false), + false, + _umbracoContextAccessor), //callback to get the children (dd, n) => children, // callback to get a property @@ -329,7 +334,8 @@ namespace Umbraco.Tests.Cache.PublishedCache // no xpath null, // not from examine - false); + false, + _umbracoContextAccessor); return dicDoc; } diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests/Published/NestedContentTests.cs index b5d6182c28..375fb5ee0f 100644 --- a/src/Umbraco.Tests/Published/NestedContentTests.cs +++ b/src/Umbraco.Tests/Published/NestedContentTests.cs @@ -161,7 +161,7 @@ namespace Umbraco.Tests.Published new TestPublishedProperty(contentType1.GetPropertyType("property1"), $@"[ {{ ""key"": ""{keyA}"", ""propertyN1"": ""foo"", ""ncContentTypeAlias"": ""contentN1"" }} ]") - }); + }, Mock.Of()); var value = content.Value("property1"); // nested single converter returns proper TestModel value @@ -189,7 +189,8 @@ namespace Umbraco.Tests.Published {{ ""key"": ""{keyA}"", ""propertyN1"": ""foo"", ""ncContentTypeAlias"": ""contentN1"" }}, {{ ""key"": ""{keyB}"", ""propertyN1"": ""bar"", ""ncContentTypeAlias"": ""contentN1"" }} ]") - }); + }, + Mock.Of()); var value = content.Value("property2"); // nested many converter returns proper IEnumerable value @@ -249,7 +250,7 @@ namespace Umbraco.Tests.Published class TestPublishedContent : PublishedContentBase { - public TestPublishedContent(PublishedContentType contentType, Guid key, IEnumerable properties) + public TestPublishedContent(PublishedContentType contentType, Guid key, IEnumerable properties, IUmbracoContextAccessor umbracoContextAccessor): base(umbracoContextAccessor) { ContentType = contentType; Key = key; diff --git a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs index ef37a822c1..9130161d3a 100644 --- a/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs +++ b/src/Umbraco.Tests/PublishedContent/NuCacheTests.cs @@ -144,6 +144,7 @@ namespace Umbraco.Tests.PublishedContent null, new TestPublishedSnapshotAccessor(), variationAccessor, + Mock.Of(), Mock.Of(), scopeProvider, Mock.Of(), diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index dfb51e83fb..bc1d8c2b70 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -69,7 +69,7 @@ namespace Umbraco.Tests.PublishedContent { var cache = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, - Factory.GetInstance()); + Factory.GetInstance(), Factory.GetInstance()); var doc = cache.GetById(id); Assert.IsNotNull(doc); return doc; @@ -482,7 +482,7 @@ namespace Umbraco.Tests.PublishedContent "); var node = xml.DescendantsAndSelf("Image").Single(x => (int)x.Attribute("id") == nodeId); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance()); var nav = node.CreateNavigator(); @@ -502,7 +502,7 @@ namespace Umbraco.Tests.PublishedContent var errorXml = new XElement("error", string.Format("No media is maching '{0}'", 1234)); var nav = errorXml.CreateNavigator(); - var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance()); + var publishedMedia = new PublishedMediaCache(new XmlStore((XmlDocument)null, null, null, null), ServiceContext.MediaService, ServiceContext.UserService, new DictionaryAppCache(), ContentTypesCache, Factory.GetInstance(), Factory.GetInstance()); var converted = publishedMedia.ConvertFromXPathNodeIterator(nav.Select("/"), 1234); Assert.IsNull(converted); diff --git a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs index e8f3463ca7..eb545fdb4f 100644 --- a/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs +++ b/src/Umbraco.Tests/Scoping/ScopedNuCacheTests.cs @@ -90,6 +90,7 @@ namespace Umbraco.Tests.Scoping null, publishedSnapshotAccessor, Mock.Of(), + Mock.Of(), Logger, ScopeProvider, documentRepository, mediaRepository, memberRepository, diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs index d0c0b93b48..3d9a36ca80 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceVariantsTests.cs @@ -17,6 +17,7 @@ using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; using Umbraco.Core.Sync; using Umbraco.Tests.Testing; +using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.PublishedCache.NuCache; using Umbraco.Web.PublishedCache.NuCache.DataSource; @@ -62,6 +63,7 @@ namespace Umbraco.Tests.Services null, publishedSnapshotAccessor, Mock.Of(), + Mock.Of(), Logger, ScopeProvider, documentRepository, mediaRepository, memberRepository, diff --git a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs index 2deb30bbdd..b312bc1607 100644 --- a/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs +++ b/src/Umbraco.Tests/TestHelpers/TestWithDatabaseBase.cs @@ -264,6 +264,7 @@ namespace Umbraco.Tests.TestHelpers Factory.GetInstance(), ScopeProvider, cache, publishedSnapshotAccessor, variationContextAccessor, + Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), Factory.GetInstance(), DefaultCultureAccessor, Logger, diff --git a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs index 133cbb2ee7..fee18cb382 100644 --- a/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/UmbracoViewPageTests.cs @@ -419,13 +419,15 @@ namespace Umbraco.Tests.Web.Mvc //var provider = new ScopeUnitOfWorkProvider(databaseFactory, new RepositoryFactory(Mock.Of())); var scopeProvider = TestObjects.GetScopeProvider(Mock.Of()); var factory = Mock.Of(); - _service = new PublishedSnapshotService(svcCtx, factory, scopeProvider, cache, + var umbracoContextAccessor = Mock.Of(); + _service = new PublishedSnapshotService(svcCtx, factory, scopeProvider, cache, null, null, - null, null, null, + umbracoContextAccessor, null, null, null, new TestDefaultCultureAccessor(), Current.Logger, TestObjects.GetGlobalSettings(), new SiteDomainHelper(), Factory.GetInstance(), - null, true, false); // no events + null, true, false + ); // no events var http = GetHttpContextFactory(url, routeData).HttpContext; diff --git a/src/Umbraco.Web/Models/PublishedContentBase.cs b/src/Umbraco.Web/Models/PublishedContentBase.cs index c772f6ca85..d165209f0d 100644 --- a/src/Umbraco.Web/Models/PublishedContentBase.cs +++ b/src/Umbraco.Web/Models/PublishedContentBase.cs @@ -15,7 +15,12 @@ namespace Umbraco.Web.Models [DebuggerDisplay("Content Id: {Id}, Name: {Name}")] public abstract class PublishedContentBase : IPublishedContent { - private string _url; // fixme/task - cannot cache urls, they depends on the current request + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + + protected PublishedContentBase(IUmbracoContextAccessor umbracoContextAccessor) + { + _umbracoContextAccessor = umbracoContextAccessor; + } #region ContentType @@ -81,24 +86,21 @@ namespace Umbraco.Web.Models /// public virtual string GetUrl(string culture = null) // todo - consider .GetCulture("fr-FR").Url { + var umbracoContext = _umbracoContextAccessor.UmbracoContext; switch (ItemType) { case PublishedItemType.Content: - // todo - consider injecting an umbraco context accessor - if (UmbracoContext.Current == null) - throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.Current is null."); - if (UmbracoContext.Current.UrlProvider == null) - throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.Current.UrlProvider is null."); - return UmbracoContext.Current.UrlProvider.GetUrl(this, culture); + if (umbracoContext == null) + throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext is null."); + if (umbracoContext.UrlProvider == null) + throw new InvalidOperationException("Cannot compute Url for a content item when UmbracoContext.UrlProvider is null."); + return umbracoContext.UrlProvider.GetUrl(this, culture); case PublishedItemType.Media: - if (_url != null) return _url; // assume it will not depend on current uri/culture - var prop = GetProperty(Constants.Conventions.Media.File); if (prop?.GetValue() == null) { - _url = string.Empty; - return _url; + return string.Empty; } var propType = ContentType.GetPropertyType(Constants.Conventions.Media.File); @@ -110,7 +112,7 @@ namespace Umbraco.Web.Models switch (propType.EditorAlias) { case Constants.PropertyEditors.Aliases.UploadField: - _url = prop.GetValue().ToString(); + return prop.GetValue().ToString(); break; case Constants.PropertyEditors.Aliases.ImageCropper: //get the url from the json format @@ -118,14 +120,12 @@ namespace Umbraco.Web.Models var stronglyTyped = prop.GetValue() as ImageCropperValue; if (stronglyTyped != null) { - _url = stronglyTyped.Src; - break; + return stronglyTyped.Src; } - _url = prop.GetValue()?.ToString(); - break; + return prop.GetValue()?.ToString(); } - return _url; + return string.Empty; default: throw new NotSupportedException(); diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs index 647adaad91..d6e72b03d5 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentNode.cs @@ -34,10 +34,11 @@ namespace Umbraco.Web.PublishedCache.NuCache DateTime createDate, int creatorId, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, - IVariationContextAccessor variationContextAccessor) + IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor) : this(id, uid, level, path, sortOrder, parentContentId, createDate, creatorId) { - SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor); + SetContentTypeAndData(contentType, draftData, publishedData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor); } // 2-phases ctor, phase 1 @@ -59,7 +60,7 @@ namespace Umbraco.Web.PublishedCache.NuCache } // two-phase ctor, phase 2 - public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor) + public void SetContentTypeAndData(PublishedContentType contentType, ContentData draftData, ContentData publishedData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor) { ContentType = contentType; @@ -67,13 +68,13 @@ namespace Umbraco.Web.PublishedCache.NuCache throw new ArgumentException("Both draftData and publishedData cannot be null at the same time."); if (draftData != null) - Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + Draft = new PublishedContent(this, draftData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor).CreateModel(); if (publishedData != null) - Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + Published = new PublishedContent(this, publishedData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor).CreateModel(); } // clone parent - private ContentNode(ContentNode origin) + private ContentNode(ContentNode origin, IUmbracoContextAccessor umbracoContextAccessor) { // everything is the same, except for the child items // list which is a clone of the original list @@ -91,14 +92,14 @@ namespace Umbraco.Web.PublishedCache.NuCache var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft); var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published); - Draft = originDraft == null ? null : new PublishedContent(this, originDraft).CreateModel(); - Published = originPublished == null ? null : new PublishedContent(this, originPublished).CreateModel(); + Draft = originDraft == null ? null : new PublishedContent(this, originDraft, umbracoContextAccessor).CreateModel(); + Published = originPublished == null ? null : new PublishedContent(this, originPublished, umbracoContextAccessor).CreateModel(); ChildContentIds = new List(origin.ChildContentIds); // needs to be *another* list } // clone with new content type - public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor) + public ContentNode(ContentNode origin, PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor) { Id = origin.Id; Uid = origin.Uid; @@ -113,8 +114,8 @@ namespace Umbraco.Web.PublishedCache.NuCache var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft); var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published); - Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); - Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + Draft = originDraft == null ? null : new PublishedContent(this, originDraft._contentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor).CreateModel(); + Published = originPublished == null ? null : new PublishedContent(this, originPublished._contentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor).CreateModel(); ChildContentIds = origin.ChildContentIds; // can be the *same* list } @@ -137,9 +138,11 @@ namespace Umbraco.Web.PublishedCache.NuCache public IPublishedContent Draft; public IPublishedContent Published; - public ContentNode CloneParent(IPublishedSnapshotAccessor publishedSnapshotAccessor) + public ContentNode CloneParent( + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IUmbracoContextAccessor umbracoContextAccessor) { - return new ContentNode(this); + return new ContentNode(this, umbracoContextAccessor); } public ContentNodeKit ToKit() diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs index 5a47b99382..739a6141be 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentNodeKit.cs @@ -17,9 +17,14 @@ namespace Umbraco.Web.PublishedCache.NuCache public static ContentNodeKit Null { get; } = new ContentNodeKit { ContentTypeId = -1 }; - public void Build(PublishedContentType contentType, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, bool canBePublished) + public void Build( + PublishedContentType contentType, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, + bool canBePublished, + IUmbracoContextAccessor umbracoContextAccessor) { - Node.SetContentTypeAndData(contentType, DraftData, canBePublished ? PublishedData : null, publishedSnapshotAccessor, variationContextAccessor); + Node.SetContentTypeAndData(contentType, DraftData, canBePublished ? PublishedData : null, publishedSnapshotAccessor, variationContextAccessor,umbracoContextAccessor); } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs index 0cf2c231b5..aaf1ce29a3 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentStore.cs @@ -20,6 +20,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; private readonly IVariationContextAccessor _variationContextAccessor; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly ConcurrentDictionary> _contentNodes; private readonly ConcurrentDictionary> _contentRootNodes; private readonly ConcurrentDictionary> _contentTypesById; @@ -44,10 +45,16 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Ctor - public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, ILogger logger, BPlusTree localDb = null) + public ContentStore( + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor, + ILogger logger, + BPlusTree localDb = null) { _publishedSnapshotAccessor = publishedSnapshotAccessor; _variationContextAccessor = variationContextAccessor; + _umbracoContextAccessor = umbracoContextAccessor; _logger = logger; _localDb = localDb; @@ -279,7 +286,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (node == null) continue; var contentTypeId = node.ContentType.Id; if (index.TryGetValue(contentTypeId, out PublishedContentType contentType) == false) continue; - SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor)); + SetValueLocked(_contentNodes, node.Id, new ContentNode(node, contentType, _publishedSnapshotAccessor, _variationContextAccessor, _umbracoContextAccessor)); } } finally @@ -393,7 +400,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _contentNodes.TryGetValue(id, out LinkedNode link); if (link?.Value == null) continue; - var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor); + var node = new ContentNode(link.Value, contentType, _publishedSnapshotAccessor, _variationContextAccessor, _umbracoContextAccessor); SetValueLocked(_contentNodes, id, node); if (_localDb != null) RegisterChange(id, node.ToKit()); } @@ -419,7 +426,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var canBePublished = ParentPublishedLocked(kit); // and use - kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor, canBePublished); + kit.Build(link.Value, _publishedSnapshotAccessor, _variationContextAccessor, canBePublished, _umbracoContextAccessor); return true; } @@ -631,7 +638,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var link = GetParentLink(content); var parent = link.Value; if (link.Gen < _liveGen) - parent = parent.CloneParent(_publishedSnapshotAccessor); + parent = parent.CloneParent(_publishedSnapshotAccessor, _umbracoContextAccessor); parent.ChildContentIds.Remove(content.Id); if (link.Gen < _liveGen) SetValueLocked(_contentNodes, parent.Id, parent); @@ -670,7 +677,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var link = GetParentLink(content); var parent = link.Value; if (link.Gen < _liveGen) - parent = parent.CloneParent(_publishedSnapshotAccessor); + parent = parent.CloneParent(_publishedSnapshotAccessor, _umbracoContextAccessor); parent.ChildContentIds.Add(content.Id); if (link.Gen < _liveGen) SetValueLocked(_contentNodes, parent.Id, parent); diff --git a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs index ecf099f90b..f7ffe73109 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/MemberCache.cs @@ -17,18 +17,22 @@ namespace Umbraco.Web.PublishedCache.NuCache internal class MemberCache : IPublishedMemberCache, INavigableData { private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; + public readonly IVariationContextAccessor VariationContextAccessor; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IEntityXmlSerializer _entitySerializer; private readonly IAppCache _snapshotCache; private readonly IMemberService _memberService; private readonly PublishedContentTypeCache _contentTypeCache; private readonly bool _previewDefault; - public MemberCache(bool previewDefault, IAppCache snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IEntityXmlSerializer entitySerializer) + public MemberCache(bool previewDefault, IAppCache snapshotCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache, + IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, IUmbracoContextAccessor umbracoContextAccessor, IEntityXmlSerializer entitySerializer) { _snapshotCache = snapshotCache; _publishedSnapshotAccessor = publishedSnapshotAccessor; VariationContextAccessor = variationContextAccessor; + _umbracoContextAccessor = umbracoContextAccessor; _entitySerializer = entitySerializer; _memberService = memberService; _previewDefault = previewDefault; @@ -64,14 +68,14 @@ namespace Umbraco.Web.PublishedCache.NuCache var member = _memberService.GetById(memberId); return member == null ? null - : PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor); + : PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor); }); } private IPublishedContent /*IPublishedMember*/ GetById(IMember member, bool previewing) { return GetCacheItem(CacheKeys.MemberCacheMember("ById", _previewDefault, member.Id), () => - PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationContextAccessor)); + PublishedMember.Create(member, GetContentType(member.ContentTypeId), previewing, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor)); } public IPublishedContent /*IPublishedMember*/ GetByProviderKey(object key) @@ -106,7 +110,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public IPublishedContent /*IPublishedMember*/ GetByMember(IMember member) { - return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor); + return PublishedMember.Create(member, GetContentType(member.ContentTypeId), _previewDefault, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor); } public IEnumerable GetAtRoot(bool preview) @@ -114,7 +118,7 @@ namespace Umbraco.Web.PublishedCache.NuCache // because members are flat (not a tree) everything is at root // because we're loading everything... let's just not cache? var members = _memberService.GetAllMembers(); - return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationContextAccessor)); + return members.Select(m => PublishedMember.Create(m, GetContentType(m.ContentTypeId), preview, _publishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor)); } public XPathNavigator CreateNavigator() diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index d1e1d63630..5228c3f876 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -14,6 +14,7 @@ namespace Umbraco.Web.PublishedCache.NuCache internal class PublishedContent : PublishedContentBase { private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly ContentNode _contentNode; // ReSharper disable once InconsistentNaming internal readonly ContentData _contentData; // internal for ContentNode cloning @@ -22,11 +23,17 @@ namespace Umbraco.Web.PublishedCache.NuCache #region Constructors - public PublishedContent(ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor) + public PublishedContent( + ContentNode contentNode, + ContentData contentData, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor) { _contentNode = contentNode; _contentData = contentData; _publishedSnapshotAccessor = publishedSnapshotAccessor; + _umbracoContextAccessor = umbracoContextAccessor; VariationContextAccessor = variationContextAccessor; _urlSegment = _contentData.Name.ToUrlSegment(); @@ -66,7 +73,10 @@ namespace Umbraco.Web.PublishedCache.NuCache } // (see ContentNode.CloneParent) - public PublishedContent(ContentNode contentNode, PublishedContent origin) + public PublishedContent( + ContentNode contentNode, + PublishedContent origin, + IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor) { _contentNode = contentNode; _publishedSnapshotAccessor = origin._publishedSnapshotAccessor; @@ -83,7 +93,9 @@ namespace Umbraco.Web.PublishedCache.NuCache } // clone for previewing as draft a published content that is published and has no draft - private PublishedContent(PublishedContent origin) + private PublishedContent( + PublishedContent origin, + IUmbracoContextAccessor umbracoContextAccessor) :base(umbracoContextAccessor) { _publishedSnapshotAccessor = origin._publishedSnapshotAccessor; VariationContextAccessor = origin.VariationContextAccessor; @@ -433,8 +445,8 @@ namespace Umbraco.Web.PublishedCache.NuCache return this; var cache = GetAppropriateCache(); - if (cache == null) return new PublishedContent(this).CreateModel(); - return (IPublishedContent)cache.Get(AsPreviewingCacheKey, () => new PublishedContent(this).CreateModel()); + if (cache == null) return new PublishedContent(this, _umbracoContextAccessor).CreateModel(); + return (IPublishedContent)cache.Get(AsPreviewingCacheKey, () => new PublishedContent(this, _umbracoContextAccessor).CreateModel()); } // used by Navigable.Source,... diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs index 47c8d738f1..db50fc3fe6 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedMember.cs @@ -15,13 +15,26 @@ namespace Umbraco.Web.PublishedCache.NuCache { private readonly IMember _member; - private PublishedMember(IMember member, ContentNode contentNode, ContentData contentData, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor) - : base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor) + private PublishedMember( + IMember member, + ContentNode contentNode, + ContentData contentData, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor + ) + : base(contentNode, contentData, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor) { _member = member; } - public static IPublishedContent Create(IMember member, PublishedContentType contentType, bool previewing, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor) + public static IPublishedContent Create( + IMember member, + PublishedContentType contentType, + bool previewing, + IPublishedSnapshotAccessor publishedSnapshotAccessor, + IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor) { var d = new ContentData { @@ -37,7 +50,7 @@ namespace Umbraco.Web.PublishedCache.NuCache member.Level, member.Path, member.SortOrder, member.ParentId, member.CreateDate, member.CreatorId); - return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor).CreateModel(); + return new PublishedMember(member, n, d, publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor).CreateModel(); } private static Dictionary GetPropertyValues(PublishedContentType contentType, IMember member) diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 8675aefd1a..34c495ece9 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -32,6 +32,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { private readonly ServiceContext _serviceContext; private readonly IPublishedContentTypeFactory _publishedContentTypeFactory; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly IScopeProvider _scopeProvider; private readonly IDataSource _dataSource; private readonly ILogger _logger; @@ -80,7 +81,7 @@ namespace Umbraco.Web.PublishedCache.NuCache public PublishedSnapshotService(Options options, IMainDom mainDom, IRuntimeState runtime, ServiceContext serviceContext, IPublishedContentTypeFactory publishedContentTypeFactory, IdkMap idkMap, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, - ILogger logger, IScopeProvider scopeProvider, + IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IScopeProvider scopeProvider, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, IDataSource dataSource, IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, @@ -92,6 +93,7 @@ namespace Umbraco.Web.PublishedCache.NuCache _serviceContext = serviceContext; _publishedContentTypeFactory = publishedContentTypeFactory; + _umbracoContextAccessor = umbracoContextAccessor; _dataSource = dataSource; _logger = logger; _scopeProvider = scopeProvider; @@ -148,13 +150,13 @@ namespace Umbraco.Web.PublishedCache.NuCache // stores are created with a db so they can write to it, but they do not read from it, // stores need to be populated, happens in OnResolutionFrozen which uses _localDbExists to // figure out whether it can read the dbs or it should populate them from sql - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localContentDb); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger, _localMediaDb); + _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger, _localContentDb); + _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger, _localMediaDb); } else { - _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger); - _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, logger); + _contentStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger); + _mediaStore = new ContentStore(publishedSnapshotAccessor, variationContextAccessor, _umbracoContextAccessor, logger); } _domainStore = new SnapDictionary(); @@ -1015,7 +1017,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainHelper, _globalSettings, _serviceContext.LocalizationService), MediaCache = new MediaCache(previewDefault, mediaSnap, snapshotCache, elementsCache), - MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _entitySerializer), + MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor, _entitySerializer), DomainCache = domainCache, SnapshotCache = snapshotCache, ElementsCache = elementsCache diff --git a/src/Umbraco.Web/PublishedCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/PublishedMember.cs index ef95b2846c..56a0110f45 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedMember.cs @@ -19,7 +19,11 @@ namespace Umbraco.Web.PublishedCache private readonly IPublishedProperty[] _properties; private readonly PublishedContentType _publishedMemberType; - public PublishedMember(IMember member, PublishedContentType publishedMemberType) + public PublishedMember( + IMember member, + PublishedContentType publishedMemberType, + IUmbracoContextAccessor umbracoContextAccessor) + :base(umbracoContextAccessor) { _member = member ?? throw new ArgumentNullException(nameof(member)); _membershipUser = member; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs index 83bd84dab6..24b3ed6ab5 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/DictionaryPublishedContent.cs @@ -38,7 +38,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IAppCache appCache, PublishedContentTypeCache contentTypeCache, XPathNavigator nav, - bool fromExamine) + bool fromExamine, + IUmbracoContextAccessor umbracoContextAccessor) + :base(umbracoContextAccessor) { if (valueDictionary == null) throw new ArgumentNullException(nameof(valueDictionary)); if (getParent == null) throw new ArgumentNullException(nameof(getParent)); diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index d8c7c41ea1..6fd9f1da2b 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -17,6 +17,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { private readonly IAppCache _appCache; private readonly IGlobalSettings _globalSettings; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly RoutesCache _routesCache; private readonly IDomainCache _domainCache; private readonly DomainHelper _domainHelper; @@ -33,6 +34,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IAppCache appCache, // an IAppCache that should be at request-level IGlobalSettings globalSettings, ISiteDomainHelper siteDomainHelper, + IUmbracoContextAccessor umbracoContextAccessor, PublishedContentTypeCache contentTypeCache, // a PublishedContentType cache RoutesCache routesCache, // a RoutesCache string previewToken) // a preview token string (or null if not previewing) @@ -40,6 +42,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache { _appCache = appCache; _globalSettings = globalSettings; + _umbracoContextAccessor = umbracoContextAccessor; _routesCache = routesCache; // may be null for unit-testing _contentTypeCache = contentTypeCache; _domainCache = domainCache; @@ -315,13 +318,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private IPublishedContent ConvertToDocument(XmlNode xmlNode, bool isPreviewing) { - return xmlNode == null ? null : XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache); + return xmlNode == null ? null : XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache,_umbracoContextAccessor); } private IEnumerable ConvertToDocuments(XmlNodeList xmlNodes, bool isPreviewing) { return xmlNodes.Cast() - .Select(xmlNode => XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache)); + .Select(xmlNode => XmlPublishedContent.Get(xmlNode, isPreviewing, _appCache, _contentTypeCache, _umbracoContextAccessor)); } #endregion diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index dadf40a33b..85a9725f17 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -41,11 +41,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly XmlStore _xmlStore; private readonly PublishedContentTypeCache _contentTypeCache; private readonly IEntityXmlSerializer _entitySerializer; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; // must be specified by the ctor private readonly IAppCache _appCache; - public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer) + public PublishedMediaCache(XmlStore xmlStore, IMediaService mediaService, IUserService userService, + IAppCache appCache, PublishedContentTypeCache contentTypeCache, IEntityXmlSerializer entitySerializer, + IUmbracoContextAccessor umbracoContextAccessor) : base(false) { _mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService)); @@ -55,6 +58,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _xmlStore = xmlStore; _contentTypeCache = contentTypeCache; _entitySerializer = entitySerializer; + _umbracoContextAccessor = umbracoContextAccessor; } /// @@ -666,7 +670,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _appCache, _contentTypeCache, cacheValues.XPath, // though, outside of tests, that should be null - cacheValues.FromExamine + cacheValues.FromExamine, + _umbracoContextAccessor ); return content.CreateModel(); } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs index 816eb3c545..db6d85fb2d 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMemberCache.cs @@ -16,13 +16,16 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly IAppCache _requestCache; private readonly XmlStore _xmlStore; private readonly PublishedContentTypeCache _contentTypeCache; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; - public PublishedMemberCache(XmlStore xmlStore, IAppCache requestCache, IMemberService memberService, PublishedContentTypeCache contentTypeCache) + public PublishedMemberCache(XmlStore xmlStore, IAppCache requestCache, IMemberService memberService, + PublishedContentTypeCache contentTypeCache, IUmbracoContextAccessor umbracoContextAccessor) { _requestCache = requestCache; _memberService = memberService; _xmlStore = xmlStore; _contentTypeCache = contentTypeCache; + _umbracoContextAccessor = umbracoContextAccessor; } public IPublishedContent GetByProviderKey(object key) @@ -39,7 +42,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var result = _memberService.GetByProviderKey(key); if (result == null) return null; var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId); - return new PublishedMember(result, type).CreateModel(); + return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel(); }); } @@ -57,7 +60,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var result = _memberService.GetById(memberId); if (result == null) return null; var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId); - return new PublishedMember(result, type).CreateModel(); + return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel(); }); } @@ -75,7 +78,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var result = _memberService.GetByUsername(username); if (result == null) return null; var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId); - return new PublishedMember(result, type).CreateModel(); + return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel(); }); } @@ -93,14 +96,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var result = _memberService.GetByEmail(email); if (result == null) return null; var type = _contentTypeCache.Get(PublishedItemType.Member, result.ContentTypeId); - return new PublishedMember(result, type).CreateModel(); + return new PublishedMember(result, type, _umbracoContextAccessor).CreateModel(); }); } public IPublishedContent GetByMember(IMember member) { var type = _contentTypeCache.Get(PublishedItemType.Member, member.ContentTypeId); - return new PublishedMember(member, type).CreateModel(); + return new PublishedMember(member, type, _umbracoContextAccessor).CreateModel(); } public XPathNavigator CreateNavigator() diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs index c4ce05c9a9..d96bfd8a0a 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedSnapshotService.cs @@ -35,6 +35,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly ISiteDomainHelper _siteDomainHelper; private readonly IEntityXmlSerializer _entitySerializer; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; #region Constructors @@ -44,6 +45,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IScopeProvider scopeProvider, IAppCache requestCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, ILogger logger, @@ -52,12 +54,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IEntityXmlSerializer entitySerializer, MainDom mainDom, bool testing = false, bool enableRepositoryEvents = true) - : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, - publishedSnapshotAccessor, variationContextAccessor, + : this(serviceContext, publishedContentTypeFactory, scopeProvider, requestCache, + publishedSnapshotAccessor, variationContextAccessor, umbracoContextAccessor, documentRepository, mediaRepository, memberRepository, defaultCultureAccessor, logger, globalSettings, siteDomainHelper, entitySerializer, null, mainDom, testing, enableRepositoryEvents) - { } + { + _umbracoContextAccessor = umbracoContextAccessor; + } // used in some tests internal PublishedSnapshotService(ServiceContext serviceContext, @@ -65,6 +69,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache IScopeProvider scopeProvider, IAppCache requestCache, IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, + IUmbracoContextAccessor umbracoContextAccessor, IDocumentRepository documentRepository, IMediaRepository mediaRepository, IMemberRepository memberRepository, IDefaultCultureAccessor defaultCultureAccessor, ILogger logger, @@ -92,6 +97,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _defaultCultureAccessor = defaultCultureAccessor; _requestCache = requestCache; + _umbracoContextAccessor = umbracoContextAccessor; _globalSettings = globalSettings; _siteDomainHelper = siteDomainHelper; _entitySerializer = entitySerializer; @@ -138,9 +144,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var domainCache = new DomainCache(_domainService, _defaultCultureAccessor); return new PublishedSnapshot( - new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _siteDomainHelper, _contentTypeCache, _routesCache, previewToken), - new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache, _entitySerializer), - new PublishedMemberCache(_xmlStore, _requestCache, _memberService, _contentTypeCache), + new PublishedContentCache(_xmlStore, domainCache, _requestCache, _globalSettings, _siteDomainHelper,_umbracoContextAccessor, _contentTypeCache, _routesCache, previewToken), + new PublishedMediaCache(_xmlStore, _mediaService, _userService, _requestCache, _contentTypeCache, _entitySerializer, _umbracoContextAccessor), + new PublishedMemberCache(_xmlStore, _requestCache, _memberService, _contentTypeCache, _umbracoContextAccessor), domainCache); } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index 2b3bc39452..00919e6a87 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -20,21 +20,29 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache [XmlType(Namespace = "http://umbraco.org/webservices/")] internal class XmlPublishedContent : PublishedContentBase { - private XmlPublishedContent(XmlNode xmlNode, bool isPreviewing, IAppCache appCache, PublishedContentTypeCache contentTypeCache) + private XmlPublishedContent( + XmlNode xmlNode, + bool isPreviewing, + IAppCache appCache, + PublishedContentTypeCache contentTypeCache, + IUmbracoContextAccessor umbracoContextAccessor) + :base(umbracoContextAccessor) { _xmlNode = xmlNode; _isPreviewing = isPreviewing; _appCache = appCache; _contentTypeCache = contentTypeCache; + _umbracoContextAccessor = umbracoContextAccessor; } private readonly XmlNode _xmlNode; private readonly bool _isPreviewing; private readonly IAppCache _appCache; // at snapshot/request level (see PublishedContentCache) private readonly PublishedContentTypeCache _contentTypeCache; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; - private readonly object _initializeLock = new object(); + private readonly object _initializeLock = new object(); private bool _nodeInitialized; private bool _parentInitialized; @@ -252,7 +260,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache if (parent == null) return; if (parent.Attributes?.GetNamedItem("isDoc") != null) - _parent = Get(parent, _isPreviewing, _appCache, _contentTypeCache); + _parent = Get(parent, _isPreviewing, _appCache, _contentTypeCache, _umbracoContextAccessor); _parentInitialized = true; } @@ -409,7 +417,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var iterator = nav.Select(expr); _children = iterator.Cast() - .Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _appCache, _contentTypeCache)) + .Select(n => Get(((IHasXmlNode) n).GetNode(), _isPreviewing, _appCache, _contentTypeCache, _umbracoContextAccessor)) .OrderBy(x => x.SortOrder) .ToList(); @@ -423,11 +431,13 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache /// A value indicating whether we are previewing or not. /// A cache. /// A content type cache. + /// A umbraco context accessor /// The IPublishedContent corresponding to the Xml cache node. /// Maintains a per-request cache of IPublishedContent items in order to make /// sure that we create only one instance of each for the duration of a request. The /// returned IPublishedContent is a model, if models are enabled. - public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache appCache, PublishedContentTypeCache contentTypeCache) + public static IPublishedContent Get(XmlNode node, bool isPreviewing, IAppCache appCache, + PublishedContentTypeCache contentTypeCache, IUmbracoContextAccessor umbracoContextAccessor) { // only 1 per request @@ -435,7 +445,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache var id = attrs?.GetNamedItem("id").Value; if (id.IsNullOrWhiteSpace()) throw new InvalidOperationException("Node has no ID attribute."); var key = CacheKeyPrefix + id; // dont bother with preview, wont change during request in Xml cache - return (IPublishedContent) appCache.Get(key, () => (new XmlPublishedContent(node, isPreviewing, appCache, contentTypeCache)).CreateModel()); + return (IPublishedContent) appCache.Get(key, () => (new XmlPublishedContent(node, isPreviewing, appCache, contentTypeCache, umbracoContextAccessor)).CreateModel()); } public static void ClearRequest() From d16aa91a5e364f986ba48a1394e145f0d0721cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Wed, 23 Jan 2019 15:13:42 +0100 Subject: [PATCH 018/213] remove extra border from MCE-edit-area --- src/Umbraco.Web.UI.Client/src/less/rte.less | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/rte.less b/src/Umbraco.Web.UI.Client/src/less/rte.less index 4d3a680523..9aae9840d1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/rte.less +++ b/src/Umbraco.Web.UI.Client/src/less/rte.less @@ -42,7 +42,6 @@ } .umb-rte .mce-tinymce .mce-edit-area { - border: 1px solid @gray-8 !important; border-radius: 0px !important; } From f8b9fb039f1538156d6adf041c4fe2fad03fe536 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Wed, 23 Jan 2019 15:35:20 +0100 Subject: [PATCH 019/213] Handle culture not set in HasCulture. --- src/Umbraco.Web/PublishedContentExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 530c9bd9b4..7b0b7e44a3 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -228,7 +228,7 @@ namespace Umbraco.Web /// /// Culture is case-insensitive. public static bool HasCulture(this IPublishedContent content, string culture) - => content.Cultures.ContainsKey(culture); + => content.Cultures.ContainsKey(culture ?? string.Empty); /// /// Filters a sequence of to return invariant items, and items that are published for the specified culture. From 69a3c85bbc07ed4697dd484b37433b8fd6940822 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 14:37:33 +0000 Subject: [PATCH 020/213] Refactor of dashboards * Remove dashboards from Configs().Dashboards * Remove dashboard.config XML file & associated code reading from XML * Load Dashboards from TypeLoader into a CollectionBuilder * Load merge/concat C# Dashboard Types with package.manifest * Add buildercolletion to an extension method on Composition --- src/Umbraco.Core/ConfigsExtensions.cs | 5 - .../Configuration/Dashboard/AccessElement.cs | 30 --- .../Configuration/Dashboard/AreaCollection.cs | 32 --- .../Configuration/Dashboard/AreaElement.cs | 12 -- .../Configuration/Dashboard/AreasElement.cs | 15 -- .../Dashboard/ControlCollection.cs | 37 ---- .../Configuration/Dashboard/ControlElement.cs | 44 ---- .../Dashboard/DashboardSection.cs | 24 --- .../Configuration/Dashboard/IAccess.cs | 9 - .../Configuration/Dashboard/IArea.cs | 7 - .../Dashboard/IDashboardControl.cs | 11 - .../Dashboard/IDashboardSection.cs | 9 - .../Configuration/Dashboard/IDashboardTab.cs | 13 -- .../Configuration/Dashboard/ISection.cs | 15 -- .../Dashboard/SectionCollection.cs | 37 ---- .../Configuration/Dashboard/SectionElement.cs | 50 ----- .../Configuration/Dashboard/TabCollection.cs | 37 ---- .../Configuration/Dashboard/TabElement.cs | 38 ---- .../Dashboard => Dashboards}/AccessRule.cs | 2 +- .../AccessRuleType.cs | 2 +- .../Dashboard => Dashboards}/IAccessRule.cs | 2 +- .../Dashboards/IDashboardSection.cs | 30 +++ .../Manifest/DashboardAccessRuleConverter.cs | 2 +- .../Manifest/ManifestDashboardDefinition.cs | 5 +- src/Umbraco.Core/Umbraco.Core.csproj | 24 +-- .../DashboardSettingsTests.cs | 189 +++++++++--------- .../Manifest/ManifestParserTests.cs | 2 +- src/Umbraco.Web.UI.Client/package-lock.json | 96 ++++----- .../src/views/common/dashboard.html | 13 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 + src/Umbraco.Web.UI/config/Dashboard.config | 1 + src/Umbraco.Web/CompositionExtensions.cs | 8 + .../Dashboards/ContentDashboard.cs | 38 ++++ .../Dashboards/DashboardCollection.cs | 13 ++ .../Dashboards/DashboardCollectionBuilder.cs | 24 +++ .../Dashboards/ExamineDashboard.cs | 29 +++ src/Umbraco.Web/Dashboards/FormsDashboard.cs | 27 +++ .../Dashboards/HealthCheckDashboard.cs | 29 +++ src/Umbraco.Web/Dashboards/MediaDashboard.cs | 27 +++ .../Dashboards/MembersDashboard.cs | 27 +++ .../Dashboards/ModelsBuilderDashboard.cs | 29 +++ .../Dashboards/PublishedStatusDashboard.cs | 29 +++ .../Dashboards/RedirectUrlDashboard.cs | 27 +++ .../Dashboards/SettingsDashboards.cs | 27 +++ .../Editors/DashboardController.cs | 16 +- src/Umbraco.Web/Editors/Dashboards.cs | 160 --------------- .../Editors/EditorModelEventManager.cs | 9 +- src/Umbraco.Web/Editors/SectionController.cs | 8 +- .../Models/ContentEditing/DashboardControl.cs | 19 -- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 28 ++- .../DashboardService.cs} | 109 ++++++---- src/Umbraco.Web/Services/IDashboardService.cs | 27 +++ src/Umbraco.Web/Umbraco.Web.csproj | 17 +- 53 files changed, 678 insertions(+), 844 deletions(-) delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/AccessElement.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/AreaCollection.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/AreaElement.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/AreasElement.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/ControlCollection.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/ControlElement.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/DashboardSection.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/IAccess.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/IArea.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/IDashboardControl.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/IDashboardSection.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/IDashboardTab.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/ISection.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/SectionCollection.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/SectionElement.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/TabCollection.cs delete mode 100644 src/Umbraco.Core/Configuration/Dashboard/TabElement.cs rename src/Umbraco.Core/{Configuration/Dashboard => Dashboards}/AccessRule.cs (85%) rename src/Umbraco.Core/{Configuration/Dashboard => Dashboards}/AccessRuleType.cs (93%) rename src/Umbraco.Core/{Configuration/Dashboard => Dashboards}/IAccessRule.cs (88%) create mode 100644 src/Umbraco.Core/Dashboards/IDashboardSection.cs create mode 100644 src/Umbraco.Web/Dashboards/ContentDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/DashboardCollection.cs create mode 100644 src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs create mode 100644 src/Umbraco.Web/Dashboards/ExamineDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/FormsDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/MediaDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/MembersDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs create mode 100644 src/Umbraco.Web/Dashboards/SettingsDashboards.cs delete mode 100644 src/Umbraco.Web/Editors/Dashboards.cs delete mode 100644 src/Umbraco.Web/Models/ContentEditing/DashboardControl.cs rename src/Umbraco.Web/{Editors/DashboardSecurity.cs => Services/DashboardService.cs} (62%) create mode 100644 src/Umbraco.Web/Services/IDashboardService.cs diff --git a/src/Umbraco.Core/ConfigsExtensions.cs b/src/Umbraco.Core/ConfigsExtensions.cs index 0fcea5f430..6fdf7ea3b9 100644 --- a/src/Umbraco.Core/ConfigsExtensions.cs +++ b/src/Umbraco.Core/ConfigsExtensions.cs @@ -2,7 +2,6 @@ using Umbraco.Core.Cache; using Umbraco.Core.Composing; using Umbraco.Core.Configuration; -using Umbraco.Core.Configuration.Dashboard; using Umbraco.Core.Configuration.Grid; using Umbraco.Core.Configuration.HealthChecks; using Umbraco.Core.Configuration.UmbracoSettings; @@ -22,9 +21,6 @@ namespace Umbraco.Core public static IUmbracoSettingsSection Settings(this Configs configs) => configs.GetConfig(); - public static IDashboardSection Dashboards(this Configs configs) - => configs.GetConfig(); - public static IHealthChecks HealthChecks(this Configs configs) => configs.GetConfig(); @@ -40,7 +36,6 @@ namespace Umbraco.Core configs.Add(() => new GlobalSettings()); configs.Add("umbracoConfiguration/settings"); - configs.Add("umbracoConfiguration/dashBoard"); configs.Add("umbracoConfiguration/HealthChecks"); configs.Add(() => new CoreDebug()); diff --git a/src/Umbraco.Core/Configuration/Dashboard/AccessElement.cs b/src/Umbraco.Core/Configuration/Dashboard/AccessElement.cs deleted file mode 100644 index 01538c8e0b..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/AccessElement.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Xml.Linq; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class AccessElement : RawXmlConfigurationElement, IAccess - { - public AccessElement() - { } - - public AccessElement(XElement rawXml) - : base(rawXml) - { } - - public IEnumerable Rules - { - get - { - var result = new List(); - if (RawXml == null) return result; - - result.AddRange(RawXml.Elements("deny").Select(x => new AccessRule {Type = AccessRuleType.Deny, Value = x.Value })); - result.AddRange(RawXml.Elements("grant").Select(x => new AccessRule { Type = AccessRuleType.Grant, Value = x.Value })); - result.AddRange(RawXml.Elements("grantBySection").Select(x => new AccessRule { Type = AccessRuleType.GrantBySection, Value = x.Value })); - return result; - } - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/AreaCollection.cs b/src/Umbraco.Core/Configuration/Dashboard/AreaCollection.cs deleted file mode 100644 index 31cc3eaec8..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/AreaCollection.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class AreaCollection : ConfigurationElementCollection, IEnumerable - { - protected override ConfigurationElement CreateNewElement() - { - return new AreaElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((AreaElement) element).Value; - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as IArea; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/AreaElement.cs b/src/Umbraco.Core/Configuration/Dashboard/AreaElement.cs deleted file mode 100644 index 20393f89d8..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/AreaElement.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class AreaElement : InnerTextConfigurationElement, IArea - { - string IArea.AreaName - { - get { return Value; } - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/AreasElement.cs b/src/Umbraco.Core/Configuration/Dashboard/AreasElement.cs deleted file mode 100644 index 92e51c9b73..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/AreasElement.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class AreasElement : ConfigurationElement - { - [ConfigurationCollection(typeof(SectionCollection), AddItemName = "area")] - [ConfigurationProperty("", IsDefaultCollection = true)] - public AreaCollection AreaCollection - { - get { return (AreaCollection)base[""]; } - set { base[""] = value; } - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/ControlCollection.cs b/src/Umbraco.Core/Configuration/Dashboard/ControlCollection.cs deleted file mode 100644 index b8aa40da7f..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/ControlCollection.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class ControlCollection : ConfigurationElementCollection, IEnumerable - { - internal void Add(ControlElement c) - { - BaseAdd(c); - } - - protected override ConfigurationElement CreateNewElement() - { - return new ControlElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((ControlElement)element).ControlPath; - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as IDashboardControl; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/ControlElement.cs b/src/Umbraco.Core/Configuration/Dashboard/ControlElement.cs deleted file mode 100644 index 20dac7460e..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/ControlElement.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Configuration; -using System.Linq; -using System.Xml.Linq; - -namespace Umbraco.Core.Configuration.Dashboard -{ - - internal class ControlElement : RawXmlConfigurationElement, IDashboardControl - { - public string PanelCaption - { - get - { - var panelCaption = RawXml.Attribute("panelCaption"); - return panelCaption == null ? "" : panelCaption.Value; - } - } - - public AccessElement Access - { - get - { - var access = RawXml.Element("access"); - return access == null ? new AccessElement() : new AccessElement(access); - } - } - - public string ControlPath - { - get - { - //we need to return the first (and only) text element of the children (wtf... who designed this configuration ! :P ) - var txt = RawXml.Nodes().OfType().FirstOrDefault(); - if (txt == null) - { - throw new ConfigurationErrorsException("The control element must contain a text node indicating the control path"); - } - return txt.Value.Trim(); - } - } - - IAccess IDashboardControl.AccessRights => Access; - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/DashboardSection.cs b/src/Umbraco.Core/Configuration/Dashboard/DashboardSection.cs deleted file mode 100644 index 12bf0522e0..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/DashboardSection.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Text; -using System.Threading.Tasks; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class DashboardSection : ConfigurationSection, IDashboardSection - { - [ConfigurationCollection(typeof(SectionCollection), AddItemName = "section")] - [ConfigurationProperty("", IsDefaultCollection = true)] - public SectionCollection SectionCollection - { - get { return (SectionCollection)base[""]; } - set { base[""] = value; } - } - - IEnumerable IDashboardSection.Sections - { - get { return SectionCollection; } - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/IAccess.cs b/src/Umbraco.Core/Configuration/Dashboard/IAccess.cs deleted file mode 100644 index 8ac1b18cca..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/IAccess.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.Dashboard -{ - public interface IAccess - { - IEnumerable Rules { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/IArea.cs b/src/Umbraco.Core/Configuration/Dashboard/IArea.cs deleted file mode 100644 index 25401db408..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/IArea.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Umbraco.Core.Configuration.Dashboard -{ - public interface IArea - { - string AreaName { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/IDashboardControl.cs b/src/Umbraco.Core/Configuration/Dashboard/IDashboardControl.cs deleted file mode 100644 index cdf05af1ec..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/IDashboardControl.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Umbraco.Core.Configuration.Dashboard -{ - public interface IDashboardControl - { - string PanelCaption { get; } - - string ControlPath { get; } - - IAccess AccessRights { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/IDashboardSection.cs b/src/Umbraco.Core/Configuration/Dashboard/IDashboardSection.cs deleted file mode 100644 index 32dfc6653d..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/IDashboardSection.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.Dashboard -{ - public interface IDashboardSection - { - IEnumerable Sections { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/IDashboardTab.cs b/src/Umbraco.Core/Configuration/Dashboard/IDashboardTab.cs deleted file mode 100644 index 914b226265..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/IDashboardTab.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.Dashboard -{ - public interface IDashboardTab - { - string Caption { get; } - - IEnumerable Controls { get; } - - IAccess AccessRights { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/ISection.cs b/src/Umbraco.Core/Configuration/Dashboard/ISection.cs deleted file mode 100644 index 1005c0750d..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/ISection.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Collections.Generic; - -namespace Umbraco.Core.Configuration.Dashboard -{ - public interface ISection - { - string Alias { get; } - - IEnumerable Areas { get; } - - IEnumerable Tabs { get; } - - IAccess AccessRights { get; } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/SectionCollection.cs b/src/Umbraco.Core/Configuration/Dashboard/SectionCollection.cs deleted file mode 100644 index 5717bd28c3..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/SectionCollection.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class SectionCollection : ConfigurationElementCollection, IEnumerable - { - internal void Add(SectionElement c) - { - BaseAdd(c); - } - - protected override ConfigurationElement CreateNewElement() - { - return new SectionElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((SectionElement)element).Alias; - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as ISection; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/SectionElement.cs b/src/Umbraco.Core/Configuration/Dashboard/SectionElement.cs deleted file mode 100644 index 09049c13db..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/SectionElement.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; -using System.Linq; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class SectionElement : ConfigurationElement, ISection - { - [ConfigurationProperty("alias", IsRequired = true)] - public string Alias - { - get { return (string) this["alias"]; } - } - - [ConfigurationProperty("areas", IsRequired = true)] - public AreasElement Areas - { - get { return (AreasElement)this["areas"]; } - } - - [ConfigurationProperty("access")] - public AccessElement Access - { - get { return (AccessElement)this["access"]; } - } - - [ConfigurationCollection(typeof(SectionCollection), AddItemName = "tab")] - [ConfigurationProperty("", IsDefaultCollection = true)] - public TabCollection TabCollection - { - get { return (TabCollection)base[""]; } - set { base[""] = value; } - } - - IEnumerable ISection.Tabs - { - get { return TabCollection; } - } - - IEnumerable ISection.Areas - { - get { return Areas.AreaCollection.Cast().Select(x => x.Value); } - } - - IAccess ISection.AccessRights - { - get { return Access; } - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/TabCollection.cs b/src/Umbraco.Core/Configuration/Dashboard/TabCollection.cs deleted file mode 100644 index 1b77ffd3fb..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/TabCollection.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class TabCollection : ConfigurationElementCollection, IEnumerable - { - internal void Add(TabElement c) - { - BaseAdd(c); - } - - protected override ConfigurationElement CreateNewElement() - { - return new TabElement(); - } - - protected override object GetElementKey(ConfigurationElement element) - { - return ((TabElement)element).Caption; - } - - IEnumerator IEnumerable.GetEnumerator() - { - for (var i = 0; i < Count; i++) - { - yield return BaseGet(i) as IDashboardTab; - } - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/TabElement.cs b/src/Umbraco.Core/Configuration/Dashboard/TabElement.cs deleted file mode 100644 index b92394596e..0000000000 --- a/src/Umbraco.Core/Configuration/Dashboard/TabElement.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using System.Configuration; - -namespace Umbraco.Core.Configuration.Dashboard -{ - internal class TabElement : ConfigurationElement, IDashboardTab - { - [ConfigurationProperty("caption", IsRequired = true)] - public string Caption - { - get { return (string)this["caption"]; } - } - - [ConfigurationProperty("access")] - public AccessElement Access - { - get { return (AccessElement)this["access"]; } - } - - [ConfigurationCollection(typeof(ControlCollection), AddItemName = "control")] - [ConfigurationProperty("", IsDefaultCollection = true)] - public ControlCollection ControlCollection - { - get { return (ControlCollection)base[""]; } - set { base[""] = value; } - } - - IEnumerable IDashboardTab.Controls - { - get { return ControlCollection; } - } - - IAccess IDashboardTab.AccessRights - { - get { return Access; } - } - } -} diff --git a/src/Umbraco.Core/Configuration/Dashboard/AccessRule.cs b/src/Umbraco.Core/Dashboards/AccessRule.cs similarity index 85% rename from src/Umbraco.Core/Configuration/Dashboard/AccessRule.cs rename to src/Umbraco.Core/Dashboards/AccessRule.cs index fe6840ff64..70f9da8fa9 100644 --- a/src/Umbraco.Core/Configuration/Dashboard/AccessRule.cs +++ b/src/Umbraco.Core/Dashboards/AccessRule.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core.Configuration.Dashboard +namespace Umbraco.Core.Dashboards { /// /// Implements . diff --git a/src/Umbraco.Core/Configuration/Dashboard/AccessRuleType.cs b/src/Umbraco.Core/Dashboards/AccessRuleType.cs similarity index 93% rename from src/Umbraco.Core/Configuration/Dashboard/AccessRuleType.cs rename to src/Umbraco.Core/Dashboards/AccessRuleType.cs index cb9ce983fe..efed361f6c 100644 --- a/src/Umbraco.Core/Configuration/Dashboard/AccessRuleType.cs +++ b/src/Umbraco.Core/Dashboards/AccessRuleType.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core.Configuration.Dashboard +namespace Umbraco.Core.Dashboards { /// /// Defines dashboard access rules type. diff --git a/src/Umbraco.Core/Configuration/Dashboard/IAccessRule.cs b/src/Umbraco.Core/Dashboards/IAccessRule.cs similarity index 88% rename from src/Umbraco.Core/Configuration/Dashboard/IAccessRule.cs rename to src/Umbraco.Core/Dashboards/IAccessRule.cs index 8b51b1b73a..f44a846248 100644 --- a/src/Umbraco.Core/Configuration/Dashboard/IAccessRule.cs +++ b/src/Umbraco.Core/Dashboards/IAccessRule.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Core.Configuration.Dashboard +namespace Umbraco.Core.Dashboards { /// /// Represents an access rule. diff --git a/src/Umbraco.Core/Dashboards/IDashboardSection.cs b/src/Umbraco.Core/Dashboards/IDashboardSection.cs new file mode 100644 index 0000000000..90d351bcd2 --- /dev/null +++ b/src/Umbraco.Core/Dashboards/IDashboardSection.cs @@ -0,0 +1,30 @@ +namespace Umbraco.Core.Dashboards +{ + public interface IDashboardSection + { + /// + /// Display name of the dashboard tab + /// + string Name { get; } + + /// + /// Alias to refer to this dashboard via code + /// + string Alias { get; } + + /// + /// A collection of sections/application aliases that this dashboard will appear on + /// + string[] Sections { get; } + + /// + /// The HTML view to load for the dashboard + /// + string View { get; } + + /// + /// Dashboards can be shown/hidden based on access rights + /// + IAccessRule[] AccessRules { get; } + } +} diff --git a/src/Umbraco.Core/Manifest/DashboardAccessRuleConverter.cs b/src/Umbraco.Core/Manifest/DashboardAccessRuleConverter.cs index c627728a32..67c5a5824e 100644 --- a/src/Umbraco.Core/Manifest/DashboardAccessRuleConverter.cs +++ b/src/Umbraco.Core/Manifest/DashboardAccessRuleConverter.cs @@ -1,7 +1,7 @@ using System; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -using Umbraco.Core.Configuration.Dashboard; +using Umbraco.Core.Dashboards; using Umbraco.Core.Serialization; namespace Umbraco.Core.Manifest diff --git a/src/Umbraco.Core/Manifest/ManifestDashboardDefinition.cs b/src/Umbraco.Core/Manifest/ManifestDashboardDefinition.cs index 83f047b264..b2b3fd5dfb 100644 --- a/src/Umbraco.Core/Manifest/ManifestDashboardDefinition.cs +++ b/src/Umbraco.Core/Manifest/ManifestDashboardDefinition.cs @@ -1,12 +1,12 @@ using System; using System.ComponentModel; using Newtonsoft.Json; -using Umbraco.Core.Configuration.Dashboard; +using Umbraco.Core.Dashboards; using Umbraco.Core.IO; namespace Umbraco.Core.Manifest { - public class ManifestDashboardDefinition + public class ManifestDashboardDefinition : IDashboardSection { private string _view; @@ -32,5 +32,6 @@ namespace Umbraco.Core.Manifest [JsonProperty("access")] public IAccessRule[] AccessRules { get; set; } = Array.Empty(); + } } diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 0ff88da2f3..993797392f 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -211,26 +211,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -331,6 +311,10 @@ + + + + diff --git a/src/Umbraco.Tests/Configurations/DashboardSettings/DashboardSettingsTests.cs b/src/Umbraco.Tests/Configurations/DashboardSettings/DashboardSettingsTests.cs index 920de683b4..219e6092d2 100644 --- a/src/Umbraco.Tests/Configurations/DashboardSettings/DashboardSettingsTests.cs +++ b/src/Umbraco.Tests/Configurations/DashboardSettings/DashboardSettingsTests.cs @@ -1,123 +1,124 @@ -using System.Configuration; +using System; +using System.Configuration; using System.IO; using System.Linq; using NUnit.Framework; -using Umbraco.Core.Configuration.Dashboard; -using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Dashboards; using Umbraco.Tests.TestHelpers; namespace Umbraco.Tests.Configurations.DashboardSettings { - [TestFixture] - public class DashboardSettingsTests - { - [SetUp] - public void Init() - { - var config = new FileInfo(TestHelper.MapPathForTest("~/Configurations/DashboardSettings/web.config")); + //[Obsolete("Dashboard tests not in config/XML", true)] + //[TestFixture] + //public class DashboardSettingsTests + //{ + // [SetUp] + // public void Init() + // { + // var config = new FileInfo(TestHelper.MapPathForTest("~/Configurations/DashboardSettings/web.config")); - var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = config.FullName }; - var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); + // var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = config.FullName }; + // var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); - SettingsSection = configuration.GetSection("umbracoConfiguration/dashBoard") as DashboardSection; + // SettingsSection = configuration.GetSection("umbracoConfiguration/dashBoard") as DashboardSection; - Assert.IsNotNull(SettingsSection); - } + // Assert.IsNotNull(SettingsSection); + // } - protected IDashboardSection SettingsSection { get; private set; } + // protected IDashboardSection SettingsSection { get; private set; } - [Test] - public void Test_Sections() - { - Assert.AreEqual(5, SettingsSection.Sections.Count()); + // [Test] + // public void Test_Sections() + // { + // Assert.AreEqual(5, SettingsSection.Sections.Count()); - Assert.AreEqual("StartupSettingsDashboardSection", SettingsSection.Sections.ElementAt(0).Alias); - Assert.AreEqual("StartupDeveloperDashboardSection", SettingsSection.Sections.ElementAt(1).Alias); - Assert.AreEqual("StartupMediaDashboardSection", SettingsSection.Sections.ElementAt(2).Alias); - Assert.AreEqual("StartupDashboardSection", SettingsSection.Sections.ElementAt(3).Alias); - Assert.AreEqual("StartupMemberDashboardSection", SettingsSection.Sections.ElementAt(4).Alias); - } + // Assert.AreEqual("StartupSettingsDashboardSection", SettingsSection.Sections.ElementAt(0).Alias); + // Assert.AreEqual("StartupDeveloperDashboardSection", SettingsSection.Sections.ElementAt(1).Alias); + // Assert.AreEqual("StartupMediaDashboardSection", SettingsSection.Sections.ElementAt(2).Alias); + // Assert.AreEqual("StartupDashboardSection", SettingsSection.Sections.ElementAt(3).Alias); + // Assert.AreEqual("StartupMemberDashboardSection", SettingsSection.Sections.ElementAt(4).Alias); + // } - [Test] - public void Test_Section_Area() - { - Assert.AreEqual("settings", SettingsSection.Sections.ElementAt(0).Areas.First()); - Assert.AreEqual("developer", SettingsSection.Sections.ElementAt(1).Areas.First()); - Assert.AreEqual("media", SettingsSection.Sections.ElementAt(2).Areas.First()); - Assert.AreEqual("content", SettingsSection.Sections.ElementAt(3).Areas.First()); - Assert.AreEqual("default", SettingsSection.Sections.ElementAt(4).Areas.First()); - Assert.AreEqual("member", SettingsSection.Sections.ElementAt(4).Areas.Last()); - } + // [Test] + // public void Test_Section_Area() + // { + // Assert.AreEqual("settings", SettingsSection.Sections.ElementAt(0).Areas.First()); + // Assert.AreEqual("developer", SettingsSection.Sections.ElementAt(1).Areas.First()); + // Assert.AreEqual("media", SettingsSection.Sections.ElementAt(2).Areas.First()); + // Assert.AreEqual("content", SettingsSection.Sections.ElementAt(3).Areas.First()); + // Assert.AreEqual("default", SettingsSection.Sections.ElementAt(4).Areas.First()); + // Assert.AreEqual("member", SettingsSection.Sections.ElementAt(4).Areas.Last()); + // } - [Test] - public void Test_Section_Access() - { + // [Test] + // public void Test_Section_Access() + // { - Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.Count()); + // Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.Count()); - Assert.AreEqual("translator", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Value); - Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Type); - Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Value); - Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Type); - Assert.AreEqual("world", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Value); - Assert.AreEqual(AccessRuleType.GrantBySection, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Type); - } + // Assert.AreEqual("translator", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Value); + // Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(0).Type); + // Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Value); + // Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(1).Type); + // Assert.AreEqual("world", SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Value); + // Assert.AreEqual(AccessRuleType.GrantBySection, SettingsSection.Sections.ElementAt(3).AccessRights.Rules.ElementAt(2).Type); + // } - [Test] - public void Test_Section_Tabs() - { - //Element 0 Alias "StartupSettingsDashboardSection" - Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.Count()); + // [Test] + // public void Test_Section_Tabs() + // { + // //Element 0 Alias "StartupSettingsDashboardSection" + // Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.Count()); - //Element 1 Alias "StartupDeveloperDashboardSection" - Assert.AreEqual(1, SettingsSection.Sections.ElementAt(1).Tabs.Count()); + // //Element 1 Alias "StartupDeveloperDashboardSection" + // Assert.AreEqual(1, SettingsSection.Sections.ElementAt(1).Tabs.Count()); - //Element 2 Alias "StartupMediaDashboardSection" - Assert.AreEqual(2, SettingsSection.Sections.ElementAt(2).Tabs.Count()); + // //Element 2 Alias "StartupMediaDashboardSection" + // Assert.AreEqual(2, SettingsSection.Sections.ElementAt(2).Tabs.Count()); - //Element 3 Alias "StartupDashboardSection" - Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).Tabs.Count()); + // //Element 3 Alias "StartupDashboardSection" + // Assert.AreEqual(3, SettingsSection.Sections.ElementAt(3).Tabs.Count()); - //Element 4 Alias "StartupMemberDashboardSection" - Assert.AreEqual(1, SettingsSection.Sections.ElementAt(4).Tabs.Count()); + // //Element 4 Alias "StartupMemberDashboardSection" + // Assert.AreEqual(1, SettingsSection.Sections.ElementAt(4).Tabs.Count()); - } + // } - [Test] - public void Test_Tab() - { - Assert.AreEqual("Get Started", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Caption); - Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.Count()); - } + // [Test] + // public void Test_Tab() + // { + // Assert.AreEqual("Get Started", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Caption); + // Assert.AreEqual(2, SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.Count()); + // } - [Test] - public void Test_Tab_Access() - { - Assert.AreEqual(1, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.Count()); - Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Type); - Assert.AreEqual("admin", SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Value); - } + // [Test] + // public void Test_Tab_Access() + // { + // Assert.AreEqual(1, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.Count()); + // Assert.AreEqual(AccessRuleType.Grant, SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Type); + // Assert.AreEqual("admin", SettingsSection.Sections.ElementAt(2).Tabs.ElementAt(1).AccessRights.Rules.ElementAt(0).Value); + // } - [Test] - public void Test_Control() - { - Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).PanelCaption); - Assert.AreEqual("views/dashboard/settings/settingsdashboardintro.html", - SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).ControlPath); + // [Test] + // public void Test_Control() + // { + // Assert.AreEqual("hello", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).PanelCaption); + // Assert.AreEqual("views/dashboard/settings/settingsdashboardintro.html", + // SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(0).ControlPath); - Assert.AreEqual("", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).PanelCaption); - Assert.AreEqual("views/dashboard/settings/settingsdashboardvideos.html", - SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).ControlPath); - } + // Assert.AreEqual("", SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).PanelCaption); + // Assert.AreEqual("views/dashboard/settings/settingsdashboardvideos.html", + // SettingsSection.Sections.ElementAt(0).Tabs.ElementAt(0).Controls.ElementAt(1).ControlPath); + // } - [Test] - public void Test_Control_Access() - { - Assert.AreEqual(2, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.Count()); - Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Type); - Assert.AreEqual("editor", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Value); - Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Type); - Assert.AreEqual("writer", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Value); - } - } + // [Test] + // public void Test_Control_Access() + // { + // Assert.AreEqual(2, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.Count()); + // Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Type); + // Assert.AreEqual("editor", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(0).Value); + // Assert.AreEqual(AccessRuleType.Deny, SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Type); + // Assert.AreEqual("writer", SettingsSection.Sections.ElementAt(3).Tabs.ElementAt(0).Controls.ElementAt(1).AccessRights.Rules.ElementAt(1).Value); + // } + //} } diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs index 4e791c0169..a12f90c4eb 100644 --- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs +++ b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs @@ -7,12 +7,12 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core.Cache; using Umbraco.Core.Composing; -using Umbraco.Core.Configuration.Dashboard; using Umbraco.Core.Logging; using Umbraco.Core.Manifest; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; using Umbraco.Core.Services; +using Umbraco.Core.Dashboards; namespace Umbraco.Tests.Manifest { diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index ed28a93caf..fe657ae470 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -937,7 +937,7 @@ }, "ansi-colors": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { @@ -955,7 +955,7 @@ }, "ansi-escapes": { "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, @@ -1170,7 +1170,7 @@ "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "array-sort": { @@ -1216,7 +1216,7 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", "dev": true }, "asap": { @@ -1269,7 +1269,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, "asynckit": { @@ -2379,7 +2379,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -2459,7 +2459,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "continuable-cache": { @@ -2502,7 +2502,7 @@ "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha1-+XJgj/DOrWi4QaFqky0LGDeRgU4=", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", "dev": true }, "core-util-is": { @@ -3425,7 +3425,7 @@ "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -3953,7 +3953,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -3989,7 +3989,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -4153,7 +4153,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -4248,7 +4248,7 @@ "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -4258,13 +4258,13 @@ "eslint-utils": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", "dev": true }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, "espree": { @@ -4287,7 +4287,7 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { "estraverse": "^4.0.0" @@ -4296,7 +4296,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -4356,7 +4356,7 @@ "eventemitter3": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", "dev": true }, "exec-buffer": { @@ -4571,7 +4571,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", "dev": true, "requires": { "is-number": "^2.1.0", @@ -5891,7 +5891,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -6461,7 +6461,7 @@ "gulp-eslint": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz", - "integrity": "sha1-KiaECV93Syz3kxAmIHjFbMehK1I=", + "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==", "dev": true, "requires": { "eslint": "^5.0.1", @@ -7415,7 +7415,7 @@ "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { "isarray": "2.0.1" @@ -7566,7 +7566,7 @@ "http-proxy": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { "eventemitter3": "^3.0.0", @@ -7860,7 +7860,7 @@ "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -8155,7 +8155,7 @@ "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" @@ -8164,7 +8164,7 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-retry-allowed": { @@ -8212,7 +8212,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -8369,7 +8369,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { @@ -8496,7 +8496,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -9146,7 +9146,7 @@ "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { "kind-of": "^6.0.2" @@ -9327,7 +9327,7 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { @@ -12855,7 +12855,7 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "posix-character-classes": { @@ -13345,7 +13345,7 @@ "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, "qs": { @@ -13541,7 +13541,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -14039,7 +14039,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "sax": { @@ -14226,7 +14226,7 @@ "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, "shebang-command": { @@ -14516,7 +14516,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -14796,7 +14796,7 @@ "stream-consume": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha1-0721mMK9CugrjKx6xQsRB6eZbEg=", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", "dev": true }, "stream-shift": { @@ -14808,7 +14808,7 @@ "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", "dev": true, "requires": { "date-format": "^1.2.0", @@ -14835,7 +14835,7 @@ "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -14850,7 +14850,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14867,7 +14867,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -15409,7 +15409,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -15573,7 +15573,7 @@ "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "dev": true, "requires": { "media-typer": "0.3.0", @@ -15615,7 +15615,7 @@ "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, "unc-path-regex": { @@ -15777,13 +15777,13 @@ "upath": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha1-NSVll+RqWB20eT0M5H+prr/J+r0=", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -16218,7 +16218,7 @@ "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { "async-limiter": "~1.0.0", diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html index 6453963670..c3b60e2f0a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dashboard.html @@ -17,16 +17,15 @@
- +
- +
-

{{property.caption}}

-
+
- +
- +
@@ -34,5 +33,5 @@
- +
diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 0ff158dadb..c7b6540b3d 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -178,6 +178,7 @@ + @@ -205,6 +206,7 @@ + 404handlers.config diff --git a/src/Umbraco.Web.UI/config/Dashboard.config b/src/Umbraco.Web.UI/config/Dashboard.config index fec6ab34ae..94325913df 100644 --- a/src/Umbraco.Web.UI/config/Dashboard.config +++ b/src/Umbraco.Web.UI/config/Dashboard.config @@ -94,6 +94,7 @@ +
content diff --git a/src/Umbraco.Web/CompositionExtensions.cs b/src/Umbraco.Web/CompositionExtensions.cs index 246127b312..783c991ab4 100644 --- a/src/Umbraco.Web/CompositionExtensions.cs +++ b/src/Umbraco.Web/CompositionExtensions.cs @@ -10,6 +10,7 @@ using Umbraco.Web.Routing; using Umbraco.Web.ContentApps; using Umbraco.Web.Tour; using Umbraco.Web.Trees; +using Umbraco.Web.Dashboards; // the namespace here is intentional - although defined in Umbraco.Web assembly, // this class should be visible when using Umbraco.Core.Components, alongside @@ -92,6 +93,13 @@ namespace Umbraco.Core.Components public static BackOfficeSectionCollectionBuilder Sections(this Composition composition) => composition.WithCollectionBuilder(); + /// + /// Gets the backoffice dashboards collection builder. + /// + /// The composition. + public static DashboardCollectionBuilder Dashboards(this Composition composition) + => composition.WithCollectionBuilder(); + #endregion #region Uniques diff --git a/src/Umbraco.Web/Dashboards/ContentDashboard.cs b/src/Umbraco.Web/Dashboards/ContentDashboard.cs new file mode 100644 index 0000000000..c184e593aa --- /dev/null +++ b/src/Umbraco.Web/Dashboards/ContentDashboard.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(10)] + //[HideFromTypeFinder] + [DataContract] + public class ContentDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Get Started"; + + [DataMember(Name = "alias")] + public string Alias => "contentIntro"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "content" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/default/startupdashboardintro.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules + { + get + { + //TODO: WB Not convinced these rules work correctly?! + var rules = new List(); + rules.Add(new AccessRule { Type = AccessRuleType.Deny, Value = "translator" }); + rules.Add(new AccessRule { Type = AccessRuleType.Grant, Value = "admin" }); + return rules.ToArray(); + } + } + } +} diff --git a/src/Umbraco.Web/Dashboards/DashboardCollection.cs b/src/Umbraco.Web/Dashboards/DashboardCollection.cs new file mode 100644 index 0000000000..8d3bde622e --- /dev/null +++ b/src/Umbraco.Web/Dashboards/DashboardCollection.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + public class DashboardCollection : BuilderCollectionBase + { + public DashboardCollection(IEnumerable items) + : base(items) + { } + } +} diff --git a/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs b/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs new file mode 100644 index 0000000000..d4a89a61b2 --- /dev/null +++ b/src/Umbraco.Web/Dashboards/DashboardCollectionBuilder.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; +using Umbraco.Core.Manifest; + +namespace Umbraco.Web.Dashboards +{ + public class DashboardCollectionBuilder : WeightedCollectionBuilderBase + { + protected override DashboardCollectionBuilder This => this; + + protected override IEnumerable CreateItems(IFactory factory) + { + // get the manifest parser just-in-time - injecting it in the ctor would mean that + // simply getting the builder in order to configure the collection, would require + // its dependencies too, and that can create cycles or other oddities + var manifestParser = factory.GetInstance(); + + //TODO WB: We will need to re-sort items from package manifest with the C# Types + return base.CreateItems(factory).Concat(manifestParser.Manifest.Dashboards); + } + } +} diff --git a/src/Umbraco.Web/Dashboards/ExamineDashboard.cs b/src/Umbraco.Web/Dashboards/ExamineDashboard.cs new file mode 100644 index 0000000000..5f04a4b78d --- /dev/null +++ b/src/Umbraco.Web/Dashboards/ExamineDashboard.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(20)] + [DataContract] + public class ExamineDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Examine Management"; + + [DataMember(Name = "alias")] + public string Alias => "settingsExamine"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "settings" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/settings/examinemanagement.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } + + +} diff --git a/src/Umbraco.Web/Dashboards/FormsDashboard.cs b/src/Umbraco.Web/Dashboards/FormsDashboard.cs new file mode 100644 index 0000000000..c9e8e06b7d --- /dev/null +++ b/src/Umbraco.Web/Dashboards/FormsDashboard.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(10)] + [DataContract] + public class FormsDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Install Umbraco Forms"; + + [DataMember(Name = "alias")] + public string Alias => "formsInstall"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "forms" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/forms/formsdashboardintro.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } +} diff --git a/src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs b/src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs new file mode 100644 index 0000000000..808dc099e8 --- /dev/null +++ b/src/Umbraco.Web/Dashboards/HealthCheckDashboard.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(50)] + [DataContract] + public class HealthCheckDashboard : IDashboardSection + { + [DataMember(Name="name")] + public string Name => "Health Check"; + + [DataMember(Name = "alias")] + public string Alias => "settingsHealthCheck"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "settings" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/settings/healthcheck.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } + + +} diff --git a/src/Umbraco.Web/Dashboards/MediaDashboard.cs b/src/Umbraco.Web/Dashboards/MediaDashboard.cs new file mode 100644 index 0000000000..c122ba1f7f --- /dev/null +++ b/src/Umbraco.Web/Dashboards/MediaDashboard.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(10)] + [DataContract] + public class MediaDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Content"; + + [DataMember(Name = "alias")] + public string Alias => "mediaFolderBrowser"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "media" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/media/mediafolderbrowser.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } +} diff --git a/src/Umbraco.Web/Dashboards/MembersDashboard.cs b/src/Umbraco.Web/Dashboards/MembersDashboard.cs new file mode 100644 index 0000000000..9da6f59108 --- /dev/null +++ b/src/Umbraco.Web/Dashboards/MembersDashboard.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(10)] + [DataContract] + public class MembersDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Get Started"; + + [DataMember(Name = "alias")] + public string Alias => "memberIntro"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "member" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/members/membersdashboardvideos.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } +} diff --git a/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs b/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs new file mode 100644 index 0000000000..f25a9f7ea0 --- /dev/null +++ b/src/Umbraco.Web/Dashboards/ModelsBuilderDashboard.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(40)] + [DataContract] + public class ModelsBuilderDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Models Builder"; + + [DataMember(Name = "alias")] + public string Alias => "settingsModelsBuilder"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "settings" }; + + [DataMember(Name = "view")] + public string View => "/App_Plugins/ModelsBuilder/modelsbuilder.htm"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } + + +} diff --git a/src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs b/src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs new file mode 100644 index 0000000000..d2fa5b217b --- /dev/null +++ b/src/Umbraco.Web/Dashboards/PublishedStatusDashboard.cs @@ -0,0 +1,29 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(30)] + [DataContract] + public class PublishedStatusDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Published Status"; + + [DataMember(Name = "alias")] + public string Alias => "settingsPublishedStatus"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "settings" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/settings/publishedstatus.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } + + +} diff --git a/src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs b/src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs new file mode 100644 index 0000000000..731d259d39 --- /dev/null +++ b/src/Umbraco.Web/Dashboards/RedirectUrlDashboard.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(20)] + [DataContract] + public class RedirectUrlDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Redirect URL Management"; + + [DataMember(Name = "alias")] + public string Alias => "contentRedirectManager"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "content" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/content/redirecturls.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } +} diff --git a/src/Umbraco.Web/Dashboards/SettingsDashboards.cs b/src/Umbraco.Web/Dashboards/SettingsDashboards.cs new file mode 100644 index 0000000000..47c1723075 --- /dev/null +++ b/src/Umbraco.Web/Dashboards/SettingsDashboards.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.Serialization; +using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; + +namespace Umbraco.Web.Dashboards +{ + [Weight(10)] + [DataContract] + public class SettingsDashboard : IDashboardSection + { + [DataMember(Name = "name")] + public string Name => "Welcome"; + + [DataMember(Name = "alias")] + public string Alias => "settingsWelcome"; + + [IgnoreDataMember] + public string[] Sections => new string[] { "settings" }; + + [DataMember(Name = "view")] + public string View => "views/dashboard/settings/settingsdashboardintro.html"; + + [IgnoreDataMember] + public IAccessRule[] AccessRules => Array.Empty(); + } +} diff --git a/src/Umbraco.Web/Editors/DashboardController.cs b/src/Umbraco.Web/Editors/DashboardController.cs index c6e0049865..11d31a86b4 100644 --- a/src/Umbraco.Web/Editors/DashboardController.cs +++ b/src/Umbraco.Web/Editors/DashboardController.cs @@ -16,6 +16,8 @@ using Umbraco.Web.WebApi.Filters; using Umbraco.Core.Logging; using Umbraco.Core.Persistence; using Umbraco.Core.Services; +using Umbraco.Core.Dashboards; +using Umbraco.Web.Services; namespace Umbraco.Web.Editors { @@ -27,7 +29,7 @@ namespace Umbraco.Web.Editors [WebApi.UmbracoAuthorize] public class DashboardController : UmbracoApiController { - private readonly Dashboards _dashboards; + private readonly IDashboardService _dashboardService; /// /// Initializes a new instance of the with auto dependencies. @@ -38,10 +40,10 @@ namespace Umbraco.Web.Editors /// /// Initializes a new instance of the with all its dependencies. /// - public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, Dashboards dashboards) + public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, IDashboardService dashboardService) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) { - _dashboards = dashboards; + _dashboardService = dashboardService; } //we have just one instance of HttpClient shared for the entire application @@ -79,7 +81,7 @@ namespace Umbraco.Web.Editors } catch (HttpRequestException ex) { - Logger.Error(ex.InnerException ?? ex, "Error getting dashboard content from '{Url}'", url); + Logger.Error(ex.InnerException ?? ex, "Error getting dashboard content from {Url}", url); //it's still new JObject() - we return it like this to avoid error codes which triggers UI warnings AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0)); @@ -117,7 +119,7 @@ namespace Umbraco.Web.Editors } catch (HttpRequestException ex) { - Logger.Error(ex.InnerException ?? ex, "Error getting dashboard CSS from '{Url}'", url); + Logger.Error(ex.InnerException ?? ex, "Error getting dashboard CSS from {Url}", url); //it's still string.Empty - we return it like this to avoid error codes which triggers UI warnings AppCaches.RuntimeCache.InsertCacheItem(key, () => result, new TimeSpan(0, 5, 0)); @@ -132,9 +134,9 @@ namespace Umbraco.Web.Editors [ValidateAngularAntiForgeryToken] [OutgoingEditorModelEvent] - public IEnumerable> GetDashboard(string section) + public IEnumerable> GetDashboard(string section) { - return _dashboards.GetDashboards(section, Security.CurrentUser); + return _dashboardService.GetDashboards(section, Security.CurrentUser); } } } diff --git a/src/Umbraco.Web/Editors/Dashboards.cs b/src/Umbraco.Web/Editors/Dashboards.cs deleted file mode 100644 index c837cbbf33..0000000000 --- a/src/Umbraco.Web/Editors/Dashboards.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core; -using Umbraco.Core.Configuration.Dashboard; -using Umbraco.Core.IO; -using Umbraco.Core.Manifest; -using Umbraco.Core.Models.Membership; -using Umbraco.Core.Services; -using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Services; - -namespace Umbraco.Web.Editors -{ - public class Dashboards - { - private readonly ISectionService _sectionService; - private readonly IDashboardSection _dashboardSection; - private readonly ManifestParser _manifestParser; - - public Dashboards(ISectionService sectionService, IDashboardSection dashboardSection, ManifestParser manifestParser) - { - _sectionService = sectionService ?? throw new ArgumentNullException(nameof(sectionService)); - _dashboardSection = dashboardSection; - _manifestParser = manifestParser; - } - - /// - /// Gets all dashboards, organized by section, for a user. - /// - public IDictionary>> GetDashboards(IUser currentUser) - { - return _sectionService.GetSections().ToDictionary(x => x.Alias, x => GetDashboards(x.Alias, currentUser)); - } - - /// - /// Returns dashboards for a specific section, for a user. - /// - public IEnumerable> GetDashboards(string section, IUser currentUser) - { - var tabId = 1; - var configDashboards = GetDashboardsFromConfig(ref tabId, section, currentUser); - var pluginDashboards = GetDashboardsFromPlugins(ref tabId, section, currentUser); - - // merge dashboards - // both collections contain tab.alias -> controls - var dashboards = configDashboards; - - // until now, it was fine to have duplicate tab.aliases in configDashboard - // so... the rule should be - just merge whatever we get, don't be clever - dashboards.AddRange(pluginDashboards); - - // re-sort by id - dashboards.Sort((tab1, tab2) => tab1.Id > tab2.Id ? 1 : 0); - - // re-assign ids (why?) - var i = 1; - foreach (var tab in dashboards) - { - tab.Id = i++; - tab.IsActive = tab.Id == 1; - } - - return configDashboards; - } - - // note: - // in dashboard.config we have 'sections' which define 'tabs' for 'areas' - // and 'areas' are the true UI sections - and each tab can have more than - // one control - // in a manifest, we directly have 'dashboards' which map to a unique - // control in a tab - - // gets all tabs & controls from the config file - private List> GetDashboardsFromConfig(ref int tabId, string section, IUser currentUser) - { - var tabs = new List>(); - - // disable packages section dashboard - if (section == "packages") return tabs; - - foreach (var dashboardSection in _dashboardSection.Sections.Where(x => x.Areas.InvariantContains(section))) - { - // validate access to this section - if (!DashboardSecurity.AuthorizeAccess(dashboardSection, currentUser, _sectionService)) - continue; - - foreach (var tab in dashboardSection.Tabs) - { - // validate access to this tab - if (!DashboardSecurity.AuthorizeAccess(tab, currentUser, _sectionService)) - continue; - - var dashboardControls = new List(); - - foreach (var control in tab.Controls) - { - // validate access to this control - if (!DashboardSecurity.AuthorizeAccess(control, currentUser, _sectionService)) - continue; - - // create and add control - var dashboardControl = new DashboardControl - { - Caption = control.PanelCaption, - Path = IOHelper.FindFile(control.ControlPath.Trim()) - }; - - if (dashboardControl.Path.InvariantEndsWith(".ascx")) - throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported."); - - dashboardControls.Add(dashboardControl); - } - - // create and add tab - tabs.Add(new Tab - { - Id = tabId++, - Alias = tab.Caption.ToSafeAlias(), - Label = tab.Caption, - Properties = dashboardControls - }); - } - } - - return tabs; - } - - private List> GetDashboardsFromPlugins(ref int tabId, string section, IUser currentUser) - { - var tabs = new List>(); - - foreach (var dashboard in _manifestParser.Manifest.Dashboards.Where(x => x.Sections.InvariantContains(section)).OrderBy(x => x.Weight)) - { - // validate access - if (!DashboardSecurity.CheckUserAccessByRules(currentUser, _sectionService, dashboard.AccessRules)) - continue; - - var dashboardControl = new DashboardControl - { - Caption = "", - Path = IOHelper.FindFile(dashboard.View.Trim()) - }; - - if (dashboardControl.Path.InvariantEndsWith(".ascx")) - throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported."); - - tabs.Add(new Tab - { - Id = tabId++, - Alias = dashboard.Alias.ToSafeAlias(), - Label = dashboard.Name, - Properties = new[] { dashboardControl } - }); - } - - return tabs; - } - } -} diff --git a/src/Umbraco.Web/Editors/EditorModelEventManager.cs b/src/Umbraco.Web/Editors/EditorModelEventManager.cs index 2225f5c577..dd5282d724 100644 --- a/src/Umbraco.Web/Editors/EditorModelEventManager.cs +++ b/src/Umbraco.Web/Editors/EditorModelEventManager.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Web.Http.Filters; +using Umbraco.Core.Dashboards; using Umbraco.Core.Events; using Umbraco.Web.Models.ContentEditing; @@ -14,9 +15,9 @@ namespace Umbraco.Web.Editors public static event TypedEventHandler> SendingMediaModel; public static event TypedEventHandler> SendingMemberModel; public static event TypedEventHandler> SendingUserModel; - public static event TypedEventHandler>>> SendingDashboardModel; + public static event TypedEventHandler>>> SendingDashboardModel; - private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs>> e) + private static void OnSendingDashboardModel(HttpActionExecutedContext sender, EditorModelEventArgs>> e) { var handler = SendingDashboardModel; handler?.Invoke(sender, e); @@ -65,8 +66,8 @@ namespace Umbraco.Web.Editors if (e.Model is UserDisplay) OnSendingUserModel(sender, new EditorModelEventArgs(e)); - if (e.Model is IEnumerable>) - OnSendingDashboardModel(sender, new EditorModelEventArgs>>(e)); + if (e.Model is IEnumerable) + OnSendingDashboardModel(sender, new EditorModelEventArgs>>(e)); } } } diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs index 74a06d7149..f6973fcbb9 100644 --- a/src/Umbraco.Web/Editors/SectionController.cs +++ b/src/Umbraco.Web/Editors/SectionController.cs @@ -22,15 +22,15 @@ namespace Umbraco.Web.Editors [PluginController("UmbracoApi")] public class SectionController : UmbracoAuthorizedJsonController { - private readonly Dashboards _dashboards; + private readonly IDashboardService _dashboardService; private readonly ISectionService _sectionService; private readonly ITreeService _treeService; public SectionController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, - Dashboards dashboards, ISectionService sectionService, ITreeService treeService) + IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState) { - _dashboards = dashboards; + _dashboardService = dashboardService; _sectionService = sectionService; _treeService = treeService; } @@ -48,7 +48,7 @@ namespace Umbraco.Web.Editors ControllerContext = ControllerContext }; - var dashboards = _dashboards.GetDashboards(Security.CurrentUser); + var dashboards = _dashboardService.GetDashboards(Security.CurrentUser); //now we can add metadata for each section so that the UI knows if there's actually anything at all to render for //a dashboard for a given section, then the UI can deal with it accordingly (i.e. redirect to the first tree) diff --git a/src/Umbraco.Web/Models/ContentEditing/DashboardControl.cs b/src/Umbraco.Web/Models/ContentEditing/DashboardControl.cs deleted file mode 100644 index aad6bf2d64..0000000000 --- a/src/Umbraco.Web/Models/ContentEditing/DashboardControl.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; - -namespace Umbraco.Web.Models.ContentEditing -{ - [DataContract(Name = "control", Namespace = "")] - public class DashboardControl - { - [DataMember(Name = "path")] - public string Path { get; set; } - - [DataMember(Name = "caption")] - public string Caption { get; set; } - } -} diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index 832699b5d7..d165559024 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -6,6 +6,7 @@ using Microsoft.AspNet.SignalR; using Umbraco.Core; using Umbraco.Core.Components; using Umbraco.Core.Composing; +using Umbraco.Core.Dashboards; using Umbraco.Core.Dictionary; using Umbraco.Core.Events; using Umbraco.Core.Models.PublishedContent; @@ -17,6 +18,7 @@ using Umbraco.Web.Actions; using Umbraco.Web.Cache; using Umbraco.Web.Composing.Composers; using Umbraco.Web.ContentApps; +using Umbraco.Web.Dashboards; using Umbraco.Web.Dictionary; using Umbraco.Web.Editors; using Umbraco.Web.Features; @@ -95,14 +97,13 @@ namespace Umbraco.Web.Runtime composition.RegisterUnique(); composition.RegisterUnique(); + composition.RegisterUnique(); + composition.RegisterUnique(factory => ExamineManager.Instance); // configure the container for web composition.ConfigureForWeb(); - - - composition.RegisterUnique(); - + composition .ComposeUmbracoControllers(GetType().Assembly) .SetDefaultRenderMvcController(); // default controller for template views @@ -202,6 +203,25 @@ namespace Umbraco.Web.Runtime .Append() .Append(); + + // register core CMS dashboards as types - will be ordered by weight attribute & merged with package.manifest dashboards + // TODO WB Maybe use typeloader?! + + composition.WithCollectionBuilder() + .Add(composition.TypeLoader.GetTypes()); + + //.Add() + //.Add() + //.Add() + //.Add() + //.Add() + //.Add() + //.Add() + //.Add() + //.Add() + //.Add(); + + // register back office trees foreach (var treeControllerType in umbracoApiControllerTypes .Where(x => typeof(TreeControllerBase).IsAssignableFrom(x))) diff --git a/src/Umbraco.Web/Editors/DashboardSecurity.cs b/src/Umbraco.Web/Services/DashboardService.cs similarity index 62% rename from src/Umbraco.Web/Editors/DashboardSecurity.cs rename to src/Umbraco.Web/Services/DashboardService.cs index fdbf5af7d9..9f70f876a3 100644 --- a/src/Umbraco.Web/Editors/DashboardSecurity.cs +++ b/src/Umbraco.Web/Services/DashboardService.cs @@ -1,65 +1,63 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using Umbraco.Core; -using Umbraco.Core.Configuration.Dashboard; +using Umbraco.Core.Dashboards; using Umbraco.Core.Models.Membership; -using Umbraco.Core.Services; -using Umbraco.Web.Services; +using Umbraco.Web.Dashboards; +using Umbraco.Web.Models.ContentEditing; -namespace Umbraco.Web.Editors +namespace Umbraco.Web.Services { - /// - /// A utility class for determine dashboard security - /// - internal class DashboardSecurity + internal class DashboardService : IDashboardService { - //TODO: Unit test all this!!! :/ + private readonly ISectionService _sectionService; + private readonly DashboardCollection _dashboardCollection; - public static bool AuthorizeAccess(ISection dashboardSection, IUser user, ISectionService sectionService) + public DashboardService(ISectionService sectionService, DashboardCollection dashboardCollection) { - return CheckUserAccessByRules(user, sectionService, dashboardSection.AccessRights.Rules); + _sectionService = sectionService ?? throw new ArgumentNullException(nameof(sectionService)); + _dashboardCollection = dashboardCollection ?? throw new ArgumentNullException(nameof(dashboardCollection)); } - public static bool AuthorizeAccess(IDashboardTab dashboardTab, IUser user, ISectionService sectionService) + + /// + public IEnumerable> GetDashboards(string section, IUser currentUser) { - return CheckUserAccessByRules(user, sectionService, dashboardTab.AccessRights.Rules); - } + var tabs = new List>(); + var tabId = 0; - public static bool AuthorizeAccess(IDashboardControl dashboardControl, IUser user, ISectionService sectionService) - { - return CheckUserAccessByRules(user, sectionService, dashboardControl.AccessRights.Rules); - } - - private static (IAccessRule[], IAccessRule[], IAccessRule[]) GroupRules(IEnumerable rules) - { - IAccessRule[] denyRules = null, grantRules = null, grantBySectionRules = null; - - var groupedRules = rules.GroupBy(x => x.Type); - foreach (var group in groupedRules) + foreach (var dashboard in _dashboardCollection.Where(x => x.Sections.InvariantContains(section))) { - var a = group.ToArray(); - switch (group.Key) + // validate access + if (!CheckUserAccessByRules(currentUser, _sectionService, dashboard.AccessRules)) + continue; + + if (dashboard.View.InvariantEndsWith(".ascx")) + throw new NotSupportedException("Legacy UserControl (.ascx) dashboards are no longer supported."); + + var dashboards = new List(); + dashboards.Add(dashboard); + + tabs.Add(new Tab() { - case AccessRuleType.Deny: - denyRules = a; - break; - case AccessRuleType.Grant: - grantRules = a; - break; - case AccessRuleType.GrantBySection: - grantBySectionRules = a; - break; - default: - throw new Exception("panic"); - } + Id = tabId++, + Label = dashboard.Name, + Alias = dashboard.Alias, + Properties = dashboards + }); } - return (denyRules ?? Array.Empty(), grantRules ?? Array.Empty(), grantBySectionRules ?? Array.Empty()); + return tabs; } - public static bool CheckUserAccessByRules(IUser user, ISectionService sectionService, IEnumerable rules) + /// + public IDictionary>> GetDashboards(IUser currentUser) + { + return _sectionService.GetSections().ToDictionary(x => x.Alias, x => GetDashboards(x.Alias, currentUser)); + } + + private bool CheckUserAccessByRules(IUser user, ISectionService sectionService, IEnumerable rules) { if (user.Id == Constants.Security.SuperUserId) return true; @@ -111,5 +109,32 @@ namespace Umbraco.Web.Editors return hasAccess; } + + private (IAccessRule[], IAccessRule[], IAccessRule[]) GroupRules(IEnumerable rules) + { + IAccessRule[] denyRules = null, grantRules = null, grantBySectionRules = null; + + var groupedRules = rules.GroupBy(x => x.Type); + foreach (var group in groupedRules) + { + var a = group.ToArray(); + switch (group.Key) + { + case AccessRuleType.Deny: + denyRules = a; + break; + case AccessRuleType.Grant: + grantRules = a; + break; + case AccessRuleType.GrantBySection: + grantBySectionRules = a; + break; + default: + throw new Exception("panic"); + } + } + + return (denyRules ?? Array.Empty(), grantRules ?? Array.Empty(), grantBySectionRules ?? Array.Empty()); + } } } diff --git a/src/Umbraco.Web/Services/IDashboardService.cs b/src/Umbraco.Web/Services/IDashboardService.cs new file mode 100644 index 0000000000..a86715c83d --- /dev/null +++ b/src/Umbraco.Web/Services/IDashboardService.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Umbraco.Core.Dashboards; +using Umbraco.Core.Models.Membership; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.Services +{ + public interface IDashboardService + { + /// + /// Gets dashboard for a specific section/application + /// For a specific backoffice user + /// + /// + /// + /// + IEnumerable> GetDashboards(string section, IUser currentUser); + + /// + /// Gets all dashboards, organized by section, for a user. + /// + /// + /// + IDictionary>> GetDashboards(IUser currentUser); + + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index a6f380b0dd..bd3ff8910b 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -122,6 +122,18 @@ + + + + + + + + + + + + @@ -169,6 +181,8 @@ + + @@ -244,7 +258,6 @@ - @@ -705,7 +718,6 @@ - @@ -826,7 +838,6 @@ - From 5d34ee271cc6ee57568db49fe0d379e95c885e52 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 14:42:49 +0000 Subject: [PATCH 021/213] Forgot to remove my test App_Plugin Dashboard --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index c7b6540b3d..0ff158dadb 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -178,7 +178,6 @@ - @@ -206,7 +205,6 @@ - 404handlers.config From f2cc0eebf5a79f0b9283e6e64d512810174788be Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 14:43:05 +0000 Subject: [PATCH 022/213] Remove the dashboard XML config file --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 7 -- .../config/Dashboard.Release.config | 107 ----------------- src/Umbraco.Web.UI/config/Dashboard.config | 108 ------------------ 3 files changed, 222 deletions(-) delete mode 100644 src/Umbraco.Web.UI/config/Dashboard.Release.config delete mode 100644 src/Umbraco.Web.UI/config/Dashboard.config diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 0ff158dadb..65b5691241 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -251,10 +251,6 @@ feedProxy.config - - Dashboard.config - Designer - @@ -361,9 +357,6 @@ Designer - - Designer - Designer diff --git a/src/Umbraco.Web.UI/config/Dashboard.Release.config b/src/Umbraco.Web.UI/config/Dashboard.Release.config deleted file mode 100644 index fec6ab34ae..0000000000 --- a/src/Umbraco.Web.UI/config/Dashboard.Release.config +++ /dev/null @@ -1,107 +0,0 @@ - - - -
- - settings - - - - views/dashboard/settings/settingsdashboardintro.html - - - - - views/dashboard/settings/examinemanagement.html - - - - - views/dashboard/settings/publishedstatus.html - - -
- -
- - forms - - - - views/dashboard/forms/formsdashboardintro.html - - -
- -
- - media - - - - views/dashboard/media/mediafolderbrowser.html - - -
- -
- - translator - - - content - - - - admin - - - - views/dashboard/default/startupdashboardintro.html - - -
- -
- - member - - - - views/dashboard/members/membersdashboardvideos.html - - -
- -
- - settings - - - - /App_Plugins/ModelsBuilder/modelsbuilder.htm - - -
- -
- - settings - - - - views/dashboard/settings/healthcheck.html - - -
-
- - content - - - - views/dashboard/content/redirecturls.html - - -
-
diff --git a/src/Umbraco.Web.UI/config/Dashboard.config b/src/Umbraco.Web.UI/config/Dashboard.config deleted file mode 100644 index 94325913df..0000000000 --- a/src/Umbraco.Web.UI/config/Dashboard.config +++ /dev/null @@ -1,108 +0,0 @@ - - - -
- - settings - - - - views/dashboard/settings/settingsdashboardintro.html - - - - - views/dashboard/settings/examinemanagement.html - - - - - views/dashboard/settings/publishedstatus.html - - -
- -
- - forms - - - - views/dashboard/forms/formsdashboardintro.html - - -
- -
- - media - - - - views/dashboard/media/mediafolderbrowser.html - - -
- -
- - translator - - - content - - - - admin - - - - views/dashboard/default/startupdashboardintro.html - - -
- -
- - member - - - - views/dashboard/members/membersdashboardvideos.html - - -
- -
- - settings - - - - /App_Plugins/ModelsBuilder/modelsbuilder.htm - - -
- -
- - settings - - - - views/dashboard/settings/healthcheck.html - - -
- -
- - content - - - - views/dashboard/content/redirecturls.html - - -
-
From 5e9f8619912d6edffe2d1274836e6e2cc287593d Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 15:09:31 +0000 Subject: [PATCH 023/213] Cleanup of WebRuntimeComposer --- src/Umbraco.Web/Runtime/WebRuntimeComposer.cs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs index d165559024..22595d795c 100644 --- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs +++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs @@ -204,23 +204,9 @@ namespace Umbraco.Web.Runtime .Append(); - // register core CMS dashboards as types - will be ordered by weight attribute & merged with package.manifest dashboards - // TODO WB Maybe use typeloader?! - + // register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards composition.WithCollectionBuilder() - .Add(composition.TypeLoader.GetTypes()); - - //.Add() - //.Add() - //.Add() - //.Add() - //.Add() - //.Add() - //.Add() - //.Add() - //.Add() - //.Add(); - + .Add(composition.TypeLoader.GetTypes()); // register back office trees foreach (var treeControllerType in umbracoApiControllerTypes From 03498b3c616851e53ccbb785b63bba8e47f06186 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 17:56:44 +0000 Subject: [PATCH 024/213] Update comment about this Interface usage - maybe we can remove this later on --- src/Umbraco.Web/UI/IAssignedApp.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/UI/IAssignedApp.cs b/src/Umbraco.Web/UI/IAssignedApp.cs index ef8c0fabcb..b70dafa50e 100644 --- a/src/Umbraco.Web/UI/IAssignedApp.cs +++ b/src/Umbraco.Web/UI/IAssignedApp.cs @@ -5,7 +5,7 @@ ///
/// /// Currently things that need to be assigned to an app in order for user security to work are: - /// dialogs, ITasks, editors + /// LegacyDialogTask /// public interface IAssignedApp { From fcb3f8e791e18c9dfc5fb672ef3c0d9c4fbd67cb Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 17:57:20 +0000 Subject: [PATCH 025/213] Remove Umbraco.Web.UI.Controls folder & classes - Controis reek of WebForms era --- src/Umbraco.Web/UI/Controls/ProgressBar.cs | 17 --- src/Umbraco.Web/UI/Controls/UmbracoControl.cs | 67 ------------ .../UI/Controls/UmbracoUserControl.cs | 103 ------------------ src/Umbraco.Web/Umbraco.Web.csproj | 5 - 4 files changed, 192 deletions(-) delete mode 100644 src/Umbraco.Web/UI/Controls/ProgressBar.cs delete mode 100644 src/Umbraco.Web/UI/Controls/UmbracoControl.cs delete mode 100644 src/Umbraco.Web/UI/Controls/UmbracoUserControl.cs diff --git a/src/Umbraco.Web/UI/Controls/ProgressBar.cs b/src/Umbraco.Web/UI/Controls/ProgressBar.cs deleted file mode 100644 index 3e87da1d6f..0000000000 --- a/src/Umbraco.Web/UI/Controls/ProgressBar.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Umbraco.Core.IO; - -namespace Umbraco.Web.UI.Controls -{ - public class ProgressBar : System.Web.UI.WebControls.Image - { - public string Title { get; set; } - - protected override void Render(System.Web.UI.HtmlTextWriter writer) - { - base.ImageUrl = "/images/progressBar.gif"; - base.AlternateText = Title; - - base.Render(writer); - } - } -} diff --git a/src/Umbraco.Web/UI/Controls/UmbracoControl.cs b/src/Umbraco.Web/UI/Controls/UmbracoControl.cs deleted file mode 100644 index c56e4fe07f..0000000000 --- a/src/Umbraco.Web/UI/Controls/UmbracoControl.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Web.Mvc; -using System.Web.UI; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Services; -using Umbraco.Web.Composing; - -namespace Umbraco.Web.UI.Controls -{ - /// - /// A control that exposes the helpful Umbraco context objects - /// - public abstract class UmbracoControl : Control - { - private UrlHelper _url; - - protected UmbracoControl(UmbracoContext umbracoContext, ServiceContext services) - { - UmbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext)); - Umbraco = new UmbracoHelper(umbracoContext, services); - - // todo inject somehow - Logger = Current.Logger; - ProfilingLogger = Current.ProfilingLogger; - Services = Current.Services; - } - - /// - /// Empty constructor, uses Singleton to resolve the UmbracoContext. - /// - protected UmbracoControl() - : this(Current.UmbracoContext, Current.Services) - { } - - /// - /// Returns an UmbracoHelper object - /// - public UmbracoHelper Umbraco { get; } - - /// - /// Gets the logger. - /// - public ILogger Logger { get; } - - /// - /// Gets the profiling logger. - /// - public IProfilingLogger ProfilingLogger { get; } - - /// - /// Gets the Umbraco context. - /// - public UmbracoContext UmbracoContext { get; } - - /// - /// Gets the services context. - /// - protected ServiceContext Services { get; } - - /// - /// Gets a Url helper. - /// - /// This URL helper is created without any route data and an empty request context. - public UrlHelper Url => _url ?? (_url = new UrlHelper(Context.Request.RequestContext)); - } -} diff --git a/src/Umbraco.Web/UI/Controls/UmbracoUserControl.cs b/src/Umbraco.Web/UI/Controls/UmbracoUserControl.cs deleted file mode 100644 index f4cd7f1b50..0000000000 --- a/src/Umbraco.Web/UI/Controls/UmbracoUserControl.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Web.Mvc; -using System.Web.UI; -using Umbraco.Core.Cache; -using Umbraco.Core.Composing; -using Umbraco.Core.Logging; -using Umbraco.Core.Services; -using Umbraco.Web.Security; -using Umbraco.Web.UI.Pages; -using Current = Umbraco.Web.Composing.Current; - -namespace Umbraco.Web.UI.Controls -{ - /// - /// A base class for all Presentation UserControls to inherit from - /// - public abstract class UmbracoUserControl : UserControl - { - private ClientTools _clientTools; - private UrlHelper _url; - - /// - /// Default constructor - /// - /// - /// - protected UmbracoUserControl(UmbracoContext umbracoContext, ServiceContext services) - { - if (umbracoContext == null) throw new ArgumentNullException(nameof(umbracoContext)); - UmbracoContext = umbracoContext; - Umbraco = new UmbracoHelper(umbracoContext, services); - Members = Current.Factory.GetInstance(); - - // todo inject somehow - Logger = Current.Logger; - ProfilingLogger = Current.ProfilingLogger; - Services = Current.Services; - } - - /// - /// Empty constructor, uses Singleton to resolve the UmbracoContext - /// - protected UmbracoUserControl() - : this(Current.UmbracoContext, Current.Services) - { } - - // for debugging purposes - internal Guid InstanceId { get; } = Guid.NewGuid(); - - /// - /// Gets the Umbraco helper. - /// - public UmbracoHelper Umbraco { get; } - - /// - /// Gets the membership helper; - /// - public MembershipHelper Members { get; } - - /// - /// Gets the web security helper. - /// - public WebSecurity Security => UmbracoContext.Security; - - /// - /// Gets the logger. - /// - public ILogger Logger { get; } - - /// - /// Gets the ProfilingLogger. - /// - public IProfilingLogger ProfilingLogger { get; } - - /// - /// Gets the Umbraco context. - /// - public UmbracoContext UmbracoContext { get; } - - /// - /// Gets the services context. - /// - public ServiceContext Services { get; } - - /// - /// Gets an instance of ClientTools for access to the pages client API. - /// - public ClientTools ClientTools - { - get - { - var page = Page as BasePage; - return _clientTools ?? (_clientTools = page != null ? page.ClientTools : new ClientTools(Page)); - } - } - - /// - /// Gets a Url helper. - /// - /// This URL helper is created without any route data and an empty request context. - public UrlHelper Url => _url ?? (_url = new UrlHelper(Context.Request.RequestContext)); - } -} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 64a60d824a..bf91933745 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1145,11 +1145,6 @@ - - - - ASPXCodeBehind - ASPXCodeBehind From 31509beb1cb500c77e91650f3d6ddb6525f4e0cb Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 18:17:10 +0000 Subject: [PATCH 026/213] =?UTF-8?q?=F0=9F=99=88=20WOW=20this=20was=20super?= =?UTF-8?q?=20old=20Umbraco=20V3=20days=20of=20=20WebForms=20days?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../umbraco/templateControls/ContentType.cs | 31 -- .../DisableEventValidation.cs | 27 -- .../umbraco/templateControls/Item.cs | 314 ------------------ .../umbraco/templateControls/ItemRenderer.cs | 226 ------------- .../umbraco/templateControls/Macro.cs | 223 ------------- 5 files changed, 821 deletions(-) delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ContentType.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/DisableEventValidation.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ContentType.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ContentType.cs deleted file mode 100644 index cfccac7f39..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ContentType.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.ComponentModel; -using System.Web.UI; -using System.Web.UI.WebControls; - -namespace umbraco.presentation.templateControls -{ - [DefaultProperty("MimeType")] - [ToolboxData("<{0}:ContentType runat=server>")] - public class ContentType : WebControl - { - [Category("Umbraco")] - [DefaultValue("")] - public string MimeType { get; set; } - - protected override void OnPreRender(EventArgs e) - { - if (!String.IsNullOrEmpty(MimeType)) - { - Page.Response.ContentType = MimeType; - } - } - - protected override void Render(HtmlTextWriter writer) - { - - } - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/DisableEventValidation.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/DisableEventValidation.cs deleted file mode 100644 index 1672053023..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/DisableEventValidation.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.ComponentModel; - -namespace umbraco.presentation.templateControls -{ - /// - /// This control disables request validation (equalevant of setting validateRequest to false in page directive) - /// - [ToolboxData("<{0}:DisableRequestValidation runat=\"server\">")] - [Designer("umbraco.presentation.templateControls.ItemDesigner, Umbraco.Web")] - public class DisableRequestValidation : System.Web.UI.WebControls.WebControl - { - protected override void OnInit(EventArgs e) - { - base.OnInit(e); - ((UmbracoDefault)base.Page).ValidateRequest = false; - } - - protected override void Render(System.Web.UI.HtmlTextWriter writer) - { - } - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs deleted file mode 100644 index 8473341ca8..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Item.cs +++ /dev/null @@ -1,314 +0,0 @@ -using System; -using System.Collections; -using System.ComponentModel; -using System.Globalization; -using System.Web; -using System.Linq; -using System.Web.UI; -using System.Web.UI.WebControls; -using Umbraco.Core; -using Umbraco.Core.Services; -using Umbraco.Core.Models; -using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web; -using Umbraco.Web.Actions; -using Umbraco.Web.Composing; -using Umbraco.Web.Macros; - - -namespace umbraco.presentation.templateControls -{ - /// - /// Control that renders an Umbraco item on a page. - /// - [DefaultProperty("Field")] - [ToolboxData("<{0}:Item runat=\"server\">")] - [Designer("umbraco.presentation.templateControls.ItemDesigner, Umbraco.Web")] - public class Item : CompositeControl - { - - #region Private Fields - - /// The item's unique ID on the page. - private readonly int m_ItemId; - public AttributeCollectionAdapter LegacyAttributes; - #endregion - - /// - /// Used by the UmbracoHelper to assign an IPublishedContent to the Item which allows us to pass this in - /// to the 'item' ctor so that it renders with the new API instead of the old one. - /// - internal IPublishedContent ContentItem { get; private set; } - - #region Public Control Properties - - /// - /// Gets or sets the field name. - /// - /// The field name. - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue("")] - [Localizable(true)] - public string Field - { - get { return (string)ViewState["Field"] ?? String.Empty; } - set { ViewState["Field"] = value; } - } - - /// - /// Gets or sets the node id expression. - /// - /// The node id expression. - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue("")] - [Localizable(true)] - public string NodeId - { - get { return (string)ViewState["NodeId"] ?? String.Empty; } - set { ViewState["NodeId"] = value; } - } - - /// - /// Gets or sets the text to display if the control is empty. - /// - /// The text to display if the control is empty. - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue("")] - [Localizable(true)] - public string TextIfEmpty - { - get { return (string)ViewState["TextIfEmpty"] ?? String.Empty; } - set { ViewState["TextIfEmpty"] = value; } - } - - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue("")] - [Localizable(true)] - public bool DebugMode - { - get { return ((ViewState["DebugMode"] == null) ? false : (bool)ViewState["DebugMode"]); } - set { ViewState["DebugMode"] = value; } - } - - public ItemRenderer Renderer { get; set; } - - #endregion - - #region Public Readonly Properties - - /// - /// Gets the item's unique ID on the page. - /// - /// The item id. - public int ItemId - { - get { return m_ItemId; } - } - - /// - /// Gets the Umbraco page elements. - /// - /// The Umbraco page elements. - public Hashtable PageElements - { - get - { - return Context.Items["pageElements"] as Hashtable; - } - } - - #endregion - - #region Public Constructors - - /// - /// Initializes a new instance of the class. - /// - public Item() - { - Renderer = ItemRenderer.Instance; - } - - /// - /// Internal ctor used to assign an IPublishedContent object. - /// - /// - internal Item(IPublishedContent contentItem) - :this() - { - ContentItem = contentItem; - } - - #endregion - - #region Overriden Control Methods - - /// - /// Raises the event. - /// - /// An object that contains the event data. - protected override void OnInit(EventArgs e) - { - Attributes.Add("field", Field); - LegacyAttributes = new AttributeCollectionAdapter(Attributes); - Renderer.Init(this); - - base.OnInit(e); - } - - /// - /// Raises the event. - /// - /// The object that contains the event data. - protected override void OnLoad(EventArgs e) - { - Renderer.Load(this); - - base.OnLoad(e); - } - - /// - /// Writes the content - /// to the specified object, for display on the client. - /// - /// - /// An that represents - /// the output stream to render HTML content on the client. - /// - protected override void Render(HtmlTextWriter writer) - { - Renderer.Render(this, writer); - } - - #endregion - - #region Helper Functions - - /// - /// Gets the parsed node id. As a nodeid on a item element can be null, an integer or even a squarebracket syntax, this helper method - /// is handy for getting the exact parsed nodeid back. - /// - /// The parsed nodeid, the id of the current page OR null if it's not specified - public int? GetParsedNodeId() - { - if (!String.IsNullOrEmpty(NodeId)) - { - string tempNodeId = MacroRenderer.ParseAttribute(PageElements, NodeId); - int nodeIdInt = 0; - if (int.TryParse(tempNodeId, out nodeIdInt)) - { - return nodeIdInt; - } - } - else if (UmbracoContext.Current.PageId != null) - { - return UmbracoContext.Current.PageId.Value; - } - return null; - } - - - /// - /// Gets a value indicating whether this control is inside the form tag. - /// - /// true if this control is inside the form tag; otherwise, false. - protected virtual bool IsInsideFormTag() - { - // check if this control has an ancestor that is the page form - for (Control parent = this.Parent; parent != null; parent = parent.Parent) - if (parent == Page.Form) - return true; - - return false; - } - - /// - /// Returns a that represents the current . - /// - /// - /// A that represents the current . - /// - public override string ToString() - { - return String.Format("Item {0} (NodeId '{1}' : {2})", ItemId, NodeId, Field); - } - - #endregion - - #region Field Information Functions - - static string FindAttribute(IDictionary attributes, string key) - { - key = key.ToLowerInvariant(); - var attributeValue = attributes.Contains(key) ? attributes[key].ToString() : string.Empty; - return MacroRenderer.ParseAttribute(null, attributeValue); - } - - /// - /// Determines whether the field is a dictionary item. - /// - /// true if the field is a dictionary item; otherwise, false. - protected virtual bool FieldIsDictionaryItem() - { - return FindAttribute(new AttributeCollectionAdapter(Attributes), "field").StartsWith("#"); - } - - /// - /// Determines whether the field is recursive. - /// - /// true if the field is recursive; otherwise, false. - protected virtual bool FieldIsRercursive() - { - return FindAttribute(new AttributeCollectionAdapter(Attributes), "recursive") == "true"; - } - - - /// - /// Gets a value indicating whether the current item is editable by the current user. - /// - /// true if the current item is editable by the current user; otherwise, false. - protected virtual bool FieldEditableWithUserPermissions() - { - var u = UmbracoContext.Current.Security.CurrentUser; - if (u == null) return false; - var permission = Current.Services.UserService.GetPermissions(u, PageElements["path"].ToString()); - - return permission.AssignedPermissions.Contains(ActionUpdate.ActionLetter.ToString(CultureInfo.InvariantCulture), StringComparer.Ordinal); - } - - #endregion - } - - public class ItemDesigner : System.Web.UI.Design.ControlDesigner { - - private Item m_control; - - public override string GetDesignTimeHtml() - { - m_control = this.Component as Item; - return returnMarkup(String.Format("Getting '{0}'", m_control.Field)); - } - - private string returnMarkup(string message) - { - return "" + message + ""; - } - - protected override string GetErrorDesignTimeHtml(Exception e) - { - if (this.Component != null) { - m_control = this.Component as Item; - } - - if (m_control != null && !String.IsNullOrEmpty(m_control.Field)) - { - return returnMarkup(String.Format("Getting '{0}'", m_control.Field)); - } - else { return returnMarkup("Please add a Field property"); } - } - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs deleted file mode 100644 index 67e82b3822..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/ItemRenderer.cs +++ /dev/null @@ -1,226 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Web; -using System.Web.UI; -using System.Xml; -using Umbraco.Core.Macros; -using Umbraco.Web.Templates; -using Umbraco.Web.Composing; -using Umbraco.Web.Macros; - -namespace umbraco.presentation.templateControls -{ - public class ItemRenderer - { - public readonly static ItemRenderer Instance = new ItemRenderer(); - /// - /// Initializes a new instance of the class. - /// - protected ItemRenderer() - { } - - /// - /// Renders the specified item. - /// - /// The item. - /// The writer. - public virtual void Render(Item item, HtmlTextWriter writer) - { - if (item.DebugMode) - { - writer.AddAttribute(HtmlTextWriterAttribute.Title, string.Format("Field Tag: '{0}'", item.Field)); - writer.AddAttribute("style", "border: 1px solid #fc6;"); - writer.RenderBeginTag(HtmlTextWriterTag.Div); - } - - try - { - StringWriter renderOutputWriter = new StringWriter(); - HtmlTextWriter htmlWriter = new HtmlTextWriter(renderOutputWriter); - foreach (Control control in item.Controls) - { - try - { - control.RenderControl(htmlWriter); - } - catch (Exception renderException) - { - // TODO: Validate that the current control is within the scope of a form control - // Even controls that are inside this scope, can produce this error in async postback. - HttpContext.Current.Trace.Warn("ItemRenderer", - String.Format("Error rendering control {0} of {1}.", control.ClientID, item), renderException); - } - } - - // parse macros and execute the XSLT transformation on the result if not empty - string renderOutput = renderOutputWriter.ToString(); - renderOutput = renderOutput.Trim().Length == 0 ? string.Empty : renderOutput; - // handle text before/after - renderOutput = AddBeforeAfterText(renderOutput, FindAttribute(item.LegacyAttributes, "insertTextBefore"), FindAttribute(item.LegacyAttributes, "insertTextAfter")); - string finalResult = renderOutput.Trim().Length > 0 ? renderOutput : GetEmptyText(item); - - //Don't parse urls if a content item is assigned since that is taken care - // of with the value converters - if (item.ContentItem == null) - { - writer.Write(TemplateUtilities.ResolveUrlsFromTextString(finalResult)); - } - else - { - writer.Write(finalResult); - } - - } - catch (Exception renderException) - { - HttpContext.Current.Trace.Warn("ItemRenderer", String.Format("Error rendering {0}.", item), renderException); - } - finally - { - if (item.DebugMode) - { - writer.RenderEndTag(); - } - } - } - - static string FindAttribute(IDictionary attributes, string key) - { - key = key.ToLowerInvariant(); - var attributeValue = attributes.Contains(key) ? attributes[key].ToString() : string.Empty; - return MacroRenderer.ParseAttribute(null, attributeValue); - } - - /// - /// Renders the field contents. - /// Checks via the NodeId attribute whether to fetch data from another page than the current one. - /// - /// A string of field contents (macros not parsed) - protected virtual string GetFieldContents(Item item) - { - var tempElementContent = string.Empty; - - // if a nodeId is specified we should get the data from another page than the current one - if (string.IsNullOrEmpty(item.NodeId) == false) - { - var tempNodeId = item.GetParsedNodeId(); - if (tempNodeId != null && tempNodeId.Value != 0) - { - //moved the following from the catch block up as this will allow fallback options alt text etc to work - // stop using GetXml - //var cache = Umbraco.Web.UmbracoContext.Current.ContentCache.InnerCache as PublishedContentCache; - //if (cache == null) throw new InvalidOperationException("Unsupported IPublishedContentCache, only the Xml one is supported."); - //var xml = cache.GetXml(Umbraco.Web.UmbracoContext.Current, Umbraco.Web.UmbracoContext.Current.InPreviewMode); - //var itemPage = new page(xml.GetElementById(tempNodeId.ToString())); - var c = Umbraco.Web.UmbracoContext.Current.ContentCache.GetById(tempNodeId.Value); - var itemPage = new page(c); - - tempElementContent = - new item(item.ContentItem, itemPage.Elements, item.LegacyAttributes).FieldContent; - } - } - else - { - // gets the field content from the current page (via the PageElements collection) - tempElementContent = - new item(item.ContentItem, item.PageElements, item.LegacyAttributes).FieldContent; - } - - return tempElementContent; - } - - /// - /// Inits the specified item. To be called from the OnInit method of Item. - /// - /// The item. - public virtual void Init(Item item) - { } - - /// - /// Loads the specified item. To be called from the OnLoad method of Item. - /// - /// The item. - public virtual void Load(Item item) - { - using (Current.ProfilingLogger.DebugDuration(string.Format("Item: {0}", item.Field))) - { - ParseMacros(item); - } - } - - /// - /// Parses the macros inside the text, by creating child elements for each item. - /// - /// The item. - protected virtual void ParseMacros(Item item) - { - // do nothing if the macros have already been rendered - if (item.Controls.Count > 0) - return; - - var elementText = GetFieldContents(item); - - //Don't parse macros if there's a content item assigned since the content value - // converters take care of that, just add the already parsed text - if (item.ContentItem != null) - { - item.Controls.Add(new LiteralControl(elementText)); - } - else - { - using (Current.ProfilingLogger.DebugDuration("Parsing Macros")) - { - - MacroTagParser.ParseMacros( - elementText, - - //callback for when a text block is parsed - textBlock => item.Controls.Add(new LiteralControl(textBlock)), - - //callback for when a macro is parsed: - (macroAlias, attributes) => - { - var macroControl = new Macro - { - Alias = macroAlias - }; - foreach (var i in attributes.Where(i => macroControl.Attributes[i.Key] == null)) - { - macroControl.Attributes.Add(i.Key, i.Value); - } - item.Controls.Add(macroControl); - }); - } - } - - } - - protected string AddBeforeAfterText(string text, string before, string after) - { - if (!String.IsNullOrEmpty(text)) - { - if (!String.IsNullOrEmpty(before)) - text = String.Format("{0}{1}", HttpContext.Current.Server.HtmlDecode(before), text); - if (!String.IsNullOrEmpty(after)) - text = String.Format("{0}{1}", text, HttpContext.Current.Server.HtmlDecode(after)); - } - - return text; - } - - /// - /// Gets the text to display if the field contents are empty. - /// - /// The item. - /// The text to display. - protected virtual string GetEmptyText(Item item) - { - return item.TextIfEmpty; - } - - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs deleted file mode 100644 index 0d54ce2a02..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/templateControls/Macro.cs +++ /dev/null @@ -1,223 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Collections; -using System.Web; -using Umbraco.Core; -using Umbraco.Core.Configuration; -using Umbraco.Core.Models; -using Umbraco.Web; -using Umbraco.Web.Composing; -using Umbraco.Web.Macros; - -namespace umbraco.presentation.templateControls -{ - - [DefaultProperty("Alias")] - [ToolboxData("<{0}:Macro runat=server>")] - [PersistChildren(false)] - [ParseChildren(true, "Text")] - public class Macro : WebControl, ITextControl - { - public Hashtable MacroAttributes { get; set; } = new Hashtable(); - - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue("")] - [Localizable(true)] - public string Alias - { - get - { - var s = (string)ViewState["Alias"]; - return s ?? string.Empty; - } - - set - { - ViewState["Alias"] = value; - } - } - - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue("")] - [Localizable(true)] - public string Language { - get { - var s = (string)ViewState["Language"]; - return s ?? string.Empty; - } - set { - ViewState["Language"] = value.ToLower(); - } - } - - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue("")] - [Localizable(true)] - public string FileLocation { - get { - var s = (string)ViewState["FileLocation"]; - return s ?? string.Empty; - } - set { - ViewState["FileLocation"] = value.ToLower(); - } - } - [Bindable(true)] - [Category("Umbraco")] - [DefaultValue(RenderEvents.Init)] - [Localizable(true)] - public RenderEvents RenderEvent - { - get - { - var renderEvent = RenderEvents.Init; - if (ViewState["RenderEvent"] != null) - renderEvent = (RenderEvents)ViewState["RenderEvent"]; - return renderEvent; - } - set - { - ViewState["RenderEvent"] = value; - } - } - - // Indicates where to run EnsureChildControls and effectively render the macro - public enum RenderEvents - { - Init, - PreRender, - Render - } - - public IList Exceptions = new List(); - - /// - /// Raises the event. - /// - /// An object that contains the event data. - protected override void OnInit(EventArgs e) { - base.OnInit(e); - - // Create child controls when told to - this is the default - if (RenderEvent == RenderEvents.Init) - EnsureChildControls(); - } - - // Create child controls when told to - new option to render at PreRender - protected override void OnPreRender(EventArgs e) - { - base.OnPreRender(e); - - if (RenderEvent == RenderEvents.PreRender) - EnsureChildControls(); - } - - /// - /// Called by the ASP.NET page framework to notify server controls that use composition-based implementation to create any child controls they contain in preparation for posting back or rendering. - /// - protected override void CreateChildControls() { - // collect all attributes set on the control - var keys = Attributes.Keys; - foreach (string key in keys) - MacroAttributes.Add(key.ToLower(), HttpUtility.HtmlDecode(Attributes[key])); - - if (MacroAttributes.ContainsKey("macroalias") == false && MacroAttributes.ContainsKey("macroAlias") == false) - MacroAttributes.Add("macroalias", Alias); - - // set pageId to int.MinValue if no pageID was found, - // e.g. if the macro was rendered on a custom (non-Umbraco) page - var pageId = UmbracoContext.Current.PageId == null ? int.MinValue : UmbracoContext.Current.PageId.Value; - - if ((string.IsNullOrEmpty(Language) == false && Text != "") || string.IsNullOrEmpty(FileLocation) == false) { - var tempMacro = new MacroModel(); - MacroRenderer.GenerateMacroModelPropertiesFromAttributes(tempMacro, MacroAttributes); - - // executing an inline macro? - // ie the code of the macro is in the control's text body - // ok, this is not supported in v8 anymore - if (string.IsNullOrEmpty(FileLocation)) - throw new NotSupportedException("Inline macros are not supported anymore."); - - // executing an on-disk macro - // it has to be a partial (cshtml or vbhtml) macro in v8 - var extension = System.IO.Path.GetExtension(FileLocation); - if (extension.InvariantEndsWith(".cshtml") == false && extension.InvariantEndsWith(".vbhtml") == false) - throw new NotSupportedException(""); - - tempMacro.MacroSource = FileLocation; - tempMacro.MacroType = MacroTypes.PartialView; - - if (string.IsNullOrEmpty(Attributes["Cache"]) == false) - { - int cacheDuration; - if (int.TryParse(Attributes["Cache"], out cacheDuration)) - tempMacro.CacheDuration = cacheDuration; - else - Context.Trace.Warn("Template", "Cache attribute is in incorect format (should be an integer)."); - } - - var renderer = new MacroRenderer(Current.ProfilingLogger); - var c = renderer.Render(tempMacro, (Hashtable) Context.Items["pageElements"], pageId).GetAsControl(); - if (c != null) - { - Exceptions = renderer.Exceptions; - Controls.Add(c); - } - else - { - Context.Trace.Warn("Template", "Result of inline macro scripting is null"); - } - } - else - { - var m = Current.Services.MacroService.GetByAlias(Alias); - if (m == null) return; - - var tempMacro = new MacroModel(m); - try - { - var renderer = new MacroRenderer(Current.ProfilingLogger); - var c = renderer.Render(tempMacro, (Hashtable)Context.Items["pageElements"], pageId, MacroAttributes).GetAsControl(); - if (c != null) - Controls.Add(c); - else - Context.Trace.Warn("Template", "Result of macro " + tempMacro.Name + " is null"); - } - catch (Exception ee) - { - Context.Trace.Warn("Template", "Error adding macro " + tempMacro.Name, ee); - throw; - } - } - } - - /// - /// Renders the control to the specified HTML writer. - /// - /// The object that receives the control content. - protected override void Render(HtmlTextWriter writer) - { - // Create child controls when told to - do it here anyway as it has to be done - EnsureChildControls(); - - var isDebug = GlobalSettings.DebugMode && (Context.Request.GetItemAsString("umbdebugshowtrace") != "" || Context.Request.GetItemAsString("umbdebug") != ""); - if (isDebug) - { - writer.Write("
", Alias); - } - RenderChildren(writer); - if (isDebug) - { - writer.Write("
"); - } - } - - public string Text { get; set; } = string.Empty; - } -} From 0480242532498af5f7f79d0e028ff5f1ff4f91b7 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Wed, 23 Jan 2019 18:56:33 +0000 Subject: [PATCH 027/213] =?UTF-8?q?Some=20sneaky=20MasterPages=20kill=20th?= =?UTF-8?q?e=20last=20of=20them=20off=20with=20fire=20=F0=9F=94=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Umbraco/masterpages/Default.Master.cs | 11 - .../masterpages/Default.Master.designer.cs | 15 -- .../masterpages/UmbracoDialog.master.cs | 11 - .../UmbracoDialog.master.designer.cs | 24 -- .../Umbraco/masterpages/UmbracoPage.master.cs | 11 - .../UmbracoPage.master.designer.cs | 24 -- .../Umbraco/masterpages/umbracoDialog.Master | 35 --- .../Umbraco/masterpages/umbracoPage.Master | 40 --- .../umbraco/masterpages/default.Master.cs | 35 --- .../masterpages/umbracoDialog.Master.cs | 161 ------------ .../umbraco/masterpages/umbracoPage.Master.cs | 239 ------------------ 11 files changed, 606 deletions(-) delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.designer.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.designer.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.designer.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/umbracoDialog.Master delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/umbracoPage.Master delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoDialog.Master.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.cs b/src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.cs deleted file mode 100644 index 33daac7b32..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace Umbraco.Web.UI.Umbraco.Masterpages -{ - public partial class Default : global::umbraco.presentation.masterpages._default - { - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.designer.cs b/src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.designer.cs deleted file mode 100644 index 68f54a4fab..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/Default.Master.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.Masterpages { - - - public partial class Default { - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.cs b/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.cs deleted file mode 100644 index 33d1c9f79b..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace Umbraco.Web.UI.Umbraco.Masterpages -{ - public partial class UmbracoDialog : global::umbraco.presentation.masterpages.umbracoDialog - { - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.designer.cs b/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.designer.cs deleted file mode 100644 index 38f9e1f6bc..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoDialog.master.designer.cs +++ /dev/null @@ -1,24 +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.Masterpages { - - - public partial class UmbracoDialog { - - /// - /// DocType control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder DocType; - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.cs b/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.cs deleted file mode 100644 index e45cf3e68b..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace Umbraco.Web.UI.Umbraco.Masterpages -{ - public partial class UmbracoPage : global::umbraco.presentation.masterpages.umbracoPage - { - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.designer.cs b/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.designer.cs deleted file mode 100644 index 7a24953c3f..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/UmbracoPage.master.designer.cs +++ /dev/null @@ -1,24 +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.Masterpages { - - - public partial class UmbracoPage { - - /// - /// DocType control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder DocType; - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/umbracoDialog.Master b/src/Umbraco.Web.UI/Umbraco/masterpages/umbracoDialog.Master deleted file mode 100644 index d74a41d637..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/umbracoDialog.Master +++ /dev/null @@ -1,35 +0,0 @@ -<%@ Master Language="C#" AutoEventWireup="True" CodeBehind="UmbracoDialog.master.cs" Inherits="Umbraco.Web.UI.Umbraco.Masterpages.UmbracoDialog" %> - - - - - -<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> -<%@ Register TagPrefix="umbClient" Namespace="Umbraco.Web.UI.Bundles" Assembly="Umbraco.Web" %> -<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web.UI.JavaScript" Assembly="Umbraco.Web" %> - - - - - - - - - - - - - - - - - - -
- - - -
- - - diff --git a/src/Umbraco.Web.UI/Umbraco/masterpages/umbracoPage.Master b/src/Umbraco.Web.UI/Umbraco/masterpages/umbracoPage.Master deleted file mode 100644 index 380ed3d898..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/masterpages/umbracoPage.Master +++ /dev/null @@ -1,40 +0,0 @@ -<%@ Master Language="C#" AutoEventWireup="True" CodeBehind="UmbracoPage.master.cs" Inherits="Umbraco.Web.UI.Umbraco.Masterpages.UmbracoPage" %> - - - - - -<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %> -<%@ Register TagPrefix="umbClient" Namespace="Umbraco.Web.UI.Bundles" Assembly="Umbraco.Web" %> -<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web.UI.JavaScript" Assembly="Umbraco.Web" %> - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs deleted file mode 100644 index c28a218246..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/default.Master.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Web.Mvc; -using System.Web.UI; -using Umbraco.Web; -using System.IO; - -namespace umbraco.presentation.masterpages -{ - public partial class _default : MasterPage - { - - protected override void Render(HtmlTextWriter writer) - { - // get base output - StringWriter baseWriter = new StringWriter(); - base.Render(new HtmlTextWriter(baseWriter)); - string baseOutput = baseWriter.ToString(); - - // add custom umbraco namespace (required for events on custom tags in IE) - baseOutput = baseOutput.Replace(" - /// ContentPlaceHolderDefault control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder ContentPlaceHolderDefault; - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoDialog.Master.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoDialog.Master.cs deleted file mode 100644 index b7ec63576b..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoDialog.Master.cs +++ /dev/null @@ -1,161 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Web; -using System.Web.UI; -using System.Web.UI.WebControls; -using Umbraco.Core.IO; -using Umbraco.Web.UI.JavaScript; - -namespace umbraco.presentation.masterpages -{ - public partial class umbracoDialog : System.Web.UI.MasterPage - { - - public bool reportModalSize { get; set; } - public static new event MasterPageLoadHandler Load; - public new static event MasterPageLoadHandler Init; - - protected void Page_Load(object sender, EventArgs e) - { - ClientLoader.DataBind(); - ScriptManager.RegisterStartupScript(Page, Page.GetType(), "setRoot", "UmbClientMgr.setUmbracoPath(\"" + IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "\");", true); - FireOnLoad(e); - } - - protected override void OnInit(EventArgs e) - { - base.OnInit(e); - - if (Init != null) - { - Init(this, e); - } - } - - - protected virtual void FireOnLoad(EventArgs e) - { - if (Load != null) - { - Load(this, e); - } - } - - /// - /// Head1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.HtmlControls.HtmlHead Head1; - - /// - /// ClientLoader control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected UmbracoClientDependencyLoader ClientLoader; - - /// - /// CssInclude1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.CssInclude CssInclude1; - - /// - /// JsInclude1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude1; - - /// - /// JsInclude3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude3; - - /// - /// JsInclude6 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude6; - - /// - /// JsInclude4 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude4; - - /// - /// JsInclude2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude2; - - /// - /// head control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder head; - - /// - /// 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; - - /// - /// ScriptManager1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.ScriptManager ScriptManager1; - - /// - /// body control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder body; - - /// - /// footer control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder footer; - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs deleted file mode 100644 index 584ad4ca7f..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/masterpages/umbracoPage.Master.cs +++ /dev/null @@ -1,239 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Web; -using System.Web.Mvc; -using System.Web.UI; -using System.Web.UI.WebControls; - -//This is only in case an upgrade goes wrong and the the /masterpages/ files are not copied over -//which would result in an error. so we have kept the old namespaces intact with references to new ones -using StackExchange.Profiling; -using Umbraco.Core.Configuration; -using Umbraco.Core.Profiling; -using Umbraco.Web; -using Umbraco.Web.UI.JavaScript; -using mp = umbraco.presentation.masterpages; -namespace umbraco.presentation.umbraco.masterpages -{ - public class umbracoPage : mp.umbracoPage { } - public class umbracoDialog : mp.umbracoDialog { } -} - -namespace umbraco.presentation.masterpages -{ - public delegate void MasterPageLoadHandler(object sender, System.EventArgs e); - - public partial class umbracoPage : System.Web.UI.MasterPage - { - - public new static event MasterPageLoadHandler Load; - public new static event MasterPageLoadHandler Init; - - protected void Page_Load(object sender, EventArgs e) - { - ClientLoader.DataBind(); - FireOnLoad(e); - } - - - protected override void Render(HtmlTextWriter writer) - { - // get base output - var baseWriter = new StringWriter(); - base.Render(new HtmlTextWriter(baseWriter)); - var baseOutput = baseWriter.ToString(); - - // profiling - if (string.IsNullOrEmpty(Request.QueryString["umbDebug"]) == false && GlobalSettings.DebugMode) - { - var htmlHelper = new HtmlHelper(new ViewContext(), new ViewPage()); - baseOutput = baseOutput.Replace("", htmlHelper.RenderProfiler() + ""); - } - - // write modified output - writer.Write(baseOutput); - } - - protected override void OnInit(EventArgs e) - { - base.OnInit(e); - - if (Init != null) - { - Init(this, e); - } - } - - - protected virtual void FireOnLoad(EventArgs e) - { - if (Load != null) - { - Load(this, e); - } - } - - /// - /// ClientLoader control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected UmbracoClientDependencyLoader ClientLoader; - - /// - /// CssInclude1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.CssInclude CssInclude1; - - /// - /// CssInclude2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.CssInclude CssInclude2; - - /// - /// JsInclude1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude1; - - /// - /// JsInclude2 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude2; - - /// - /// JsInclude8 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude8; - - /// - /// JsInclude9 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude9; - - /// - /// JsInclude4 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude4; - - /// - /// JsInclude5 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude5; - - /// - /// JsInclude6 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude6; - - /// - /// JsInclude7 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude7; - - /// - /// JsInclude3 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsInclude3; - - /// - /// JsIncludeHotkeys control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::ClientDependency.Core.Controls.JsInclude JsIncludeHotkeys; - - /// - /// head control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder head; - - /// - /// 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; - - /// - /// ScriptManager1 control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.ScriptManager ScriptManager1; - - /// - /// body control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder body; - - /// - /// footer control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.ContentPlaceHolder footer; - } -} From b389e6c07feb13de540762e87265fa5808056400 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 24 Jan 2019 08:16:55 +0100 Subject: [PATCH 028/213] 3396 - don't let user determine whether to publish mandatory languages on first publish. All mandatory languages with data is saved. If a mandatory language does not have data we cannot publish anything. --- .../src/views/content/overlays/publish.controller.js | 3 ++- .../src/views/content/overlays/publish.html | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js index 9074834ee6..74d80b6ab9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js @@ -109,8 +109,9 @@ if (!vm.hasPristineVariants) { vm.hasPristineVariants = pristineVariantFilter(variant); } - + if(vm.isNew && hasAnyData(variant)){ + variant.publish = true; variant.save = true; } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html index b33b7ccbfc..3fd3015de2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html @@ -18,6 +18,7 @@ type="checkbox" ng-model="variant.publish" ng-change="vm.changeSelection(variant)" + ng-disabled="vm.isNew && variant.language.isMandatory" style="margin-right: 8px;" val-server-field="{{variant.htmlId}}" />
From cc897285c9a9a4786108930b6df8ea378c8357f6 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 24 Jan 2019 08:31:42 +0100 Subject: [PATCH 029/213] 3396 - Force publish for all mandatory langauges that has not yet beed published --- .../src/views/content/overlays/publish.controller.js | 12 +++++++++--- .../src/views/content/overlays/publish.html | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js index 74d80b6ab9..a86a636e9e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js @@ -110,9 +110,15 @@ vm.hasPristineVariants = pristineVariantFilter(variant); } - if(vm.isNew && hasAnyData(variant)){ - variant.publish = true; - variant.save = true; + if(hasAnyData(variant)){ + if(vm.isNew || variant.publishDate == null){ + variant.publish = true; + variant.save = true; + } + }else{ + variant.publish = false; + variant.save = false; + variant.canSave = false; } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html index 3fd3015de2..364ed47361 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.html @@ -18,7 +18,7 @@ type="checkbox" ng-model="variant.publish" ng-change="vm.changeSelection(variant)" - ng-disabled="vm.isNew && variant.language.isMandatory" + ng-disabled="(vm.isNew && variant.language.isMandatory) || !variant.canSave" style="margin-right: 8px;" val-server-field="{{variant.htmlId}}" />
From 5842337d02385ce07c958f827f93c538a587e420 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 24 Jan 2019 09:42:49 +0100 Subject: [PATCH 030/213] 3396 - Fix for when clearing the name again --- .../src/views/content/overlays/publish.controller.js | 8 ++++++-- .../src/views/content/overlays/save.controller.js | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js index a86a636e9e..1c8b302e52 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/publish.controller.js @@ -55,7 +55,11 @@ } function hasAnyData(variant) { - var result = variant.isDirty != null || (variant.name != null && variant.name.length > 0); + + if(variant.name == null || variant.name.length === 0) { + return false; + } + var result = variant.isDirty != null; if(result) return true; @@ -109,7 +113,7 @@ if (!vm.hasPristineVariants) { vm.hasPristineVariants = pristineVariantFilter(variant); } - + if(hasAnyData(variant)){ if(vm.isNew || variant.publishDate == null){ variant.publish = true; diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js index 8d21234aee..9d3a8a87e5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/save.controller.js @@ -32,7 +32,10 @@ } function hasAnyData(variant) { - var result = variant.isDirty != null || (variant.name != null && variant.name.length > 0); + if(variant.name == null || variant.name.length === 0) { + return false; + } + var result = variant.isDirty != null; if(result) return true; From 9e0d2e58732c4ac00baa369451da5e855c39cc08 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Thu, 24 Jan 2019 11:37:28 +0100 Subject: [PATCH 031/213] Revert "Remove obsoleted RelatedLinks picker (replaced by Multi URL Picker)" This reverts commit fedf0c78de6d2ad365db1c112c22af13abd7b9fb. --- src/Umbraco.Core/Constants-PropertyEditors.cs | 7 +- .../Migrations/Install/DatabaseDataCreator.cs | 4 +- .../V_8_0_0/PropertyEditorsMigration.cs | 1 + .../Composing/TypeLoaderTests.cs | 2 +- .../Services/ContentServiceTests.cs | 2 +- .../TestHelpers/Entities/MockedContent.cs | 2 +- .../Entities/MockedContentTypes.cs | 2 +- .../Mvc/HtmlHelperExtensionMethodsTests.cs | 25 +++ src/Umbraco.Web/HtmlHelperRenderExtensions.cs | 34 ++++ src/Umbraco.Web/Models/RelatedLink.cs | 11 ++ src/Umbraco.Web/Models/RelatedLinkBase.cs | 18 ++ src/Umbraco.Web/Models/RelatedLinkType.cs | 27 +++ src/Umbraco.Web/Models/RelatedLinks.cs | 42 +++++ .../RelatedLinksConfiguration.cs | 13 ++ .../RelatedLinksConfigurationEditor.cs | 18 ++ .../RelatedLinksPropertyEditor.cs | 16 ++ .../RelatedLinksLegacyValueConverter.cs | 132 ++++++++++++++ .../RelatedLinksValueConverter.cs | 169 ++++++++++++++++++ src/Umbraco.Web/RelatedLinksTypeConverter.cs | 98 ++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 10 ++ 20 files changed, 626 insertions(+), 7 deletions(-) create mode 100644 src/Umbraco.Web/Models/RelatedLink.cs create mode 100644 src/Umbraco.Web/Models/RelatedLinkBase.cs create mode 100644 src/Umbraco.Web/Models/RelatedLinkType.cs create mode 100644 src/Umbraco.Web/Models/RelatedLinks.cs create mode 100644 src/Umbraco.Web/PropertyEditors/RelatedLinksConfiguration.cs create mode 100644 src/Umbraco.Web/PropertyEditors/RelatedLinksConfigurationEditor.cs create mode 100644 src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs create mode 100644 src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs create mode 100644 src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs create mode 100644 src/Umbraco.Web/RelatedLinksTypeConverter.cs diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index 8b637fe90e..b9f20fb449 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -118,7 +118,12 @@ namespace Umbraco.Core /// RadioButton list. /// public const string RadioButtonList = "Umbraco.RadioButtonList"; - + + /// + /// Related Links. + /// + public const string RelatedLinks = "Umbraco.RelatedLinks"; + /// /// Slider. /// diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs index 4e0b5dfa0f..f32ea1cb6f 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs @@ -135,7 +135,7 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1047, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1047", SortOrder = 2, UniqueId = new Guid("1EA2E01F-EBD8-4CE1-8D71-6B1149E63548"), Text = "Member Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1048, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1048", SortOrder = 2, UniqueId = new Guid("135D60E0-64D9-49ED-AB08-893C9BA44AE5"), Text = "Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1049, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1049", SortOrder = 2, UniqueId = new Guid("9DBBCBBB-2327-434A-B355-AF1B84E5010A"), Text = "Multiple Media Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); - _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Multi URL Picker", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); + _database.Insert(Constants.DatabaseSchema.Tables.Node, "id", false, new NodeDto { NodeId = 1050, Trashed = false, ParentId = -1, UserId = -1, Level = 1, Path = "-1,1050", SortOrder = 2, UniqueId = new Guid("B4E3535A-1753-47E2-8568-602CF8CFEE6F"), Text = "Related Links", NodeObjectType = Constants.ObjectTypes.DataType, CreateDate = DateTime.Now }); } private void CreateLockData() @@ -301,7 +301,7 @@ namespace Umbraco.Core.Migrations.Install _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1048, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext" }); _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1049, EditorAlias = Constants.PropertyEditors.Aliases.MediaPicker, DbType = "Ntext", Configuration = "{\"multiPicker\":1}" }); - _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1050, EditorAlias = Constants.PropertyEditors.Aliases.MultiUrlPicker, DbType = "Ntext" }); + _database.Insert(Constants.DatabaseSchema.Tables.DataType, "pk", false, new DataTypeDto { NodeId = 1050, EditorAlias = Constants.PropertyEditors.Aliases.RelatedLinks, DbType = "Ntext" }); } private void CreateRelationTypeData() diff --git a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigration.cs b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigration.cs index 064ffc7228..ee439088be 100644 --- a/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigration.cs +++ b/src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/PropertyEditorsMigration.cs @@ -16,6 +16,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0 RenameDataType(Constants.PropertyEditors.Aliases.MediaPicker + "2", Constants.PropertyEditors.Aliases.MediaPicker); RenameDataType(Constants.PropertyEditors.Aliases.MemberPicker + "2", Constants.PropertyEditors.Aliases.MemberPicker); RenameDataType(Constants.PropertyEditors.Aliases.MultiNodeTreePicker + "2", Constants.PropertyEditors.Aliases.MultiNodeTreePicker); + RenameDataType(Constants.PropertyEditors.Aliases.RelatedLinks + "2", Constants.PropertyEditors.Aliases.RelatedLinks); RenameDataType("Umbraco.TextboxMultiple", Constants.PropertyEditors.Aliases.TextArea, false); RenameDataType("Umbraco.Textbox", Constants.PropertyEditors.Aliases.TextBox, false); } diff --git a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs index add3424599..6b3ce3eb4e 100644 --- a/src/Umbraco.Tests/Composing/TypeLoaderTests.cs +++ b/src/Umbraco.Tests/Composing/TypeLoaderTests.cs @@ -279,7 +279,7 @@ AnotherContentFinder public void GetDataEditors() { var types = _typeLoader.GetDataEditors(); - Assert.AreEqual(39, types.Count()); + Assert.AreEqual(40, types.Count()); } /// diff --git a/src/Umbraco.Tests/Services/ContentServiceTests.cs b/src/Umbraco.Tests/Services/ContentServiceTests.cs index 9490213d62..039bcaed24 100644 --- a/src/Umbraco.Tests/Services/ContentServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentServiceTests.cs @@ -2215,7 +2215,7 @@ namespace Umbraco.Tests.Services Assert.That(sut.GetValue("contentPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")))); Assert.That(sut.GetValue("mediaPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")))); Assert.That(sut.GetValue("memberPicker"), Is.EqualTo(Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")))); - Assert.That(sut.GetValue("multiUrlPicker"), Is.EqualTo("[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]")); + Assert.That(sut.GetValue("relatedLinks"), Is.EqualTo("")); Assert.That(sut.GetValue("tags"), Is.EqualTo("this,is,tags")); } diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs index 19a57d7775..faf4acf8a4 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContent.cs @@ -132,7 +132,7 @@ namespace Umbraco.Tests.TestHelpers.Entities content.SetValue("contentPicker", Udi.Create(Constants.UdiEntityType.Document, new Guid("74ECA1D4-934E-436A-A7C7-36CC16D4095C")).ToString()); content.SetValue("mediaPicker", Udi.Create(Constants.UdiEntityType.Media, new Guid("44CB39C8-01E5-45EB-9CF8-E70AAF2D1691")).ToString()); content.SetValue("memberPicker", Udi.Create(Constants.UdiEntityType.Member, new Guid("9A50A448-59C0-4D42-8F93-4F1D55B0F47D")).ToString()); - content.SetValue("multiUrlPicker", "[{\"name\":\"https://test.com\",\"url\":\"https://test.com\"}]"); + content.SetValue("relatedLinks", ""); content.SetValue("tags", "this,is,tags"); return content; diff --git a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs index d7dcf8e79a..14b967b1c9 100644 --- a/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs +++ b/src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs @@ -370,7 +370,7 @@ namespace Umbraco.Tests.TestHelpers.Entities contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.ContentPicker, ValueStorageType.Integer) { Alias = "contentPicker", Name = "Content Picker", Mandatory = false, SortOrder = 16, DataTypeId = 1046 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MediaPicker, ValueStorageType.Integer) { Alias = "mediaPicker", Name = "Media Picker", Mandatory = false, SortOrder = 17, DataTypeId = 1048 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MemberPicker, ValueStorageType.Integer) { Alias = "memberPicker", Name = "Member Picker", Mandatory = false, SortOrder = 18, DataTypeId = 1047 }); - contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.MultiUrlPicker, ValueStorageType.Nvarchar) { Alias = "multiUrlPicker", Name = "Multi URL Picker", Mandatory = false, SortOrder = 21, DataTypeId = 1050 }); + contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.RelatedLinks, ValueStorageType.Ntext) { Alias = "relatedLinks", Name = "Related Links", Mandatory = false, SortOrder = 21, DataTypeId = 1050 }); contentCollection.Add(new PropertyType(Constants.PropertyEditors.Aliases.Tags, ValueStorageType.Ntext) { Alias = "tags", Name = "Tags", Mandatory = false, SortOrder = 22, DataTypeId = 1041 }); contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); diff --git a/src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs b/src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs index ba19f41e74..cc83dcb1c9 100644 --- a/src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs +++ b/src/Umbraco.Tests/Web/Mvc/HtmlHelperExtensionMethodsTests.cs @@ -29,5 +29,30 @@ namespace Umbraco.Tests.Web.Mvc var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"}); Assert.AreEqual("
hello world
", output.ToHtmlString()); } + + [Test] + public void GetRelatedLinkHtml_Simple() + { + var relatedLink = new Umbraco.Web.Models.RelatedLink { + Caption = "Link Caption", + NewWindow = true, + Link = "https://www.google.com/" + }; + var output = _htmlHelper.GetRelatedLinkHtml(relatedLink); + Assert.AreEqual("Link Caption", output.ToHtmlString()); + } + + [Test] + public void GetRelatedLinkHtml_HtmlAttributes() + { + var relatedLink = new Umbraco.Web.Models.RelatedLink + { + Caption = "Link Caption", + NewWindow = true, + Link = "https://www.google.com/" + }; + var output = _htmlHelper.GetRelatedLinkHtml(relatedLink, new { @class = "test-class"}); + Assert.AreEqual("Link Caption", output.ToHtmlString()); + } } } diff --git a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs index 1186102bc8..626a19a369 100644 --- a/src/Umbraco.Web/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/HtmlHelperRenderExtensions.cs @@ -830,5 +830,39 @@ namespace Umbraco.Web } #endregion + + + #region RelatedLink + + /// + /// Renders an anchor element for a RelatedLink instance. + /// Format: <a href="relatedLink.Link" target="_blank/_self">relatedLink.Caption</a> + /// + /// The HTML helper instance that this method extends. + /// The RelatedLink instance + /// An anchor element + public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink) + { + return htmlHelper.GetRelatedLinkHtml(relatedLink, null); + } + + /// + /// Renders an anchor element for a RelatedLink instance, accepting htmlAttributes. + /// Format: <a href="relatedLink.Link" target="_blank/_self" htmlAttributes>relatedLink.Caption</a> + /// + /// The HTML helper instance that this method extends. + /// The RelatedLink instance + /// An object that contains the HTML attributes to set for the element. + /// + public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink, object htmlAttributes) + { + var tagBuilder = new TagBuilder("a"); + tagBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); + tagBuilder.MergeAttribute("href", relatedLink.Link); + tagBuilder.MergeAttribute("target", relatedLink.NewWindow ? "_blank" : "_self"); + tagBuilder.InnerHtml = HttpUtility.HtmlEncode(relatedLink.Caption); + return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal)); + } + #endregion } } diff --git a/src/Umbraco.Web/Models/RelatedLink.cs b/src/Umbraco.Web/Models/RelatedLink.cs new file mode 100644 index 0000000000..1e1d7636ad --- /dev/null +++ b/src/Umbraco.Web/Models/RelatedLink.cs @@ -0,0 +1,11 @@ +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Web.Models +{ + public class RelatedLink : RelatedLinkBase + { + public int? Id { get; internal set; } + internal bool IsDeleted { get; set; } + public IPublishedContent Content { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/RelatedLinkBase.cs b/src/Umbraco.Web/Models/RelatedLinkBase.cs new file mode 100644 index 0000000000..c2077ce4a9 --- /dev/null +++ b/src/Umbraco.Web/Models/RelatedLinkBase.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace Umbraco.Web.Models +{ + public abstract class RelatedLinkBase + { + [JsonProperty("caption")] + public string Caption { get; set; } + [JsonProperty("link")] + public string Link { get; set; } + [JsonProperty("newWindow")] + public bool NewWindow { get; set; } + [JsonProperty("isInternal")] + public bool IsInternal { get; set; } + [JsonProperty("type")] + public RelatedLinkType Type { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/RelatedLinkType.cs b/src/Umbraco.Web/Models/RelatedLinkType.cs new file mode 100644 index 0000000000..eec7817ab6 --- /dev/null +++ b/src/Umbraco.Web/Models/RelatedLinkType.cs @@ -0,0 +1,27 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Umbraco +// +// +// Defines the RelatedLinkType type. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace Umbraco.Web.Models +{ + /// + /// The related link type. + /// + public enum RelatedLinkType + { + /// + /// Internal link type + /// + Internal, + + /// + /// External link type + /// + External + } +} diff --git a/src/Umbraco.Web/Models/RelatedLinks.cs b/src/Umbraco.Web/Models/RelatedLinks.cs new file mode 100644 index 0000000000..22cdcd11b6 --- /dev/null +++ b/src/Umbraco.Web/Models/RelatedLinks.cs @@ -0,0 +1,42 @@ +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace Umbraco.Web.Models +{ + [TypeConverter(typeof(RelatedLinksTypeConverter))] + public class RelatedLinks : IEnumerable + { + private readonly string _propertyData; + + private readonly IEnumerable _relatedLinks; + + public RelatedLinks(IEnumerable relatedLinks, string propertyData) + { + _relatedLinks = relatedLinks; + _propertyData = propertyData; + } + + /// + /// Gets the property data. + /// + internal string PropertyData + { + get + { + return this._propertyData; + } + } + + public IEnumerator GetEnumerator() + { + return _relatedLinks.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } +} diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksConfiguration.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksConfiguration.cs new file mode 100644 index 0000000000..5db14c6842 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/RelatedLinksConfiguration.cs @@ -0,0 +1,13 @@ +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + /// + /// Represents the configuration for the related links value editor. + /// + public class RelatedLinksConfiguration + { + [ConfigurationField("max", "Maximum number of links", "number", Description = "Enter the maximum amount of links to be added, enter 0 for unlimited")] + public int Maximum { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksConfigurationEditor.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksConfigurationEditor.cs new file mode 100644 index 0000000000..07ff359a82 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/RelatedLinksConfigurationEditor.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + /// + /// Represents the configuration editor for the related links value editor. + /// + public class RelatedLinksConfigurationEditor : ConfigurationEditor + { + public override IDictionary ToValueEditor(object configuration) + { + var d = base.ToValueEditor(configuration); + d["idType"] = "udi"; + return d; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs new file mode 100644 index 0000000000..b450fcc67f --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs @@ -0,0 +1,16 @@ +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + [DataEditor(Constants.PropertyEditors.Aliases.RelatedLinks, "Related links", "relatedlinks", ValueType = ValueTypes.Json, Icon = "icon-thumbnail-list", Group = "pickers")] + public class RelatedLinksPropertyEditor : DataEditor + { + public RelatedLinksPropertyEditor(ILogger logger) + : base(logger) + { } + + protected override IConfigurationEditor CreateConfigurationEditor() => new RelatedLinksConfigurationEditor(); + } +} diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs new file mode 100644 index 0000000000..6c2a4331d0 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.ValueConverters; +using Umbraco.Core.Services; + +namespace Umbraco.Web.PropertyEditors.ValueConverters +{ + [DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter + public class RelatedLinksLegacyValueConverter : PropertyValueConverterBase + { + private static readonly string[] MatchingEditors = { + Constants.PropertyEditors.Aliases.RelatedLinks + }; + + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly ILogger _logger; + private readonly ServiceContext _services; + + public RelatedLinksLegacyValueConverter(IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, ILogger logger) + { + _umbracoContextAccessor = umbracoContextAccessor; + _services = services; + _logger = logger; + } + + public override bool IsConverter(PublishedPropertyType propertyType) + => MatchingEditors.Contains(propertyType.EditorAlias); + + public override Type GetPropertyValueType(PublishedPropertyType propertyType) + => typeof (JArray); + + public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) + => PropertyCacheLevel.Element; + + public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview) + { + if (source == null) return null; + var sourceString = source.ToString(); + + if (sourceString.DetectIsJson()) + { + try + { + var obj = JsonConvert.DeserializeObject(sourceString); + //update the internal links if we have a context + if (UmbracoContext.Current != null) + { + var helper = new UmbracoHelper(_umbracoContextAccessor.UmbracoContext, _services); + foreach (var a in obj) + { + var type = a.Value("type"); + if (type.IsNullOrWhiteSpace() == false) + { + if (type == "internal") + { + switch (propertyType.EditorAlias) + { + case Constants.PropertyEditors.Aliases.RelatedLinks: + var strLinkId = a.Value("link"); + var udiAttempt = strLinkId.TryConvertTo(); + if (udiAttempt) + { + var content = helper.PublishedContent(udiAttempt.Result); + if (content == null) break; + a["link"] = helper.Url(content.Id); + } + break; + } + } + } + } + } + return obj; + } + catch (Exception ex) + { + _logger.Error(ex, "Could not parse the string '{Json}' to a json object", sourceString); + } + } + + //it's not json, just return the string + return sourceString; + } + + public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object source, bool preview) + { + if (source == null) return null; + var sourceString = source.ToString(); + + if (sourceString.DetectIsJson()) + { + try + { + var obj = JsonConvert.DeserializeObject(sourceString); + + var d = new XmlDocument(); + var e = d.CreateElement("links"); + d.AppendChild(e); + + foreach (dynamic link in obj) + { + var ee = d.CreateElement("link"); + ee.SetAttribute("title", link.title); + ee.SetAttribute("link", link.link); + ee.SetAttribute("type", link.type); + ee.SetAttribute("newwindow", link.newWindow); + + e.AppendChild(ee); + } + + return d.CreateNavigator(); + } + catch (Exception ex) + { + _logger.Error(ex, "Could not parse the string '{Json}' to a json object", sourceString); + } + } + + //it's not json, just return the string + return sourceString; + } + } +} diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs new file mode 100644 index 0000000000..983d122a83 --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.ValueConverters; +using Umbraco.Web.Models; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Web.PropertyEditors.ValueConverters +{ + /// + /// The related links property value converter. + /// + [DefaultPropertyValueConverter(typeof(RelatedLinksLegacyValueConverter), typeof(JsonValueConverter))] + public class RelatedLinksValueConverter : PropertyValueConverterBase + { + private readonly IPublishedSnapshotAccessor _publishedSnapshotAccessor; + private readonly IUmbracoContextAccessor _umbracoContextAccessor; + private readonly ILogger _logger; + + public RelatedLinksValueConverter(IPublishedSnapshotAccessor publishedSnapshotAccessor, IUmbracoContextAccessor umbracoContextAccessor, ILogger logger) + { + _publishedSnapshotAccessor = publishedSnapshotAccessor; + _umbracoContextAccessor = umbracoContextAccessor; + _logger = logger; + } + + /// + /// Checks if this converter can convert the property editor and registers if it can. + /// + /// + /// The property type. + /// + /// + /// The . + /// + public override bool IsConverter(PublishedPropertyType propertyType) + => propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.RelatedLinks); + + public override Type GetPropertyValueType(PublishedPropertyType propertyType) + => typeof (JArray); + + public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) + => PropertyCacheLevel.Element; + + public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview) + { + if (source == null) return null; + var sourceString = source.ToString(); + + var relatedLinksData = JsonConvert.DeserializeObject>(sourceString); + var relatedLinks = new List(); + + foreach (var linkData in relatedLinksData) + { + var relatedLink = new RelatedLink + { + Caption = linkData.Caption, + NewWindow = linkData.NewWindow, + IsInternal = linkData.IsInternal, + Type = linkData.Type, + Link = linkData.Link + }; + + int contentId; + if (int.TryParse(relatedLink.Link, out contentId)) + { + relatedLink.Id = contentId; + relatedLink = CreateLink(relatedLink); + } + else + { + var strLinkId = linkData.Link; + var udiAttempt = strLinkId.TryConvertTo(); + if (udiAttempt.Success && udiAttempt.Result != null) + { + var content = _publishedSnapshotAccessor.PublishedSnapshot.Content.GetById(udiAttempt.Result.Guid); + if (content != null) + { + relatedLink.Id = content.Id; + relatedLink = CreateLink(relatedLink); + relatedLink.Content = content; + } + } + } + + if (relatedLink.IsDeleted == false) + { + relatedLinks.Add(relatedLink); + } + else + { + _logger.Warn("Related Links value converter skipped a link as the node has been unpublished/deleted (Internal Link NodeId: {RelatedLinkNodeId}, Link Caption: '{RelatedLinkCaption}')", relatedLink.Link, relatedLink.Caption); + } + } + + return new RelatedLinks(relatedLinks, sourceString); + } + + private RelatedLink CreateLink(RelatedLink link) + { + var umbracoContext = _umbracoContextAccessor.UmbracoContext; + + if (link.IsInternal && link.Id != null) + { + if (umbracoContext == null) + return null; + + var urlProvider = umbracoContext.UrlProvider; + + link.Link = urlProvider.GetUrl((int)link.Id); + if (link.Link.Equals("#")) + { + link.IsDeleted = true; + link.Link = link.Id.ToString(); + } + else + { + link.IsDeleted = false; + } + } + + return link; + } + + public override object ConvertIntermediateToXPath(IPublishedElement owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + { + if (inter == null) return null; + var sourceString = inter.ToString(); + + if (sourceString.DetectIsJson()) + { + try + { + var obj = JsonConvert.DeserializeObject(sourceString); + + var d = new XmlDocument(); + var e = d.CreateElement("links"); + d.AppendChild(e); + + foreach (dynamic link in obj) + { + var ee = d.CreateElement("link"); + ee.SetAttribute("title", link.title); + ee.SetAttribute("link", link.link); + ee.SetAttribute("type", link.type); + ee.SetAttribute("newwindow", link.newWindow); + + e.AppendChild(ee); + } + + return d.CreateNavigator(); + } + catch (Exception ex) + { + _logger.Error(ex, "Could not parse the string {Json} to a json object", sourceString); + } + } + + //it's not json, just return the string + return sourceString; + } + } +} diff --git a/src/Umbraco.Web/RelatedLinksTypeConverter.cs b/src/Umbraco.Web/RelatedLinksTypeConverter.cs new file mode 100644 index 0000000000..647959b920 --- /dev/null +++ b/src/Umbraco.Web/RelatedLinksTypeConverter.cs @@ -0,0 +1,98 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Linq; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Composing; +using Umbraco.Web.Models; + +namespace Umbraco.Web +{ + public class RelatedLinksTypeConverter : TypeConverter + { + private readonly UmbracoHelper _umbracoHelper; + + public RelatedLinksTypeConverter(UmbracoHelper umbracoHelper) + { + _umbracoHelper = umbracoHelper; + } + + public RelatedLinksTypeConverter() + { + + } + + private static readonly Type[] ConvertableTypes = new[] + { + typeof(JArray) + }; + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + return ConvertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, destinationType)) + || base.CanConvertFrom(context, destinationType); + } + + public override object ConvertTo( + ITypeDescriptorContext context, + CultureInfo culture, + object value, + Type destinationType) + { + var relatedLinks = value as RelatedLinks; + if (relatedLinks == null) + return null; + + if (TypeHelper.IsTypeAssignableFrom(destinationType)) + { + // Conversion to JArray taken from old value converter + + var obj = JsonConvert.DeserializeObject(relatedLinks.PropertyData); + + var umbracoHelper = GetUmbracoHelper(); + + //update the internal links if we have a context + if (umbracoHelper != null) + { + foreach (var a in obj) + { + var type = a.Value("type"); + if (type.IsNullOrWhiteSpace() == false) + { + if (type == "internal") + { + var linkId = a.Value("link"); + var link = umbracoHelper.Url(linkId); + a["link"] = link; + } + } + } + } + return obj; + + } + + return base.ConvertTo(context, culture, value, destinationType); + } + + private UmbracoHelper GetUmbracoHelper() + { + if (_umbracoHelper != null) + return _umbracoHelper; + + if (UmbracoContext.Current == null) + { + Current.Logger.Warn("Cannot create an UmbracoHelper the UmbracoContext is null"); + return null; + } + + //DO NOT assign to _umbracoHelper variable, this is a singleton class and we cannot assign this based on an UmbracoHelper which is request based + return new UmbracoHelper(UmbracoContext.Current, Current.Services); + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 64a60d824a..6736f7512b 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -404,6 +404,10 @@ + + + + @@ -449,6 +453,9 @@ + + + @@ -464,6 +471,7 @@ + @@ -527,6 +535,7 @@ + @@ -851,6 +860,7 @@ + From eef6c783eafb358a5d29eae59021efe6b284190b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Lyngs=C3=B8?= Date: Thu, 24 Jan 2019 11:59:33 +0100 Subject: [PATCH 032/213] updated package-lock.json --- src/Umbraco.Web.UI.Client/package-lock.json | 96 ++++++++++----------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index ed28a93caf..fe657ae470 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -937,7 +937,7 @@ }, "ansi-colors": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { @@ -955,7 +955,7 @@ }, "ansi-escapes": { "version": "3.1.0", - "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", "dev": true }, @@ -1170,7 +1170,7 @@ "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "array-sort": { @@ -1216,7 +1216,7 @@ "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", "dev": true }, "asap": { @@ -1269,7 +1269,7 @@ "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", "dev": true }, "asynckit": { @@ -2379,7 +2379,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -2459,7 +2459,7 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, "continuable-cache": { @@ -2502,7 +2502,7 @@ "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha1-+XJgj/DOrWi4QaFqky0LGDeRgU4=", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", "dev": true }, "core-util-is": { @@ -3425,7 +3425,7 @@ "doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { "esutils": "^2.0.2" @@ -3953,7 +3953,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -3989,7 +3989,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -4153,7 +4153,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true } @@ -4248,7 +4248,7 @@ "eslint-scope": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha1-UL8wcekzi83EMzF5Sgy1M/ATYXI=", + "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", "dev": true, "requires": { "esrecurse": "^4.1.0", @@ -4258,13 +4258,13 @@ "eslint-utils": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", - "integrity": "sha1-moUbqJ7nxGA0b5fPiTnHKYgn5RI=", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", "dev": true }, "eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", "dev": true }, "espree": { @@ -4287,7 +4287,7 @@ "esquery": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", "dev": true, "requires": { "estraverse": "^4.0.0" @@ -4296,7 +4296,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -4356,7 +4356,7 @@ "eventemitter3": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=", + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", "dev": true }, "exec-buffer": { @@ -4571,7 +4571,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", "dev": true, "requires": { "is-number": "^2.1.0", @@ -5891,7 +5891,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -6461,7 +6461,7 @@ "gulp-eslint": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-5.0.0.tgz", - "integrity": "sha1-KiaECV93Syz3kxAmIHjFbMehK1I=", + "integrity": "sha512-9GUqCqh85C7rP9120cpxXuZz2ayq3BZc85pCTuPJS03VQYxne0aWPIXWx6LSvsGPa3uRqtSO537vaugOh+5cXg==", "dev": true, "requires": { "eslint": "^5.0.1", @@ -7415,7 +7415,7 @@ "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { "isarray": "2.0.1" @@ -7566,7 +7566,7 @@ "http-proxy": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=", + "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", "dev": true, "requires": { "eventemitter3": "^3.0.0", @@ -7860,7 +7860,7 @@ "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -8155,7 +8155,7 @@ "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { "is-unc-path": "^1.0.0" @@ -8164,7 +8164,7 @@ "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", "dev": true }, "is-retry-allowed": { @@ -8212,7 +8212,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -8369,7 +8369,7 @@ "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, "json-stable-stringify-without-jsonify": { @@ -8496,7 +8496,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } } @@ -9146,7 +9146,7 @@ "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", "dev": true, "requires": { "kind-of": "^6.0.2" @@ -9327,7 +9327,7 @@ "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { @@ -12855,7 +12855,7 @@ "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", "dev": true }, "posix-character-classes": { @@ -13345,7 +13345,7 @@ "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true }, "qs": { @@ -13541,7 +13541,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { @@ -14039,7 +14039,7 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, "sax": { @@ -14226,7 +14226,7 @@ "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", "dev": true }, "shebang-command": { @@ -14516,7 +14516,7 @@ "debug": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -14796,7 +14796,7 @@ "stream-consume": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha1-0721mMK9CugrjKx6xQsRB6eZbEg=", + "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", "dev": true }, "stream-shift": { @@ -14808,7 +14808,7 @@ "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", "dev": true, "requires": { "date-format": "^1.2.0", @@ -14835,7 +14835,7 @@ "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -14850,7 +14850,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14867,7 +14867,7 @@ "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -15409,7 +15409,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -15573,7 +15573,7 @@ "type-is": { "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=", + "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "dev": true, "requires": { "media-typer": "0.3.0", @@ -15615,7 +15615,7 @@ "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", "dev": true }, "unc-path-regex": { @@ -15777,13 +15777,13 @@ "upath": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha1-NSVll+RqWB20eT0M5H+prr/J+r0=", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -16218,7 +16218,7 @@ "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", "dev": true, "requires": { "async-limiter": "~1.0.0", From 49b2a9a080a390bf07a4c69e51b7cafffac2b176 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 24 Jan 2019 12:17:30 +0100 Subject: [PATCH 033/213] Fixes for search of members + Removed fixme in member that apparently are not necessary after tags refactoring --- src/Umbraco.Core/Cache/HttpRequestAppCache.cs | 2 +- src/Umbraco.Core/Configuration/UmbracoVersion.cs | 2 +- .../Persistence/Repositories/Implement/DataTypeRepository.cs | 2 +- .../Persistence/Repositories/Implement/DocumentRepository.cs | 2 +- src/Umbraco.Web/PublishedContentExtensions.cs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs index a255fea133..0fdf70ac27 100644 --- a/src/Umbraco.Core/Cache/HttpRequestAppCache.cs +++ b/src/Umbraco.Core/Cache/HttpRequestAppCache.cs @@ -31,7 +31,7 @@ namespace Umbraco.Core.Cache ///
/// /// Will use HttpContext.Current. - /// fixme/task: use IHttpContextAccessor NOT HttpContext.Current + /// TODO - https://github.com/umbraco/Umbraco-CMS/issues/4239 - use IHttpContextAccessor NOT HttpContext.Current /// public HttpRequestAppCache() { } diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 7cb1a61cf1..bc5b6993e3 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -81,7 +81,7 @@ namespace Umbraco.Core.Configuration { try { - // fixme/task - stop having version in web.config appSettings + // TODO - https://github.com/umbraco/Umbraco-CMS/issues/4238 - stop having version in web.config appSettings var value = ConfigurationManager.AppSettings["umbracoConfigurationStatus"]; return value.IsNullOrWhiteSpace() ? null : SemVersion.TryParse(value, out var semver) ? semver : null; } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs index f4f0da8bee..0e6ff0310d 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { private readonly Lazy _editors; - // fixme/task - get rid of Lazy injection and fix circular dependencies + // TODO - https://github.com/umbraco/Umbraco-CMS/issues/4237 - get rid of Lazy injection and fix circular dependencies public DataTypeRepository(IScopeAccessor scopeAccessor, AppCaches cache, Lazy editors, ILogger logger) : base(scopeAccessor, cache, logger) { diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 344c0b9489..8bee55060b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -260,7 +260,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override void PersistNewItem(IContent entity) { - // fixme/task - sort out IContent vs Content + // TODO: https://github.com/umbraco/Umbraco-CMS/issues/4234 - sort out IContent vs Content // however, it's not just so we have access to AddingEntity // there are tons of things at the end of the methods, that can only work with a true Content // and basically, the repository requires a Content, not an IContent diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 231aa2a307..1284cf513d 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -954,7 +954,7 @@ namespace Umbraco.Web /// public static IEnumerable Children(this IPublishedContent content, string culture = null) { - if (content == null) throw new ArgumentNullException(nameof(content)); // fixme/task wtf is this? + if (content == null) throw new ArgumentNullException(nameof(content)); return content.Children.WhereIsInvariantOrHasCulture(culture); } From 31a6f2d67c40f78e6f65ff905f7a7b35d5ad4bd4 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 23 Jan 2019 21:22:49 +0100 Subject: [PATCH 034/213] Add runtime hooks for Deploy --- .../Migrations/Install/DatabaseBuilder.cs | 64 ++++++---- .../Persistence/UmbracoDatabaseFactory.cs | 8 +- src/Umbraco.Core/Runtime/CoreRuntime.cs | 10 +- src/Umbraco.Core/RuntimeOptions.cs | 114 ++++++++++++++++++ src/Umbraco.Core/RuntimeState.cs | 8 +- src/Umbraco.Core/RuntimeStateOptions.cs | 40 ------ src/Umbraco.Core/Umbraco.Core.csproj | 2 +- 7 files changed, 172 insertions(+), 74 deletions(-) create mode 100644 src/Umbraco.Core/RuntimeOptions.cs delete mode 100644 src/Umbraco.Core/RuntimeStateOptions.cs diff --git a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs index 4104ce947c..e73fc7453f 100644 --- a/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs +++ b/src/Umbraco.Core/Migrations/Install/DatabaseBuilder.cs @@ -283,48 +283,60 @@ namespace Umbraco.Core.Migrations.Install if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullOrEmptyException(nameof(connectionString)); if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentNullOrEmptyException(nameof(providerName)); - // set the connection string for the new datalayer - var connectionStringSettings = new ConnectionStringSettings(Constants.System.UmbracoConnectionName, connectionString, providerName); + var fileSource = "web.config"; + var fileName = IOHelper.MapPath(Path.Combine(SystemDirectories.Root, fileSource)); - var fileName = IOHelper.MapPath($"{SystemDirectories.Root}/web.config"); var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); - if (xml.Root == null) throw new Exception("Invalid web.config file."); - var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault(); - if (connectionStrings == null) throw new Exception("Invalid web.config file."); + if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root)."); - // honour configSource, if its set, change the xml file we are saving the configuration - // to the one set in the configSource attribute - if (connectionStrings.Attribute("configSource") != null) + var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault(); + if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings)."); + + // handle configSource + var configSourceAttribute = connectionStrings.Attribute("configSource"); + if (configSourceAttribute != null) { - var source = connectionStrings.Attribute("configSource").Value; - var configFile = IOHelper.MapPath($"{SystemDirectories.Root}/{source}"); - logger.Info("Storing ConnectionString in {ConfigFile}", configFile); - if (File.Exists(configFile)) - { - xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); - fileName = configFile; - } + fileSource = configSourceAttribute.Value; + fileName = IOHelper.MapPath(Path.Combine(SystemDirectories.Root, fileSource)); + + if (!File.Exists(fileName)) + throw new Exception($"Invalid configSource \"{fileSource}\" (no such file)."); + + xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace); + if (xml.Root == null) throw new Exception($"Invalid {fileSource} file (no root)."); + connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault(); - if (connectionStrings == null) throw new Exception("Invalid web.config file."); + if (connectionStrings == null) throw new Exception($"Invalid {fileSource} file (no connection strings)."); } - // update connectionString if it exists, or else create a new connectionString - var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == Constants.System.UmbracoConnectionName); + // create or update connection string + var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name")?.Value == Constants.System.UmbracoConnectionName); if (setting == null) { connectionStrings.Add(new XElement("add", new XAttribute("name", Constants.System.UmbracoConnectionName), - new XAttribute("connectionString", connectionStringSettings), + new XAttribute("connectionString", connectionString), new XAttribute("providerName", providerName))); } else { - setting.Attribute("connectionString").Value = connectionString; - setting.Attribute("providerName").Value = providerName; + AddOrUpdateAttribute(setting, "connectionString", connectionString); + AddOrUpdateAttribute(setting, "providerName", providerName); } + // save + logger.Info("Saving connection string to {ConfigFile}.", fileSource); xml.Save(fileName, SaveOptions.DisableFormatting); - logger.Info("Configured a new ConnectionString using the '{ProviderName}' provider.", providerName); + logger.Info("Saved connection string to {ConfigFile}.", fileSource); + } + + private static void AddOrUpdateAttribute(XElement element, string name, string value) + { + var attribute = element.Attribute(name); + if (attribute == null) + element.Add(new XAttribute(name, value)); + else + attribute.Value = value; } internal bool IsConnectionStringConfigured(ConnectionStringSettings databaseSettings) @@ -422,7 +434,7 @@ namespace Umbraco.Core.Migrations.Install _logger.Info("Database configuration status: Started"); var database = scope.Database; - + var message = string.Empty; var schemaResult = ValidateSchema(); @@ -482,7 +494,7 @@ namespace Umbraco.Core.Migrations.Install } _logger.Info("Database upgrade started"); - + // upgrade var upgrader = new UmbracoUpgrader(); upgrader.Execute(_scopeProvider, _migrationBuilder, _keyValueService, _logger, _postMigrations); diff --git a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs index cd6da569c5..aec49b8eb5 100644 --- a/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs +++ b/src/Umbraco.Core/Persistence/UmbracoDatabaseFactory.cs @@ -59,14 +59,18 @@ namespace Umbraco.Core.Persistence /// Used by the other ctor and in tests. public UmbracoDatabaseFactory(string connectionStringName, ILogger logger, Lazy mappers) { - if (string.IsNullOrWhiteSpace(connectionStringName)) throw new ArgumentNullOrEmptyException(nameof(connectionStringName)); + if (string.IsNullOrWhiteSpace(connectionStringName)) + throw new ArgumentNullOrEmptyException(nameof(connectionStringName)); _mappers = mappers ?? throw new ArgumentNullException(nameof(mappers)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); var settings = ConfigurationManager.ConnectionStrings[connectionStringName]; if (settings == null) + { + logger.Debug("Missing connection string, defer configuration."); return; // not configured + } // could as well be // so need to test the values too @@ -74,7 +78,7 @@ namespace Umbraco.Core.Persistence var providerName = settings.ProviderName; if (string.IsNullOrWhiteSpace(connectionString) || string.IsNullOrWhiteSpace(providerName)) { - logger.Debug("Missing connection string or provider name, defer configuration."); + logger.Debug("Empty connection string or provider name, defer configuration."); return; // not configured } diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 13e6aae149..793eb751dd 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -100,6 +100,9 @@ namespace Umbraco.Core.Runtime // throws if not full-trust new AspNetHostingPermission(AspNetHostingPermissionLevel.Unrestricted).Demand(); + // run handlers + RuntimeOptions.DoRuntimeBoot(ProfilingLogger); + // application caches var appCaches = GetAppCaches(); @@ -131,12 +134,17 @@ namespace Umbraco.Core.Runtime composition = new Composition(register, typeLoader, ProfilingLogger, _state, configs); composition.RegisterEssentials(Logger, Profiler, ProfilingLogger, mainDom, appCaches, databaseFactory, typeLoader, _state); + // run handlers + RuntimeOptions.DoRuntimeEssentials(composition, appCaches, typeLoader, databaseFactory); + // register runtime-level services // there should be none, really - this is here "just in case" Compose(composition); - // acquire the main domain, determine our runtime level + // acquire the main domain AcquireMainDom(mainDom); + + // determine our runtime level DetermineRuntimeLevel(databaseFactory, ProfilingLogger); // get composers, and compose diff --git a/src/Umbraco.Core/RuntimeOptions.cs b/src/Umbraco.Core/RuntimeOptions.cs new file mode 100644 index 0000000000..1f89ee6314 --- /dev/null +++ b/src/Umbraco.Core/RuntimeOptions.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Runtime.CompilerServices; +using Umbraco.Core.Cache; +using Umbraco.Core.Components; +using Umbraco.Core.Composing; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence; + +namespace Umbraco.Core +{ + /// + /// Provides static options for the runtime. + /// + /// + /// These options can be configured in PreApplicationStart or via appSettings. + /// + public static class RuntimeOptions + { + private static List> _onBoot; + private static List> _onEssentials; + private static bool? _installMissingDatabase; + private static bool? _installEmptyDatabase; + + // reads a boolean appSetting + private static bool BoolSetting(string key, bool missing) => ConfigurationManager.AppSettings[key]?.InvariantEquals("true") ?? missing; + + /// + /// Gets a value indicating whether the runtime should enter Install level when the database is missing. + /// + /// + /// By default, when a database connection string is configured but it is not possible to + /// connect to the database, the runtime enters the BootFailed level. If this options is set to true, + /// it enters the Install level instead. + /// It is then up to the implementor, that is setting this value, to take over the installation + /// sequence. + /// + public static bool InstallMissingDatabase + { + get => _installEmptyDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallMissingDatabase", false); + set => _installEmptyDatabase = value; + } + + /// + /// Gets a value indicating whether the runtime should enter Install level when the database is empty. + /// + /// + /// By default, when a database connection string is configured and it is possible to connect to + /// the database, but the database is empty, the runtime enters the BootFailed level. If this options + /// is set to true, it enters the Install level instead. + /// It is then up to the implementor, that is setting this value, to take over the installation + /// sequence. + /// + public static bool InstallEmptyDatabase + { + get => _installMissingDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false); + set => _installMissingDatabase = value; + } + + /// + /// Executes the RuntimeBoot handlers. + /// + internal static void DoRuntimeBoot(IProfilingLogger logger) + { + if (_onBoot == null) + return; + + foreach (var action in _onBoot) + action(logger); + } + + /// + /// Executes the RuntimeEssentials handlers. + /// + internal static void DoRuntimeEssentials(Composition composition, AppCaches appCaches, TypeLoader typeLoader, IUmbracoDatabaseFactory databaseFactory) + { + if (_onEssentials== null) + return; + + foreach (var action in _onEssentials) + action(composition, appCaches, typeLoader, databaseFactory); + } + + /// + /// Registers a RuntimeBoot handler. + /// + /// + /// A RuntimeBoot handler runs when the runtime boots, right after the + /// loggers have been created, but before anything else. + /// + public static void OnRuntimeBoot(Action action) + { + if (_onBoot == null) + _onBoot = new List>(); + _onBoot.Add(action); + } + + /// + /// Registers a RuntimeEssentials handler. + /// + /// + /// A RuntimeEssentials handler runs after the runtime has created a few + /// essential things (AppCaches, a TypeLoader, and a database factory) but + /// before anything else. + /// + public static void OnRuntimeEssentials(Action action) + { + if (_onEssentials == null) + _onEssentials = new List>(); + _onEssentials.Add(action); + } + } +} diff --git a/src/Umbraco.Core/RuntimeState.cs b/src/Umbraco.Core/RuntimeState.cs index 85e8c7370d..b21c02fdb9 100644 --- a/src/Umbraco.Core/RuntimeState.cs +++ b/src/Umbraco.Core/RuntimeState.cs @@ -169,7 +169,7 @@ namespace Umbraco.Core else if (databaseFactory.Configured == false) { // local version *does* match code version, but the database is not configured - // install (again? this is a weird situation...) + // install - may happen with Deploy/Cloud/etc logger.Debug("Database is not configured, need to install Umbraco."); Level = RuntimeLevel.Install; Reason = RuntimeLevelReason.InstallNoDatabase; @@ -179,7 +179,7 @@ namespace Umbraco.Core // else, keep going, // anything other than install wants a database - see if we can connect // (since this is an already existing database, assume localdb is ready) - var tries = RuntimeStateOptions.InstallMissingDatabase ? 2 : 5; + var tries = RuntimeOptions.InstallMissingDatabase ? 2 : 5; for (var i = 0;;) { connect = databaseFactory.CanConnect; @@ -193,7 +193,7 @@ namespace Umbraco.Core // cannot connect to configured database, this is bad, fail logger.Debug("Could not connect to database."); - if (RuntimeStateOptions.InstallMissingDatabase) + if (RuntimeOptions.InstallMissingDatabase) { // ok to install on a configured but missing database Level = RuntimeLevel.Install; @@ -222,7 +222,7 @@ namespace Umbraco.Core // can connect to the database but cannot check the upgrade state... oops logger.Warn(e, "Could not check the upgrade state."); - if (RuntimeStateOptions.InstallEmptyDatabase) + if (RuntimeOptions.InstallEmptyDatabase) { // ok to install on an empty database Level = RuntimeLevel.Install; diff --git a/src/Umbraco.Core/RuntimeStateOptions.cs b/src/Umbraco.Core/RuntimeStateOptions.cs deleted file mode 100644 index 9262a8a990..0000000000 --- a/src/Umbraco.Core/RuntimeStateOptions.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System.Configuration; - -namespace Umbraco.Core -{ - /// - /// Allows configuration of the in PreApplicationStart or in appSettings - /// - public static class RuntimeStateOptions - { - // configured statically or via app settings - private static bool BoolSetting(string key, bool missing) => ConfigurationManager.AppSettings[key]?.InvariantEquals("true") ?? missing; - - /// - /// If true the RuntimeState will continue the installation sequence when a database is missing - /// - /// - /// In this case it will be up to the implementor that is setting this value to true to take over the bootup/installation sequence - /// - public static bool InstallMissingDatabase - { - get => _installEmptyDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallMissingDatabase", false); - set => _installEmptyDatabase = value; - } - - /// - /// If true the RuntimeState will continue the installation sequence when a database is available but is empty - /// - /// - /// In this case it will be up to the implementor that is setting this value to true to take over the bootup/installation sequence - /// - public static bool InstallEmptyDatabase - { - get => _installMissingDatabase ?? BoolSetting("Umbraco.Core.RuntimeState.InstallEmptyDatabase", false); - set => _installMissingDatabase = value; - } - - private static bool? _installMissingDatabase; - private static bool? _installEmptyDatabase; - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 9a52cb8dc5..1a978650f0 100755 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -530,7 +530,7 @@ - + From a6d3078638972f1a175bb14af8c5b9e117b7b387 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 24 Jan 2019 13:54:54 +0100 Subject: [PATCH 035/213] Improve CoreRuntime handling of boot fails --- src/Umbraco.Core/Runtime/CoreRuntime.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Runtime/CoreRuntime.cs b/src/Umbraco.Core/Runtime/CoreRuntime.cs index 793eb751dd..9c18b3d8c3 100644 --- a/src/Umbraco.Core/Runtime/CoreRuntime.cs +++ b/src/Umbraco.Core/Runtime/CoreRuntime.cs @@ -296,7 +296,7 @@ namespace Umbraco.Core.Runtime /// public virtual void Terminate() { - _components.Terminate(); + _components?.Terminate(); } /// From c7bbad3c0ce208eeddf43ea7fff04d19ee5455a6 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Thu, 24 Jan 2019 13:58:16 +0000 Subject: [PATCH 036/213] Lots or removal & tidy up - still WIP & may break build --- .../Services/MemberTypeServiceTests.cs | 3 - src/Umbraco.Tests/UI/LegacyDialogTests.cs | 12 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 51 +-- src/Umbraco.Web.UI/Umbraco/Create.aspx.cs | 34 -- .../Umbraco/Create.aspx.designer.cs | 25 -- .../Umbraco/config/create/UI.Release.xml | 18 - .../Umbraco/config/create/UI.xml | 18 - src/Umbraco.Web.UI/Umbraco/create.aspx | 43 --- src/Umbraco.Web.UI/Umbraco/create/simple.ascx | 22 -- .../developer/Macros/EditMacro.aspx.cs | 363 ------------------ .../Macros/EditMacro.aspx.designer.cs | 222 ----------- .../Umbraco/developer/Macros/editMacro.aspx | 190 --------- .../Umbraco/masterpages/default.Master | 3 - src/Umbraco.Web.UI/default.aspx | 2 - .../Actions/ActionChangeDocType.cs | 7 +- src/Umbraco.Web/Actions/ActionCopy.cs | 3 - src/Umbraco.Web/Actions/ActionDelete.cs | 3 - src/Umbraco.Web/Actions/ActionMove.cs | 3 - src/Umbraco.Web/Actions/ActionNew.cs | 3 - src/Umbraco.Web/Actions/ActionProtect.cs | 3 - src/Umbraco.Web/Actions/ActionRights.cs | 3 - src/Umbraco.Web/Actions/ActionRollback.cs | 3 - src/Umbraco.Web/Actions/ActionToPublish.cs | 3 - src/Umbraco.Web/Actions/ActionUpdate.cs | 3 - src/Umbraco.Web/Cache/MacroCacheRefresher.cs | 2 + src/Umbraco.Web/Mvc/RenderRouteHandler.cs | 22 +- src/Umbraco.Web/Mvc/UmbracoPageResult.cs | 10 +- src/Umbraco.Web/Mvc/UrlHelperExtensions.cs | 9 +- src/Umbraco.Web/Templates/TemplateRenderer.cs | 7 +- src/Umbraco.Web/UI/Pages/BasePage.cs | 82 ---- src/Umbraco.Web/UI/Pages/ClientTools.cs | 347 ----------------- .../UI/Pages/UmbracoEnsuredPage.cs | 151 -------- src/Umbraco.Web/Umbraco.Web.csproj | 41 +- .../AttributeCollectionAdapter.cs | 312 --------------- .../umbraco.presentation/MacroCacheContent.cs | 4 +- .../umbraco.presentation/default.aspx.cs | 183 --------- src/Umbraco.Web/umbraco.presentation/item.cs | 237 ------------ src/Umbraco.Web/umbraco.presentation/page.cs | 1 + .../umbraco/create.aspx.cs | 49 --- .../umbraco/create/macroTasks.cs | 36 -- .../umbraco/create/simple.ascx.cs | 100 ----- .../umbraco.presentation/umbracoPageHolder.cs | 114 ------ 42 files changed, 20 insertions(+), 2727 deletions(-) delete mode 100644 src/Umbraco.Web.UI/Umbraco/Create.aspx.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/Create.aspx.designer.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml delete mode 100644 src/Umbraco.Web.UI/Umbraco/config/create/UI.xml delete mode 100644 src/Umbraco.Web.UI/Umbraco/create.aspx delete mode 100644 src/Umbraco.Web.UI/Umbraco/create/simple.ascx delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Macros/EditMacro.aspx.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Macros/EditMacro.aspx.designer.cs delete mode 100644 src/Umbraco.Web.UI/Umbraco/developer/Macros/editMacro.aspx delete mode 100644 src/Umbraco.Web.UI/Umbraco/masterpages/default.Master delete mode 100644 src/Umbraco.Web.UI/default.aspx delete mode 100644 src/Umbraco.Web/UI/Pages/BasePage.cs delete mode 100644 src/Umbraco.Web/UI/Pages/ClientTools.cs delete mode 100644 src/Umbraco.Web/UI/Pages/UmbracoEnsuredPage.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/AttributeCollectionAdapter.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/default.aspx.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/item.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/create.aspx.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/create/macroTasks.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbraco/create/simple.ascx.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/umbracoPageHolder.cs diff --git a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs index b607290c5e..459daa3da6 100644 --- a/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberTypeServiceTests.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Threading; using NUnit.Framework; -using umbraco.cms.presentation.create.controls; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Dtos; -using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; diff --git a/src/Umbraco.Tests/UI/LegacyDialogTests.cs b/src/Umbraco.Tests/UI/LegacyDialogTests.cs index 5c8a621e10..9f1e474bd9 100644 --- a/src/Umbraco.Tests/UI/LegacyDialogTests.cs +++ b/src/Umbraco.Tests/UI/LegacyDialogTests.cs @@ -23,12 +23,12 @@ namespace Umbraco.Tests.UI } } - [TestCase(typeof(macroTasks), Constants.Applications.Settings)] - public void Check_Assigned_Apps_For_Tasks(Type taskType, string app) - { - var task = (LegacyDialogTask)Activator.CreateInstance(taskType); - Assert.AreEqual(task.AssignedApp, app); - } + //[TestCase(typeof(macroTasks), Constants.Applications.Settings)] + //public void Check_Assigned_Apps_For_Tasks(Type taskType, string app) + //{ + // var task = (LegacyDialogTask)Activator.CreateInstance(taskType); + // Assert.AreEqual(task.AssignedApp, app); + //} } } diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 0ff158dadb..d51c2f7814 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -80,7 +80,6 @@ - @@ -134,7 +133,6 @@ noNodes.aspx - ASPXCodeBehind @@ -142,39 +140,6 @@ True Settings.settings - - create.aspx - ASPXCodeBehind - - - create.aspx - - - editMacro.aspx - ASPXCodeBehind - - - editMacro.aspx - - - default.Master - ASPXCodeBehind - - - default.Master - - - ASPXCodeBehind - - - umbracoDialog.Master - - - ASPXCodeBehind - - - umbracoPage.Master - @@ -197,12 +162,11 @@ + + - - - @@ -261,10 +225,6 @@ SettingsSingleFileGenerator Settings.Designer.cs - - UI.xml - Designer - Designer @@ -277,7 +237,6 @@ - Designer @@ -288,7 +247,6 @@ - Designer @@ -348,15 +306,10 @@ Web.Template.config Designer - - - - - Designer diff --git a/src/Umbraco.Web.UI/Umbraco/Create.aspx.cs b/src/Umbraco.Web.UI/Umbraco/Create.aspx.cs deleted file mode 100644 index 7848a5976b..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/Create.aspx.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using System.Web; -using Umbraco.Web._Legacy.UI; - -namespace Umbraco.Web.UI.Umbraco -{ - public partial class CreateDialog : global::umbraco.cms.presentation.Create - { - - protected override void OnLoad(EventArgs e) - { - if (SecurityCheck(Request.QueryString["nodeType"])) - { - //if we're allowed, then continue - base.OnLoad(e); - } - else - { - //otherwise show an error - UI.Visible = false; - AccessError.Visible = true; - } - } - - private bool SecurityCheck(string nodeTypeAlias) - { - return LegacyDialogHandler.UserHasCreateAccess( - new HttpContextWrapper(Context), - Security.CurrentUser, - nodeTypeAlias); - } - - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/Create.aspx.designer.cs b/src/Umbraco.Web.UI/Umbraco/Create.aspx.designer.cs deleted file mode 100644 index c17aadcbf2..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/Create.aspx.designer.cs +++ /dev/null @@ -1,25 +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 CreateDialog - { - - /// - /// AccessError control. - /// - /// - /// Auto-generated field. - /// To modify move field declaration from designer file to code-behind file. - /// - protected global::System.Web.UI.WebControls.PlaceHolder AccessError; - } -} diff --git a/src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml b/src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml deleted file mode 100644 index 635174b9da..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/config/create/UI.Release.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - -
Macro
- /create/simple.ascx - - - -
- -
Macro
- /create/simple.ascx - - - - -
-
diff --git a/src/Umbraco.Web.UI/Umbraco/config/create/UI.xml b/src/Umbraco.Web.UI/Umbraco/config/create/UI.xml deleted file mode 100644 index c075a0b8b9..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/config/create/UI.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - -
Macro
- /create/simple.ascx - - - -
- -
Macro
- /create/simple.ascx - - - - -
-
diff --git a/src/Umbraco.Web.UI/Umbraco/create.aspx b/src/Umbraco.Web.UI/Umbraco/create.aspx deleted file mode 100644 index d69bffc4b3..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/create.aspx +++ /dev/null @@ -1,43 +0,0 @@ -<%@ Page Language="c#" MasterPageFile="masterpages/umbracoDialog.Master" Codebehind="CreateDialog.aspx.cs" AutoEventWireup="True" Inherits="Umbraco.Web.UI.Umbraco.CreateDialog" %> -<%@ Register Namespace="umbraco" TagPrefix="umb" Assembly="Umbraco.Web" %> - - - - - - - - - -
-

- The current user does not have access to create this type of object -

-
-
-
- - - - \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/create/simple.ascx b/src/Umbraco.Web.UI/Umbraco/create/simple.ascx deleted file mode 100644 index df8056019d..0000000000 --- a/src/Umbraco.Web.UI/Umbraco/create/simple.ascx +++ /dev/null @@ -1,22 +0,0 @@ -<%@ Control Language="c#" AutoEventWireup="True" Inherits="umbraco.cms.presentation.create.controls.simple" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %> -<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %> - - - - - * - - - - - <%=Services.TextService.Localize("cancel")%> - - - - - - -