diff --git a/src/Umbraco.Core/Models/LoginModel.cs b/src/Umbraco.Core/Models/Security/LoginModel.cs similarity index 82% rename from src/Umbraco.Core/Models/LoginModel.cs rename to src/Umbraco.Core/Models/Security/LoginModel.cs index f44b274ffb..98c9d23cff 100644 --- a/src/Umbraco.Core/Models/LoginModel.cs +++ b/src/Umbraco.Core/Models/Security/LoginModel.cs @@ -1,7 +1,7 @@ using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { public class LoginModel : PostRedirectModel { @@ -11,7 +11,7 @@ namespace Umbraco.Web.Models [Required] [DataMember(Name = "password", IsRequired = true)] - [StringLength(maximumLength:256)] + [StringLength(maximumLength: 256)] public string Password { get; set; } } diff --git a/src/Umbraco.Core/Models/PostRedirectModel.cs b/src/Umbraco.Core/Models/Security/PostRedirectModel.cs similarity index 92% rename from src/Umbraco.Core/Models/PostRedirectModel.cs rename to src/Umbraco.Core/Models/Security/PostRedirectModel.cs index e04584704d..3a87cdcbe5 100644 --- a/src/Umbraco.Core/Models/PostRedirectModel.cs +++ b/src/Umbraco.Core/Models/Security/PostRedirectModel.cs @@ -1,4 +1,4 @@ -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { /// /// A base model containing a value to indicate to Umbraco where to redirect to after Posting if diff --git a/src/Umbraco.Web/Models/ProfileModel.cs b/src/Umbraco.Core/Models/Security/ProfileModel.cs similarity index 62% rename from src/Umbraco.Web/Models/ProfileModel.cs rename to src/Umbraco.Core/Models/Security/ProfileModel.cs index 0397f34849..8493a5f5a9 100644 --- a/src/Umbraco.Web/Models/ProfileModel.cs +++ b/src/Umbraco.Core/Models/Security/ProfileModel.cs @@ -2,36 +2,15 @@ using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Web.Mvc; -using Current = Umbraco.Web.Composing.Current; +using Umbraco.Web.Models; -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { /// /// A readonly member profile model /// - [ModelBinder(typeof(ProfileModelBinder))] public class ProfileModel : PostRedirectModel { - - public static ProfileModel CreateModel() - { - var model = new ProfileModel(false); - return model; - } - - private ProfileModel(bool doLookup) - { - MemberProperties = new List(); - if (doLookup && Current.UmbracoContext != null) - { - var helper = Current.MembershipHelper; - var model = helper.GetCurrentMemberProfileModel(); - MemberProperties = model.MemberProperties; - } - } - - [Required] [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", ErrorMessage = "Please enter a valid e-mail address")] @@ -81,18 +60,6 @@ namespace Umbraco.Web.Models /// /// Adding items to this list on the front-end will not add properties to the member in the database. /// - public List MemberProperties { get; set; } - - /// - /// A custom model binder for MVC because the default ctor performs a lookup! - /// - internal class ProfileModelBinder : DefaultModelBinder - { - protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) - { - return ProfileModel.CreateModel(); - } - - } + public List MemberProperties { get; set; } = new List(); } } diff --git a/src/Umbraco.Web/Models/RegisterModel.cs b/src/Umbraco.Core/Models/Security/RegisterModel.cs similarity index 79% rename from src/Umbraco.Web/Models/RegisterModel.cs rename to src/Umbraco.Core/Models/Security/RegisterModel.cs index 1ee9307969..fca749703d 100644 --- a/src/Umbraco.Web/Models/RegisterModel.cs +++ b/src/Umbraco.Core/Models/Security/RegisterModel.cs @@ -1,12 +1,9 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Web.Mvc; -using Umbraco.Core; +using Umbraco.Web.Models; -namespace Umbraco.Web.Models +namespace Umbraco.Core.Models.Security { - [ModelBinder(typeof(RegisterModelBinder))] public class RegisterModel : PostRedirectModel { /// @@ -27,7 +24,6 @@ namespace Umbraco.Web.Models CreatePersistentLoginCookie = true; } - [Required] [RegularExpression(@"[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?", ErrorMessage = "Please enter a valid e-mail address")] @@ -74,16 +70,5 @@ namespace Umbraco.Web.Models /// Default is true to create a persistent cookie if LoginOnSuccess is true /// public bool CreatePersistentLoginCookie { get; set; } - - /// - /// A custom model binder for MVC because the default ctor performs a lookup! - /// - internal class RegisterModelBinder : DefaultModelBinder - { - protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) - { - return RegisterModel.CreateModel(); - } - } } } diff --git a/src/Umbraco.Core/ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs similarity index 98% rename from src/Umbraco.Core/ConfigurationEditor.cs rename to src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs index 43de192914..e40db6e3cd 100644 --- a/src/Umbraco.Core/ConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs @@ -2,10 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; -using Umbraco.Core.PropertyEditors; using Umbraco.Core.Serialization; -namespace Umbraco.Core +namespace Umbraco.Core.PropertyEditors { /// /// Represents a data type configuration editor. diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollection.cs b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs similarity index 92% rename from src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollection.cs rename to src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs index 2737dcfef1..1dadd6cf0a 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollection.cs +++ b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollection.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.PropertyEditors //TODO: We will need to change this once we support tracking via variants/segments // for now, we are tracking values from ALL variants - foreach(var propertyVal in p.Values) + foreach (var propertyVal in p.Values) { var val = propertyVal.EditedValue; @@ -33,9 +33,9 @@ namespace Umbraco.Core.PropertyEditors if (valueEditor is IDataValueReference reference) { var refs = reference.GetReferences(val); - foreach(var r in refs) + foreach (var r in refs) trackedRelations.Add(r); - } + } // Loop over collection that may be add to existing property editors // implementation of GetReferences in IDataValueReference. @@ -48,14 +48,11 @@ namespace Umbraco.Core.PropertyEditors // in the dataeditor/property has referecnes to media/content items if (item.IsForEditor(editor)) { - foreach(var r in item.GetDataValueReference().GetReferences(val)) + foreach (var r in item.GetDataValueReference().GetReferences(val)) trackedRelations.Add(r); } - } } - - } return trackedRelations; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs b/src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs rename to src/Umbraco.Core/PropertyEditors/DataValueReferenceFactoryCollectionBuilder.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/DecimalConfigurationEditor.cs similarity index 90% rename from src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs rename to src/Umbraco.Core/PropertyEditors/DecimalConfigurationEditor.cs index 207a82844d..efb1df1eb7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DecimalConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DecimalConfigurationEditor.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; namespace Umbraco.Web.PropertyEditors @@ -7,7 +6,7 @@ namespace Umbraco.Web.PropertyEditors /// /// A custom pre-value editor class to deal with the legacy way that the pre-value data is stored. /// - internal class DecimalConfigurationEditor : ConfigurationEditor + public class DecimalConfigurationEditor : ConfigurationEditor { public DecimalConfigurationEditor() { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReference.cs b/src/Umbraco.Core/PropertyEditors/IDataValueReference.cs similarity index 96% rename from src/Umbraco.Infrastructure/PropertyEditors/IDataValueReference.cs rename to src/Umbraco.Core/PropertyEditors/IDataValueReference.cs index 6377098bfc..8c0806a4a4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReference.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueReference.cs @@ -13,6 +13,6 @@ namespace Umbraco.Core.PropertyEditors /// /// /// - IEnumerable GetReferences(object value); + IEnumerable GetReferences(object value); } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReferenceFactory.cs b/src/Umbraco.Core/PropertyEditors/IDataValueReferenceFactory.cs similarity index 90% rename from src/Umbraco.Infrastructure/PropertyEditors/IDataValueReferenceFactory.cs rename to src/Umbraco.Core/PropertyEditors/IDataValueReferenceFactory.cs index 6587e071bf..c13c1ed212 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IDataValueReferenceFactory.cs +++ b/src/Umbraco.Core/PropertyEditors/IDataValueReferenceFactory.cs @@ -5,7 +5,7 @@ /// /// Gets a value indicating whether the DataValueReference lookup supports a datatype (data editor). /// - /// The datatype. + /// /// A value indicating whether the converter supports a datatype. bool IsForEditor(IDataEditor dataEditor); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/IntegerConfigurationEditor.cs similarity index 90% rename from src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs rename to src/Umbraco.Core/PropertyEditors/IntegerConfigurationEditor.cs index e80c0fcb0e..bb1f8af790 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/IntegerConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IntegerConfigurationEditor.cs @@ -1,5 +1,4 @@ -using Umbraco.Core; -using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.Validators; namespace Umbraco.Web.PropertyEditors @@ -7,7 +6,7 @@ namespace Umbraco.Web.PropertyEditors /// /// A custom pre-value editor class to deal with the legacy way that the pre-value data is stored. /// - internal class IntegerConfigurationEditor : ConfigurationEditor + public class IntegerConfigurationEditor : ConfigurationEditor { public IntegerConfigurationEditor() { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ListViewConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs similarity index 84% rename from src/Umbraco.Infrastructure/PropertyEditors/ListViewConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs index ce41628ec1..083e36029e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ListViewConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/ListViewConfiguration.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Runtime.Serialization; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -31,7 +31,7 @@ namespace Umbraco.Web.PropertyEditors new Layout { Name = "grid", Icon = "icon-thumbnails-small", IsSystem = 1, Selected = true, Path = "views/propertyeditors/listview/layouts/grid/grid.html" } }; - IncludeProperties = new [] + IncludeProperties = new[] { new Property { Alias = "sortOrder", Header = "Sort order", IsSystem = 1 }, new Property { Alias = "updateDate", Header = "Last edited", IsSystem = 1 }, @@ -41,7 +41,7 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("pageSize", "Page Size", "number", Description = "Number of items per page")] public int PageSize { get; set; } - + [ConfigurationField("orderBy", "Order By", "views/propertyeditors/listview/sortby.prevalues.html", Description = "The default sort order for the list")] public string OrderBy { get; set; } @@ -69,54 +69,57 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("showContentFirst", "Show Content App First", "boolean", Description = "Enable this to show the content app by default instead of the list view app")] public bool ShowContentFirst { get; set; } + [DataContract] public class Property { - [JsonProperty("alias")] + [DataMember(Name = "alias")] public string Alias { get; set; } - [JsonProperty("header")] + [DataMember(Name = "header")] public string Header { get; set; } - [JsonProperty("nameTemplate")] + [DataMember(Name = "nameTemplate")] public string Template { get; set; } - [JsonProperty("isSystem")] + [DataMember(Name = "isSystem")] public int IsSystem { get; set; } // TODO: bool } + [DataContract] public class Layout { - [JsonProperty("name")] + [DataMember(Name = "name")] public string Name { get; set; } - [JsonProperty("path")] + [DataMember(Name = "path")] public string Path { get; set; } - [JsonProperty("icon")] + [DataMember(Name = "icon")] public string Icon { get; set; } - [JsonProperty("isSystem")] + [DataMember(Name = "isSystem")] public int IsSystem { get; set; } // TODO: bool - [JsonProperty("selected")] + [DataMember(Name = "selected")] public bool Selected { get; set; } } + [DataContract] public class BulkActionPermissionSettings { - [JsonProperty("allowBulkPublish")] + [DataMember(Name = "allowBulkPublish")] public bool AllowBulkPublish { get; set; } = true; - [JsonProperty("allowBulkUnpublish")] + [DataMember(Name = "allowBulkUnpublish")] public bool AllowBulkUnpublish { get; set; } = true; - [JsonProperty("allowBulkCopy")] + [DataMember(Name = "allowBulkCopy")] public bool AllowBulkCopy { get; set; } = true; - [JsonProperty("allowBulkMove")] + [DataMember(Name = "allowBulkMove")] public bool AllowBulkMove { get; set; } = true; - [JsonProperty("allowBulkDelete")] + [DataMember(Name = "allowBulkDelete")] public bool AllowBulkDelete { get; set; } = true; } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs b/src/Umbraco.Core/PropertyEditors/MemberPickerConfiguration.cs similarity index 89% rename from src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/MemberPickerConfiguration.cs index 255be498bc..ba7dea6548 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MemberPickerConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/MemberPickerConfiguration.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using Umbraco.Core; +using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MissingPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MissingPropertyEditor.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/MissingPropertyEditor.cs rename to src/Umbraco.Core/PropertyEditors/MissingPropertyEditor.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfiguration.cs b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfiguration.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/MultiNodePickerConfiguration.cs diff --git a/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs new file mode 100644 index 0000000000..749f46abc5 --- /dev/null +++ b/src/Umbraco.Core/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs @@ -0,0 +1,21 @@ +using System.Runtime.Serialization; +using Umbraco.Core; + +namespace Umbraco.Web.PropertyEditors +{ + /// + /// Represents the 'startNode' value for the + /// + [DataContract] + public class MultiNodePickerConfigurationTreeSource + { + [DataMember(Name = "type")] + public string ObjectType { get; set; } + + [DataMember(Name = "query")] + public string StartNodeQuery { get; set; } + + [DataMember(Name = "id")] + public Udi StartNodeId { get; set; } + } +} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentConfiguration.cs b/src/Umbraco.Core/PropertyEditors/NestedContentConfiguration.cs similarity index 88% rename from src/Umbraco.Infrastructure/PropertyEditors/NestedContentConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/NestedContentConfiguration.cs index 89190883c8..e75be48f36 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/NestedContentConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/NestedContentConfiguration.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json; +using System.Runtime.Serialization; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors @@ -27,15 +27,17 @@ namespace Umbraco.Web.PropertyEditors [ConfigurationField("hideLabel", "Hide Label", "boolean", Description = "Hide the property label and let the item list span the full width of the editor window.")] public bool HideLabel { get; set; } + + [DataContract] public class ContentType { - [JsonProperty("ncAlias")] + [DataMember(Name = "ncAlias")] public string Alias { get; set; } - [JsonProperty("ncTabAlias")] + [DataMember(Name = "ncTabAlias")] public string TabAlias { get; set; } - [JsonProperty("nameTemplate")] + [DataMember(Name = "nameTemplate")] public string Template { get; set; } } } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs b/src/Umbraco.Core/PropertyEditors/UserPickerConfiguration.cs similarity index 95% rename from src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs rename to src/Umbraco.Core/PropertyEditors/UserPickerConfiguration.cs index 88eb1d224e..bf3cd197a3 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/UserPickerConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/UserPickerConfiguration.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Umbraco.Core; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs similarity index 98% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs index 8b3655f0cc..99bbe86dae 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs @@ -27,7 +27,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters => propertyType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.ContentPicker); public override Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof (IPublishedContent); + => typeof(IPublishedContent); public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) => PropertyCacheLevel.Elements; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/LabelValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs similarity index 95% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/LabelValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs index eb461b4920..e706c198cf 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/LabelValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs @@ -65,9 +65,9 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters if (source is decimal sourceDecimal) return sourceDecimal; if (source is string sourceDecimalString) return decimal.TryParse(sourceDecimalString, NumberStyles.Any, CultureInfo.InvariantCulture, out var d) ? d : 0; - if (source is double sourceDouble) - return Convert.ToDecimal(sourceDouble); - return (decimal) 0; + if (source is double sourceDouble) + return Convert.ToDecimal(sourceDouble); + return (decimal)0; case ValueTypes.Integer: if (source is int sourceInt) return sourceInt; if (source is string sourceIntString) @@ -76,7 +76,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters case ValueTypes.Bigint: if (source is string sourceLongString) return long.TryParse(sourceLongString, out var i) ? i : 0; - return (long) 0; + return (long)0; default: // everything else is a string return source?.ToString() ?? string.Empty; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs similarity index 98% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs index 5405727791..9a33fd56e5 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MediaPickerValueConverter.cs @@ -6,6 +6,7 @@ using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Web.PublishedCache; + namespace Umbraco.Web.PropertyEditors.ValueConverters { /// @@ -67,7 +68,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { var isMultiple = IsMultipleDataType(propertyType.DataType); - var udis = (Udi[]) source; + var udis = (Udi[])source; var mediaItems = new List(); if (source == null) return isMultiple ? mediaItems : null; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs similarity index 100% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/MultiNodeTreePickerValueConverter.cs diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TinyMceValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs similarity index 97% rename from src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TinyMceValueConverter.cs rename to src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs index c4e384e1e8..51471f6da7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/TinyMceValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs @@ -14,7 +14,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters => propertyType.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce; public override Type GetPropertyValueType(IPublishedPropertyType propertyType) - => typeof (IHtmlEncodedString); + => typeof(IHtmlEncodedString); // PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros public override PropertyCacheLevel GetPropertyCacheLevel(IPublishedPropertyType propertyType) diff --git a/src/Umbraco.Core/PublishedContentExtensions.cs b/src/Umbraco.Core/PublishedContentExtensions.cs index 1b7c460c8b..fd353f95cd 100644 --- a/src/Umbraco.Core/PublishedContentExtensions.cs +++ b/src/Umbraco.Core/PublishedContentExtensions.cs @@ -2,10 +2,8 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core.Configuration.Models; -using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; -using Umbraco.Web; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; diff --git a/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs b/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs similarity index 72% rename from src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs rename to src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs index 4549227c89..eb4be355f4 100644 --- a/src/Umbraco.Core/HybridBackofficeSecurityAccessor.cs +++ b/src/Umbraco.Core/Security/HybridBackofficeSecurityAccessor.cs @@ -1,15 +1,12 @@ using Umbraco.Core.Cache; -using Umbraco.Core.Security; using Umbraco.Web; -using Umbraco.Web.Security; -namespace Umbraco.Core +namespace Umbraco.Core.Security { - public class HybridBackofficeSecurityAccessor : HybridAccessorBase, IBackOfficeSecurityAccessor { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public HybridBackofficeSecurityAccessor(IRequestCache requestCache) : base(requestCache) @@ -19,7 +16,7 @@ namespace Umbraco.Core protected override string ItemKey => "Umbraco.Web.HybridBackofficeSecurityAccessor"; /// - /// Gets or sets the object. + /// Gets or sets the object. /// public IBackOfficeSecurity BackOfficeSecurity { diff --git a/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs b/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs new file mode 100644 index 0000000000..09a7ab5d1b --- /dev/null +++ b/src/Umbraco.Core/Security/HybridUmbracoWebsiteSecurityAccessor.cs @@ -0,0 +1,28 @@ +using Umbraco.Core.Cache; +using Umbraco.Web; + +namespace Umbraco.Core.Security +{ + + public class HybridUmbracoWebsiteSecurityAccessor : HybridAccessorBase, IUmbracoWebsiteSecurityAccessor + { + /// + /// Initializes a new instance of the class. + /// + public HybridUmbracoWebsiteSecurityAccessor(IRequestCache requestCache) + : base(requestCache) + { } + + /// + protected override string ItemKey => "Umbraco.Web.HybridUmbracoWebsiteSecurityAccessor"; + + /// + /// Gets or sets the object. + /// + public IUmbracoWebsiteSecurity WebsiteSecurity + { + get => Value; + set => Value = value; + } + } +} diff --git a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs new file mode 100644 index 0000000000..c302d45354 --- /dev/null +++ b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurity.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Umbraco.Core.Models.Security; + +namespace Umbraco.Core.Security +{ + public interface IUmbracoWebsiteSecurity + { + /// + /// Registers a new member. + /// + /// Register member model. + /// Flag for whether to log the member in upon successful registration. + /// Result of registration operation. + Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true); + + /// + /// Updates the currently logged in member's profile. + /// + /// Update member profile model. + /// Result of update profile operation. + Task UpdateMemberProfileAsync(ProfileModel model); + + /// + /// A helper method to perform the validation and logging in of a member. + /// + /// The username. + /// The password. + /// Result of login operation. + Task LoginAsync(string username, string password); + + /// + /// Check if a member is logged in + /// + /// True if logged in, false if not. + bool IsLoggedIn(); + + /// + /// Logs out the current member. + /// + Task LogOutAsync(); + + /// + /// Checks if the current member is authorized based on the parameters provided. + /// + /// Allowed types. + /// Allowed groups. + /// Allowed individual members. + /// True or false if the currently logged in member is authorized + bool IsMemberAuthorized( + IEnumerable allowTypes = null, + IEnumerable allowGroups = null, + IEnumerable allowMembers = null); + } +} diff --git a/src/Umbraco.Core/Security/IUmbracoWebsiteSecurityAccessor.cs b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurityAccessor.cs new file mode 100644 index 0000000000..618aeb7146 --- /dev/null +++ b/src/Umbraco.Core/Security/IUmbracoWebsiteSecurityAccessor.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Core.Security +{ + public interface IUmbracoWebsiteSecurityAccessor + { + IUmbracoWebsiteSecurity WebsiteSecurity { get; set; } + } +} diff --git a/src/Umbraco.Core/Security/RegisterMemberStatus.cs b/src/Umbraco.Core/Security/RegisterMemberStatus.cs new file mode 100644 index 0000000000..1cbeae38d1 --- /dev/null +++ b/src/Umbraco.Core/Security/RegisterMemberStatus.cs @@ -0,0 +1,13 @@ +namespace Umbraco.Core.Security +{ + public enum RegisterMemberStatus + { + Success, + InvalidUserName, + InvalidPassword, + InvalidEmail, + DuplicateUserName, + DuplicateEmail, + Error, + } +} diff --git a/src/Umbraco.Core/Security/UpdateMemberProfileResult.cs b/src/Umbraco.Core/Security/UpdateMemberProfileResult.cs new file mode 100644 index 0000000000..1d435378a6 --- /dev/null +++ b/src/Umbraco.Core/Security/UpdateMemberProfileResult.cs @@ -0,0 +1,24 @@ +namespace Umbraco.Core.Security +{ + public class UpdateMemberProfileResult + { + private UpdateMemberProfileResult() + { + } + + public UpdateMemberProfileStatus Status { get; private set; } + + public string ErrorMessage { get; private set; } + + public static UpdateMemberProfileResult Success() + { + return new UpdateMemberProfileResult { Status = UpdateMemberProfileStatus.Success }; + } + + public static UpdateMemberProfileResult Error(string message) + { + return new UpdateMemberProfileResult { Status = UpdateMemberProfileStatus.Error, ErrorMessage = message }; + } + } + +} diff --git a/src/Umbraco.Core/Security/UpdateMemberProfileStatus.cs b/src/Umbraco.Core/Security/UpdateMemberProfileStatus.cs new file mode 100644 index 0000000000..33dfe4d486 --- /dev/null +++ b/src/Umbraco.Core/Security/UpdateMemberProfileStatus.cs @@ -0,0 +1,8 @@ +namespace Umbraco.Core.Security +{ + public enum UpdateMemberProfileStatus + { + Success, + Error, + } +} diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs deleted file mode 100644 index 2942271acc..0000000000 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodePickerConfigurationTreeSource.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Newtonsoft.Json; -using Umbraco.Core; - -namespace Umbraco.Web.PropertyEditors -{ - /// - /// Represents the 'startNode' value for the - /// - [JsonObject] - public class MultiNodePickerConfigurationTreeSource - { - [JsonProperty("type")] - public string ObjectType {get;set;} - - [JsonProperty("query")] - public string StartNodeQuery {get;set;} - - [JsonProperty("id")] - public Udi StartNodeId {get;set;} - } -} diff --git a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs index a0ae3868d1..1a6f9d1c21 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/AuthenticationController.cs @@ -3,17 +3,19 @@ using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; -using Microsoft.AspNetCore.Routing; using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Umbraco.Core; using Umbraco.Core.BackOffice; using Umbraco.Core.Configuration.Models; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; +using Umbraco.Core.Models.Security; using Umbraco.Core.Security; using Umbraco.Core.Services; using Umbraco.Extensions; @@ -25,11 +27,10 @@ using Umbraco.Web.Common.Controllers; using Umbraco.Web.Common.Exceptions; using Umbraco.Web.Common.Filters; using Umbraco.Web.Common.Security; +using Umbraco.Web.Editors.Filters; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; -using Umbraco.Web.Security; using Constants = Umbraco.Core.Constants; -using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Authorization; using Umbraco.Web.Common.Authorization; diff --git a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs index 5b104d2f9b..28c077a63c 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/EntityController.cs @@ -250,7 +250,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// The culture to fetch the URL for /// The URL or path to the item [DetermineAmbiguousActionByPassingParameters] - public HttpResponseMessage GetUrl(Udi udi, string culture = "*") + public IActionResult GetUrl(Udi udi, string culture = "*") { var intId = _entityService.GetId(udi); if (!intId.Success) @@ -284,7 +284,7 @@ namespace Umbraco.Web.BackOffice.Controllers /// We are not restricting this with security because there is no sensitive data /// [DetermineAmbiguousActionByPassingParameters] - public HttpResponseMessage GetUrl(int id, UmbracoEntityTypes type, string culture = null) + public IActionResult GetUrl(int id, UmbracoEntityTypes type, string culture = null) { culture = culture ?? ClientCulture(); @@ -297,10 +297,7 @@ namespace Umbraco.Web.BackOffice.Controllers { returnUrl = foundUrl; - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(returnUrl) - }; + return Ok(returnUrl); } } @@ -314,10 +311,7 @@ namespace Umbraco.Web.BackOffice.Controllers returnUrl = "/" + string.Join("/", ancestors.Select(x => x.Name)); - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(returnUrl) - }; + return Ok(returnUrl); } diff --git a/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs b/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs index a878910bf3..d11b89f6f0 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/MacroRenderingController.cs @@ -157,7 +157,7 @@ namespace Umbraco.Web.BackOffice.Controllers } [HttpPost] - public HttpResponseMessage CreatePartialViewMacroWithFile(CreatePartialViewMacroWithFileModel model) + public IActionResult CreatePartialViewMacroWithFile(CreatePartialViewMacroWithFileModel model) { if (model == null) throw new ArgumentNullException("model"); if (string.IsNullOrWhiteSpace(model.Filename)) throw new ArgumentException("Filename cannot be null or whitespace", "model.Filename"); @@ -173,7 +173,7 @@ namespace Umbraco.Web.BackOffice.Controllers }; _macroService.Save(macro); // may throw - return new HttpResponseMessage(HttpStatusCode.OK); + return Ok(); } public class CreatePartialViewMacroWithFileModel diff --git a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs index 7f7dcde008..fc247af55c 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoMemberAuthorizeFilter.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc.Filters; using System.Collections.Generic; using Umbraco.Core; +using Umbraco.Core.Security; using Umbraco.Extensions; namespace Umbraco.Web.Common.Filters @@ -13,6 +14,12 @@ namespace Umbraco.Web.Common.Filters public class UmbracoMemberAuthorizeFilter : IAuthorizationFilter { // TODO: Lets revisit this when we get members done and the front-end working and whether it can be replaced or moved to an authz policy + private readonly IUmbracoWebsiteSecurity _websiteSecurity; + + public UmbracoMemberAuthorizeFilter(IUmbracoWebsiteSecurity websiteSecurity) + { + _websiteSecurity = websiteSecurity; + } /// /// Comma delimited list of allowed member types @@ -29,9 +36,7 @@ namespace Umbraco.Web.Common.Filters /// public string AllowMembers { get; private set; } - - private UmbracoMemberAuthorizeFilter( - string allowType, string allowGroup, string allowMembers) + private UmbracoMemberAuthorizeFilter(string allowType, string allowGroup, string allowMembers) { AllowType = allowType; AllowGroup = allowGroup; @@ -50,11 +55,19 @@ namespace Umbraco.Web.Common.Filters private bool IsAuthorized() { if (AllowMembers.IsNullOrWhiteSpace()) - AllowMembers = ""; + { + AllowMembers = string.Empty; + } + if (AllowGroup.IsNullOrWhiteSpace()) - AllowGroup = ""; + { + AllowGroup = string.Empty; + } + if (AllowType.IsNullOrWhiteSpace()) - AllowType = ""; + { + AllowType = string.Empty; + } var members = new List(); foreach (var s in AllowMembers.Split(',')) @@ -65,7 +78,7 @@ namespace Umbraco.Web.Common.Filters } } - return false;// TODO reintroduce when members are implemented: _memberHelper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members); + return _websiteSecurity.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members); } } } diff --git a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs index a6c13bf50b..163991c458 100644 --- a/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs +++ b/src/Umbraco.Web.Common/Runtime/AspNetCoreComposer.cs @@ -74,9 +74,12 @@ namespace Umbraco.Web.Common.Runtime // register the umbraco context factory composition.Services.AddUnique(); + composition.Services.AddUnique(); composition.Services.AddUnique(); + composition.Services.AddUnique(); + //register the install components composition.ComposeInstaller(); diff --git a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs index 8125923ee4..4e0517754c 100644 --- a/src/Umbraco.Web.Website/Controllers/SurfaceController.cs +++ b/src/Umbraco.Web.Website/Controllers/SurfaceController.cs @@ -21,7 +21,13 @@ namespace Umbraco.Web.Website.Controllers // [MergeParentContextViewData] public abstract class SurfaceController : PluginController { - private readonly IPublishedUrlProvider _publishedUrlProvider; + protected SurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) + { + PublishedUrlProvider = publishedUrlProvider; + } + + protected IPublishedUrlProvider PublishedUrlProvider { get; } /// /// Gets the current page. @@ -39,12 +45,6 @@ namespace Umbraco.Web.Website.Controllers } } - protected SurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) - { - _publishedUrlProvider = publishedUrlProvider; - } - /// /// Redirects to the Umbraco page with the given id /// @@ -52,7 +52,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey) { - return new RedirectToUmbracoPageResult(contentKey, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(contentKey, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -63,7 +63,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey, QueryString queryString) { - return new RedirectToUmbracoPageResult(contentKey, queryString, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(contentKey, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -73,7 +73,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent) { - return new RedirectToUmbracoPageResult(publishedContent, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(publishedContent, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -84,7 +84,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent, QueryString queryString) { - return new RedirectToUmbracoPageResult(publishedContent, queryString, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(publishedContent, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -93,7 +93,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage() { - return new RedirectToUmbracoPageResult(CurrentPage, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(CurrentPage, PublishedUrlProvider, UmbracoContextAccessor); } /// @@ -103,7 +103,7 @@ namespace Umbraco.Web.Website.Controllers /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage(QueryString queryString) { - return new RedirectToUmbracoPageResult(CurrentPage, queryString, _publishedUrlProvider, UmbracoContextAccessor); + return new RedirectToUmbracoPageResult(CurrentPage, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// diff --git a/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs new file mode 100644 index 0000000000..6ba0f582c8 --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/UmbLoginController.cs @@ -0,0 +1,60 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; +using Umbraco.Core.Persistence; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.Website.Controllers +{ + public class UmbLoginController : SurfaceController + { + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; + + public UmbLoginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, + ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, + IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) + { + _websiteSecurityAccessor = websiteSecurityAccessor; + } + + [HttpPost] + [ValidateAntiForgeryToken] + [ValidateUmbracoFormRouteString] + public async Task HandleLogin([Bind(Prefix = "loginModel")]LoginModel model) + { + if (ModelState.IsValid == false) + { + return CurrentUmbracoPage(); + } + + if (await _websiteSecurityAccessor.WebsiteSecurity.LoginAsync(model.Username, model.Password) == false) + { + // Don't add a field level error, just model level. + ModelState.AddModelError("loginModel", "Invalid username or password"); + return CurrentUmbracoPage(); + } + + TempData["LoginSuccess"] = true; + + // If there is a specified path to redirect to then use it. + if (model.RedirectUrl.IsNullOrWhiteSpace() == false) + { + // Validate the redirect url. + // If it's not a local url we'll redirect to the root of the current site. + return Redirect(Url.IsLocalUrl(model.RedirectUrl) + ? model.RedirectUrl + : CurrentPage.AncestorOrSelf(1).Url(PublishedUrlProvider)); + } + + // Redirect to current page by default. + return RedirectToCurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs b/src/Umbraco.Web.Website/Controllers/UmbLoginStatusController.cs similarity index 50% rename from src/Umbraco.Web/Controllers/UmbLoginStatusController.cs rename to src/Umbraco.Web.Website/Controllers/UmbLoginStatusController.cs index d7a8601838..e9bf164eb3 100644 --- a/src/Umbraco.Web/Controllers/UmbLoginStatusController.cs +++ b/src/Umbraco.Web.Website/Controllers/UmbLoginStatusController.cs @@ -1,58 +1,54 @@ -using System.Web.Mvc; -using System.Web.Security; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Web.Security; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; -namespace Umbraco.Web.Controllers +namespace Umbraco.Web.Website.Controllers { - [MemberAuthorize] + [UmbracoMemberAuthorize] public class UmbLoginStatusController : SurfaceController { - private readonly MembershipHelper _membershipHelper; - - public UmbLoginStatusController() - { - } + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; public UmbLoginStatusController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, - IProfilingLogger profilingLogger, MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) + IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) { - _membershipHelper = membershipHelper; + _websiteSecurityAccessor = websiteSecurityAccessor; } [HttpPost] [ValidateAntiForgeryToken] [ValidateUmbracoFormRouteString] - public ActionResult HandleLogout([Bind(Prefix = "logoutModel")]PostRedirectModel model) + public async Task HandleLogout([Bind(Prefix = "logoutModel")]PostRedirectModel model) { if (ModelState.IsValid == false) { return CurrentUmbracoPage(); } - if (_membershipHelper.IsLoggedIn()) + if (_websiteSecurityAccessor.WebsiteSecurity.IsLoggedIn()) { - FormsAuthentication.SignOut(); + await _websiteSecurityAccessor.WebsiteSecurity.LogOutAsync(); } TempData["LogoutSuccess"] = true; - //if there is a specified path to redirect to then use it + // If there is a specified path to redirect to then use it. if (model.RedirectUrl.IsNullOrWhiteSpace() == false) { return Redirect(model.RedirectUrl); } - //redirect to current page by default - + // Redirect to current page by default. return RedirectToCurrentUmbracoPage(); } } diff --git a/src/Umbraco.Web.Website/Controllers/UmbProfileController.cs b/src/Umbraco.Web.Website/Controllers/UmbProfileController.cs new file mode 100644 index 0000000000..cc23786c4b --- /dev/null +++ b/src/Umbraco.Web.Website/Controllers/UmbProfileController.cs @@ -0,0 +1,64 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Core; +using Umbraco.Core.Cache; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; +using Umbraco.Core.Persistence; +using Umbraco.Core.Security; +using Umbraco.Core.Services; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; + +namespace Umbraco.Web.Website.Controllers +{ + [UmbracoMemberAuthorize] + public class UmbProfileController : SurfaceController + { + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; + + public UmbProfileController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, + ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, + IPublishedUrlProvider publishedUrlProvider, IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) + { + _websiteSecurityAccessor = websiteSecurityAccessor; + } + + [HttpPost] + [ValidateAntiForgeryToken] + [ValidateUmbracoFormRouteString] + public async Task HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model) + { + if (ModelState.IsValid == false) + { + return CurrentUmbracoPage(); + } + + var result = await _websiteSecurityAccessor.WebsiteSecurity.UpdateMemberProfileAsync(model); + switch (result.Status) + { + case UpdateMemberProfileStatus.Success: + break; + case UpdateMemberProfileStatus.Error: + // Don't add a field level error, just model level. + ModelState.AddModelError("profileModel", result.ErrorMessage); + return CurrentUmbracoPage(); + default: + throw new ArgumentOutOfRangeException(); + } + + TempData["ProfileUpdateSuccess"] = true; + + // If there is a specified path to redirect to then use it. + if (model.RedirectUrl.IsNullOrWhiteSpace() == false) + { + return Redirect(model.RedirectUrl); + } + + // Redirect to current page by default. + return RedirectToCurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/Controllers/UmbRegisterController.cs b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs similarity index 56% rename from src/Umbraco.Web/Controllers/UmbRegisterController.cs rename to src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs index 30720eb776..9542a2bf75 100644 --- a/src/Umbraco.Web/Controllers/UmbRegisterController.cs +++ b/src/Umbraco.Web.Website/Controllers/UmbRegisterController.cs @@ -1,37 +1,34 @@ using System; -using System.Web.Mvc; -using System.Web.Security; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; +using Umbraco.Core.Models.Security; using Umbraco.Core.Persistence; +using Umbraco.Core.Security; using Umbraco.Core.Services; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Web.Security; +using Umbraco.Web.Common.Filters; +using Umbraco.Web.Routing; -namespace Umbraco.Web.Controllers +namespace Umbraco.Web.Website.Controllers { public class UmbRegisterController : SurfaceController { - private readonly MembershipHelper _membershipHelper; - - public UmbRegisterController() - { - } + private readonly IUmbracoWebsiteSecurityAccessor _websiteSecurityAccessor; public UmbRegisterController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, - IProfilingLogger profilingLogger, MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) + IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider, IUmbracoWebsiteSecurityAccessor websiteSecurityAccessor) + : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger, publishedUrlProvider) { - _membershipHelper = membershipHelper; + _websiteSecurityAccessor = websiteSecurityAccessor; } [HttpPost] [ValidateAntiForgeryToken] [ValidateUmbracoFormRouteString] - public ActionResult HandleRegisterMember([Bind(Prefix = "registerModel")]RegisterModel model) + public async Task HandleRegisterMember([Bind(Prefix = "registerModel")]RegisterModel model) { if (ModelState.IsValid == false) { @@ -39,60 +36,52 @@ namespace Umbraco.Web.Controllers } // U4-10762 Server error with "Register Member" snippet (Cannot save member with empty name) - // If name field is empty, add the email address instead + // If name field is empty, add the email address instead. if (string.IsNullOrEmpty(model.Name) && string.IsNullOrEmpty(model.Email) == false) { model.Name = model.Email; } - MembershipCreateStatus status; - var member = _membershipHelper.RegisterMember(model, out status, model.LoginOnSuccess); + var result = await _websiteSecurityAccessor.WebsiteSecurity.RegisterMemberAsync(model, model.LoginOnSuccess); - switch (status) + switch (result) { - case MembershipCreateStatus.Success: + case RegisterMemberStatus.Success: TempData["FormSuccess"] = true; - //if there is a specified path to redirect to then use it + // If there is a specified path to redirect to then use it. if (model.RedirectUrl.IsNullOrWhiteSpace() == false) { return Redirect(model.RedirectUrl); } - //redirect to current page by default + // Redirect to current page by default. return RedirectToCurrentUmbracoPage(); - case MembershipCreateStatus.InvalidUserName: + case RegisterMemberStatus.InvalidUserName: ModelState.AddModelError((model.UsernameIsEmail || model.Username == null) ? "registerModel.Email" : "registerModel.Username", "Username is not valid"); break; - case MembershipCreateStatus.InvalidPassword: + case RegisterMemberStatus.InvalidPassword: ModelState.AddModelError("registerModel.Password", "The password is not strong enough"); break; - case MembershipCreateStatus.InvalidQuestion: - case MembershipCreateStatus.InvalidAnswer: - // TODO: Support q/a http://issues.umbraco.org/issue/U4-3213 - throw new NotImplementedException(status.ToString()); - case MembershipCreateStatus.InvalidEmail: + case RegisterMemberStatus.InvalidEmail: ModelState.AddModelError("registerModel.Email", "Email is invalid"); break; - case MembershipCreateStatus.DuplicateUserName: + case RegisterMemberStatus.DuplicateUserName: ModelState.AddModelError((model.UsernameIsEmail || model.Username == null) ? "registerModel.Email" : "registerModel.Username", "A member with this username already exists."); break; - case MembershipCreateStatus.DuplicateEmail: + case RegisterMemberStatus.DuplicateEmail: ModelState.AddModelError("registerModel.Email", "A member with this e-mail address already exists"); break; - case MembershipCreateStatus.UserRejected: - case MembershipCreateStatus.InvalidProviderUserKey: - case MembershipCreateStatus.DuplicateProviderUserKey: - case MembershipCreateStatus.ProviderError: - //don't add a field level error, just model level - ModelState.AddModelError("registerModel", "An error occurred creating the member: " + status); + case RegisterMemberStatus.Error: + // Don't add a field level error, just model level. + ModelState.AddModelError("registerModel", $"An error occurred creating the member: {result}"); break; default: throw new ArgumentOutOfRangeException(); @@ -100,6 +89,5 @@ namespace Umbraco.Web.Controllers return CurrentUmbracoPage(); } - } } diff --git a/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs b/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteServiceCollectionExtensions.cs similarity index 94% rename from src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs rename to src/Umbraco.Web.Website/Extensions/UmbracoWebsiteServiceCollectionExtensions.cs index 317afedc7a..036d66128d 100644 --- a/src/Umbraco.Web.Website/Extensions/UmbracoWebstiteServiceCollectionExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/UmbracoWebsiteServiceCollectionExtensions.cs @@ -5,7 +5,7 @@ using Umbraco.Web.Website.ViewEngines; namespace Umbraco.Extensions { - public static class UmbracoWebstiteServiceCollectionExtensions + public static class UmbracoWebsiteServiceCollectionExtensions { public static void AddUmbracoWebsite(this IServiceCollection services) { diff --git a/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs b/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs new file mode 100644 index 0000000000..90e80537ec --- /dev/null +++ b/src/Umbraco.Web.Website/Security/UmbracoWebsiteSecurity.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Http; +using Umbraco.Core.Models.Security; +using Umbraco.Core.Security; + +namespace Umbraco.Web.Website.Security +{ + public class UmbracoWebsiteSecurity : IUmbracoWebsiteSecurity + { + private readonly IHttpContextAccessor _httpContextAccessor; + + public UmbracoWebsiteSecurity(IHttpContextAccessor httpContextAccessor) + { + _httpContextAccessor = httpContextAccessor; + } + + /// + public Task RegisterMemberAsync(RegisterModel model, bool logMemberIn = true) + { + throw new System.NotImplementedException(); + } + + /// + public Task UpdateMemberProfileAsync(ProfileModel model) + { + throw new System.NotImplementedException(); + } + + /// + public bool IsLoggedIn() + { + var httpContext = _httpContextAccessor.HttpContext; + return httpContext?.User != null && httpContext.User.Identity.IsAuthenticated; + } + + /// + public Task LoginAsync(string username, string password) + { + throw new System.NotImplementedException(); + } + + /// + public async Task LogOutAsync() + { + await _httpContextAccessor.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + } + + /// + public bool IsMemberAuthorized(IEnumerable allowTypes = null, IEnumerable allowGroups = null, IEnumerable allowMembers = null) + { + throw new System.NotImplementedException(); + } + } +} diff --git a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj index daba18d51b..55cfa3e44d 100644 --- a/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj +++ b/src/Umbraco.Web.Website/Umbraco.Web.Website.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1 diff --git a/src/Umbraco.Web/Controllers/UmbLoginController.cs b/src/Umbraco.Web/Controllers/UmbLoginController.cs deleted file mode 100644 index 1f3faf7a43..0000000000 --- a/src/Umbraco.Web/Controllers/UmbLoginController.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System.Web.Mvc; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Services; -using Umbraco.Web.Security; - -namespace Umbraco.Web.Controllers -{ - public class UmbLoginController : SurfaceController - { - private readonly MembershipHelper _membershipHelper; - - public UmbLoginController() - { - } - - public UmbLoginController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, - MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) - { - _membershipHelper = membershipHelper; - } - - [HttpPost] - [ValidateAntiForgeryToken] - [ValidateUmbracoFormRouteString] - public ActionResult HandleLogin([Bind(Prefix = "loginModel")]LoginModel model) - { - if (ModelState.IsValid == false) - { - return CurrentUmbracoPage(); - } - - if (_membershipHelper.Login(model.Username, model.Password) == false) - { - //don't add a field level error, just model level - ModelState.AddModelError("loginModel", "Invalid username or password"); - return CurrentUmbracoPage(); - } - - TempData["LoginSuccess"] = true; - - //if there is a specified path to redirect to then use it - if (model.RedirectUrl.IsNullOrWhiteSpace() == false) - { - // validate the redirect url - // if it's not a local url we'll redirect to the root of the current site - return Redirect(Url.IsLocalUrl(model.RedirectUrl) - ? model.RedirectUrl - : CurrentPage.AncestorOrSelf(1).Url()); - } - - //redirect to current page by default - - return RedirectToCurrentUmbracoPage(); - } - } -} diff --git a/src/Umbraco.Web/Controllers/UmbProfileController.cs b/src/Umbraco.Web/Controllers/UmbProfileController.cs deleted file mode 100644 index 88edee26c8..0000000000 --- a/src/Umbraco.Web/Controllers/UmbProfileController.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Web.Mvc; -using Umbraco.Web.Models; -using Umbraco.Web.Mvc; -using Umbraco.Core.Security; -using Umbraco.Core; -using Umbraco.Core.Cache; -using Umbraco.Core.Logging; -using Umbraco.Core.Persistence; -using Umbraco.Core.Services; -using Umbraco.Web.Security; - -namespace Umbraco.Web.Controllers -{ - [MemberAuthorize] - public class UmbProfileController : SurfaceController - { - private readonly MembershipHelper _membershipHelper; - - public UmbProfileController() - { } - - public UmbProfileController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, - ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, - MembershipHelper membershipHelper) - : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) - { - _membershipHelper = membershipHelper; - } - - [HttpPost] - [ValidateAntiForgeryToken] - [ValidateUmbracoFormRouteString] - public ActionResult HandleUpdateProfile([Bind(Prefix = "profileModel")] ProfileModel model) - { - if (ModelState.IsValid == false) - { - return CurrentUmbracoPage(); - } - - var updateAttempt = _membershipHelper.UpdateMemberProfile(model); - if (updateAttempt.Success == false) - { - //don't add a field level error, just model level - ModelState.AddModelError("profileModel", updateAttempt.Exception.Message); - return CurrentUmbracoPage(); - } - - TempData["ProfileUpdateSuccess"] = true; - - //if there is a specified path to redirect to then use it - if (model.RedirectUrl.IsNullOrWhiteSpace() == false) - { - return Redirect(model.RedirectUrl); - } - - //redirect to current page by default - return RedirectToCurrentUmbracoPage(); - } - } -} diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs index 6d762afcd9..1e26782d4a 100644 --- a/src/Umbraco.Web/Security/MembershipHelper.cs +++ b/src/Umbraco.Web/Security/MembershipHelper.cs @@ -1,20 +1,20 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web.Security; using Microsoft.Extensions.Logging; using Umbraco.Core; -using Umbraco.Core.Models; -using Umbraco.Web.Models; -using Umbraco.Web.PublishedCache; using Umbraco.Core.Cache; -using Umbraco.Web.Composing; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.Models.Security; using Umbraco.Core.Services; using Umbraco.Core.Strings; using Umbraco.Web.Editors; +using Umbraco.Web.Models; +using Umbraco.Web.PublishedCache; using Umbraco.Web.Security.Providers; -using System.ComponentModel.DataAnnotations; namespace Umbraco.Web.Security { @@ -443,7 +443,7 @@ namespace Umbraco.Web.Security return null; } - var model = ProfileModel.CreateModel(); + var model = new ProfileModel(); model.Name = member.Name; model.MemberTypeAlias = member.ContentTypeAlias; @@ -458,7 +458,6 @@ namespace Umbraco.Web.Security model.LastActivityDate = membershipUser.LastActivityDate; model.LastPasswordChangedDate = membershipUser.LastPasswordChangedDate; - var memberType = _memberTypeService.Get(member.ContentTypeId); var builtIns = ConventionsHelper.GetStandardPropertyTypeStubs(_shortStringHelper).Select(x => x.Key).ToArray(); diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b54df88855..8157a90715 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -142,6 +142,7 @@ + @@ -220,8 +221,6 @@ - - @@ -236,13 +235,10 @@ - - - @@ -253,10 +249,8 @@ - - diff --git a/src/umbraco-netcore-only.sln b/src/umbraco-netcore-only.sln new file mode 100644 index 0000000000..f9e749c59d --- /dev/null +++ b/src/umbraco-netcore-only.sln @@ -0,0 +1,205 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29209.152 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4-3B4E-40A3-A309-F3CB4F0E125F}" + ProjectSection(SolutionItems) = preProject + ..\build\build-bootstrap.ps1 = ..\build\build-bootstrap.ps1 + ..\build\build.ps1 = ..\build\build.ps1 + ..\NuGet.Config = ..\NuGet.Config + SolutionInfo.cs = SolutionInfo.cs + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{FD962632-184C-4005-A5F3-E705D92FC645}" + ProjectSection(SolutionItems) = preProject + ..\.github\BUILD.md = ..\.github\BUILD.md + ..\.github\CLEAR.md = ..\.github\CLEAR.md + ..\.github\CODE_OF_CONDUCT.md = ..\.github\CODE_OF_CONDUCT.md + ..\.github\CONTRIBUTING.md = ..\.github\CONTRIBUTING.md + ..\.github\CONTRIBUTING_DETAILED.md = ..\.github\CONTRIBUTING_DETAILED.md + ..\.github\CONTRIBUTION_GUIDELINES.md = ..\.github\CONTRIBUTION_GUIDELINES.md + ..\.github\PULL_REQUEST_TEMPLATE.md = ..\.github\PULL_REQUEST_TEMPLATE.md + ..\.github\README.md = ..\.github\README.md + ..\.github\REVIEW_PROCESS.md = ..\.github\REVIEW_PROCESS.md + ..\.github\V8_GETTING_STARTED.md = ..\.github\V8_GETTING_STARTED.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B5BD12C1-A454-435E-8A46-FF4A364C0382}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuSpecs", "NuSpecs", "{227C3B55-80E5-4E7E-A802-BE16C5128B9D}" + ProjectSection(SolutionItems) = preProject + ..\build\NuSpecs\UmbracoCms.Core.nuspec = ..\build\NuSpecs\UmbracoCms.Core.nuspec + ..\build\NuSpecs\UmbracoCms.nuspec = ..\build\NuSpecs\UmbracoCms.nuspec + ..\build\NuSpecs\UmbracoCms.SqlCe.nuspec = ..\build\NuSpecs\UmbracoCms.SqlCe.nuspec + ..\build\NuSpecs\UmbracoCms.Web.nuspec = ..\build\NuSpecs\UmbracoCms.Web.nuspec + EndProjectSection +EndProject +Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Umbraco.Web.UI.Client", "http://localhost:3961", "{3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}" + ProjectSection(WebsiteProperties) = preProject + UseIISExpress = "true" + TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5" + Debug.AspNetCompiler.VirtualPath = "/localhost_3961" + Debug.AspNetCompiler.PhysicalPath = "Umbraco.Web.UI.Client\" + Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_3961\" + Debug.AspNetCompiler.Updateable = "true" + Debug.AspNetCompiler.ForceOverwrite = "true" + Debug.AspNetCompiler.FixedNames = "false" + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.VirtualPath = "/localhost_3961" + Release.AspNetCompiler.PhysicalPath = "Umbraco.Web.UI.Client\" + Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_3961\" + Release.AspNetCompiler.Updateable = "true" + Release.AspNetCompiler.ForceOverwrite = "true" + Release.AspNetCompiler.FixedNames = "false" + Release.AspNetCompiler.Debug = "False" + SlnRelativePath = "Umbraco.Web.UI.Client\" + DefaultWebSiteLanguage = "Visual C#" + StartServerOnDebug = "false" + EndProjectSection +EndProject +Project("{E24C65DC-7377-472B-9ABA-BC803B73C61A}") = "Umbraco.Tests.AcceptanceTest", "http://localhost:58896", "{9E4C8A12-FBE0-4673-8CE2-DF99D5D57817}" + ProjectSection(WebsiteProperties) = preProject + UseIISExpress = "true" + TargetFrameworkMoniker = ".NETFramework,Version%3Dv4.5" + Debug.AspNetCompiler.VirtualPath = "/localhost_62926" + Debug.AspNetCompiler.PhysicalPath = "Umbraco.Tests.AcceptanceTest\" + Debug.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_62926\" + Debug.AspNetCompiler.Updateable = "true" + Debug.AspNetCompiler.ForceOverwrite = "true" + Debug.AspNetCompiler.FixedNames = "false" + Debug.AspNetCompiler.Debug = "True" + Release.AspNetCompiler.VirtualPath = "/localhost_62926" + Release.AspNetCompiler.PhysicalPath = "Umbraco.Tests.AcceptanceTest\" + Release.AspNetCompiler.TargetPath = "PrecompiledWeb\localhost_62926\" + Release.AspNetCompiler.Updateable = "true" + Release.AspNetCompiler.ForceOverwrite = "true" + Release.AspNetCompiler.FixedNames = "false" + Release.AspNetCompiler.Debug = "False" + SlnRelativePath = "Umbraco.Tests.AcceptanceTest\" + DefaultWebSiteLanguage = "Visual C#" + StartServerOnDebug = "false" + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{E3F9F378-AFE1-40A5-90BD-82833375DBFE}" + ProjectSection(SolutionItems) = preProject + ..\build\NuSpecs\tools\applications.config.install.xdt = ..\build\NuSpecs\tools\applications.config.install.xdt + ..\build\NuSpecs\tools\ClientDependency.config.install.xdt = ..\build\NuSpecs\tools\ClientDependency.config.install.xdt + ..\build\NuSpecs\tools\install.ps1 = ..\build\NuSpecs\tools\install.ps1 + ..\build\NuSpecs\tools\Readme.txt = ..\build\NuSpecs\tools\Readme.txt + ..\build\NuSpecs\tools\ReadmeUpgrade.txt = ..\build\NuSpecs\tools\ReadmeUpgrade.txt + ..\build\NuSpecs\tools\serilog.config.install.xdt = ..\build\NuSpecs\tools\serilog.config.install.xdt + ..\build\NuSpecs\tools\Web.config.install.xdt = ..\build\NuSpecs\tools\Web.config.install.xdt + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{5B03EF4E-E0AC-4905-861B-8C3EC1A0D458}" + ProjectSection(SolutionItems) = preProject + ..\build\NuSpecs\build\Umbraco.Cms.props = ..\build\NuSpecs\build\Umbraco.Cms.props + ..\build\NuSpecs\build\Umbraco.Cms.targets = ..\build\NuSpecs\build\Umbraco.Cms.targets + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DocTools", "DocTools", "{53594E5B-64A2-4545-8367-E3627D266AE8}" + ProjectSection(SolutionItems) = preProject + ApiDocs\docfx.filter.yml = ApiDocs\docfx.filter.yml + ApiDocs\docfx.json = ApiDocs\docfx.json + ApiDocs\index.md = ApiDocs\index.md + ApiDocs\toc.yml = ApiDocs\toc.yml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IssueTemplates", "IssueTemplates", "{C7311C00-2184-409B-B506-52A5FAEA8736}" + ProjectSection(SolutionItems) = preProject + ..\.github\ISSUE_TEMPLATE\1_Bug.md = ..\.github\ISSUE_TEMPLATE\1_Bug.md + ..\.github\ISSUE_TEMPLATE\2_Feature_request.md = ..\.github\ISSUE_TEMPLATE\2_Feature_request.md + ..\.github\ISSUE_TEMPLATE\3_Support_question.md = ..\.github\ISSUE_TEMPLATE\3_Support_question.md + ..\.github\ISSUE_TEMPLATE\4_Documentation_issue.md = ..\.github\ISSUE_TEMPLATE\4_Documentation_issue.md + ..\.github\ISSUE_TEMPLATE\5_Security_issue.md = ..\.github\ISSUE_TEMPLATE\5_Security_issue.md + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Core", "Umbraco.Core\Umbraco.Core.csproj", "{29AA69D9-B597-4395-8D42-43B1263C240A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.ModelsBuilder.Embedded", "Umbraco.ModelsBuilder.Embedded\Umbraco.ModelsBuilder.Embedded.csproj", "{52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Infrastructure", "Umbraco.Infrastructure\Umbraco.Infrastructure.csproj", "{3AE7BF57-966B-45A5-910A-954D7C554441}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.PublishedCache.NuCache", "Umbraco.PublishedCache.NuCache\Umbraco.PublishedCache.NuCache.csproj", "{F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.BackOffice", "Umbraco.Web.BackOffice\Umbraco.Web.BackOffice.csproj", "{9B95EEF7-63FE-4432-8C63-166BE9C1A929}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.UI.NetCore", "Umbraco.Web.UI.NetCore\Umbraco.Web.UI.NetCore.csproj", "{DCDFE97C-5630-4F6F-855D-8AEEB96556A5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.Website", "Umbraco.Web.Website\Umbraco.Web.Website.csproj", "{5A246D54-3109-4D2B-BE7D-FC0787D126AE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Tests.Common", "Umbraco.Tests.Common\Umbraco.Tests.Common.csproj", "{A499779C-1B3B-48A8-B551-458E582E6E96}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Tests.UnitTests", "Umbraco.Tests.UnitTests\Umbraco.Tests.UnitTests.csproj", "{9102ABDF-E537-4E46-B525-C9ED4833EED0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Umbraco.Web.Common", "Umbraco.Web.Common\Umbraco.Web.Common.csproj", "{79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3819A550-DCEC-4153-91B4-8BA9F7F0B9B4}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {9E4C8A12-FBE0-4673-8CE2-DF99D5D57817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E4C8A12-FBE0-4673-8CE2-DF99D5D57817}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {29AA69D9-B597-4395-8D42-43B1263C240A}.Release|Any CPU.Build.0 = Release|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52AC0BA8-A60E-4E36-897B-E8B97A54ED1C}.Release|Any CPU.Build.0 = Release|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AE7BF57-966B-45A5-910A-954D7C554441}.Release|Any CPU.Build.0 = Release|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6DE8DA0-07CC-4EF2-8A59-2BC81DBB3830}.Release|Any CPU.Build.0 = Release|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9B95EEF7-63FE-4432-8C63-166BE9C1A929}.Release|Any CPU.Build.0 = Release|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DCDFE97C-5630-4F6F-855D-8AEEB96556A5}.Release|Any CPU.Build.0 = Release|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A246D54-3109-4D2B-BE7D-FC0787D126AE}.Release|Any CPU.Build.0 = Release|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A499779C-1B3B-48A8-B551-458E582E6E96}.Release|Any CPU.Build.0 = Release|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9102ABDF-E537-4E46-B525-C9ED4833EED0}.Release|Any CPU.Build.0 = Release|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79E4293D-C92C-4649-AEC8-F1EFD95BDEB1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {227C3B55-80E5-4E7E-A802-BE16C5128B9D} = {2849E9D4-3B4E-40A3-A309-F3CB4F0E125F} + {9E4C8A12-FBE0-4673-8CE2-DF99D5D57817} = {B5BD12C1-A454-435E-8A46-FF4A364C0382} + {E3F9F378-AFE1-40A5-90BD-82833375DBFE} = {227C3B55-80E5-4E7E-A802-BE16C5128B9D} + {5B03EF4E-E0AC-4905-861B-8C3EC1A0D458} = {227C3B55-80E5-4E7E-A802-BE16C5128B9D} + {53594E5B-64A2-4545-8367-E3627D266AE8} = {FD962632-184C-4005-A5F3-E705D92FC645} + {C7311C00-2184-409B-B506-52A5FAEA8736} = {FD962632-184C-4005-A5F3-E705D92FC645} + {A499779C-1B3B-48A8-B551-458E582E6E96} = {B5BD12C1-A454-435E-8A46-FF4A364C0382} + {9102ABDF-E537-4E46-B525-C9ED4833EED0} = {B5BD12C1-A454-435E-8A46-FF4A364C0382} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {7A0F2E34-D2AF-4DAB-86A0-7D7764B3D0EC} + EndGlobalSection +EndGlobal