From 614dc8f4d19e6a0c618fa1ba42ff1e6b6979883e Mon Sep 17 00:00:00 2001 From: Robert Stocks Date: Tue, 27 Aug 2013 16:10:04 +0100 Subject: [PATCH 01/14] Fix U4-2711 add Null Check to ToXMl method Fixes Object reference not set to an instance of an object. at umbraco.editorControls.imagecropper.DataTypeData.ToXMl(XmlDocument data) --- src/umbraco.editorControls/imagecropper/DataTypeData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/umbraco.editorControls/imagecropper/DataTypeData.cs b/src/umbraco.editorControls/imagecropper/DataTypeData.cs index 7c667aaa24..a658106f9f 100644 --- a/src/umbraco.editorControls/imagecropper/DataTypeData.cs +++ b/src/umbraco.editorControls/imagecropper/DataTypeData.cs @@ -8,7 +8,7 @@ namespace umbraco.editorControls.imagecropper public override XmlNode ToXMl(XmlDocument data) { - if (Value.ToString() != "") { + if (Value!=null && Value.ToString() != "") { XmlDocument xd = new XmlDocument(); xd.LoadXml(Value.ToString()); return data.ImportNode(xd.DocumentElement, true); From 8274883fa54aa9df24a08920e090f2ea99e42a0f Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 28 Aug 2013 09:09:21 +0200 Subject: [PATCH 02/14] Bump version number to 6.2.0 --- build/Build.bat | 2 +- src/Umbraco.Core/Configuration/UmbracoVersion.cs | 2 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build/Build.bat b/build/Build.bat index d1335ea93e..cf9c5ace51 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -1,5 +1,5 @@ @ECHO OFF -SET release=6.1.4 +SET release=6.2.0 SET comment= SET version=%release% diff --git a/src/Umbraco.Core/Configuration/UmbracoVersion.cs b/src/Umbraco.Core/Configuration/UmbracoVersion.cs index 9863edfee3..f1b8d39765 100644 --- a/src/Umbraco.Core/Configuration/UmbracoVersion.cs +++ b/src/Umbraco.Core/Configuration/UmbracoVersion.cs @@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration { public class UmbracoVersion { - private static readonly Version Version = new Version("6.1.4"); + private static readonly Version Version = new Version("6.2.0"); /// /// Gets the current version of Umbraco. diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 56e7e3389d..fb88c64d3a 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2618,9 +2618,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" True True - 6140 + 6200 / - http://localhost:6140 + http://localhost:6200 False False From f26d759c8444cf7f49e82f82f2c1cd3ca2e236fc Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 28 Aug 2013 13:36:04 +0200 Subject: [PATCH 03/14] Moved controllers and models as per Shannon's suggestion Added LoginStatus and updated Register Updated to use CDF instead of - - +@Html.RenderJsHere() @using (Html.BeginUmbracoForm("HandleLogin")) { diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml new file mode 100644 index 0000000000..72d63e2857 --- /dev/null +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml @@ -0,0 +1,29 @@ +@inherits Umbraco.Web.Macros.PartialViewMacroPage +@using ClientDependency.Core.Mvc +@using Umbraco.Web.Models +@using Umbraco.Web.Controllers + +@{ + var loginStatusModel = new LoginStatusModel(); + + Html.EnableClientValidation(); + Html.EnableUnobtrusiveJavaScript(); + Html.RequiresJs("/umbraco_client/ui/jquery.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); +} + +@Html.RenderJsHere() + +@if (loginStatusModel.IsLoggedIn) +{ +

You are currently logged in as @loginStatusModel.Name

+ + using (Html.BeginUmbracoForm("HandleLogout")) + { +
+ Logout + +
+ } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml index 46422928a6..2c94c04acc 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml @@ -2,47 +2,21 @@ @using System.Web.Mvc.Html @using ClientDependency.Core.Mvc -@using umbraco.cms.businesslogic.member -@using Umbraco.Web.UmbracoModels -@using Umbraco.Web.UmbracoControllers +@using Umbraco.Web.Models +@using Umbraco.Web.Controllers @{ + var registerModel = new RegisterModel(); + registerModel.FillModel(registerModel, Model.MacroParameters); + Html.EnableClientValidation(); Html.EnableUnobtrusiveJavaScript(); - - // TODO: CDF doesn't work at the moment, Shannon is looking at it - //Html.RequiresJs("/umbraco_client/ui/jquery.js"); - //Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); - //Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); - - // TODO: Make a helper for this - var memberTypeAlias = "UmbracoMember"; - if (Model.MacroParameters.Any() && Model.MacroParameters.ContainsKey("memberTypeAlias")) - { - var alias = Model.MacroParameters["memberTypeAlias"]; - if (string.IsNullOrWhiteSpace(alias.ToString()) == false) - { - memberTypeAlias = alias.ToString(); - } - } - - var registerModel = new RegisterModel - { - MemberProperties = new List(), - MemberTypeAlias = memberTypeAlias - }; - - // TODO: Fill model somewhere else - var memberType = MemberType.GetByAlias(registerModel.MemberTypeAlias); - foreach (var prop in memberType.PropertyTypes.Where(memberType.MemberCanEdit)) - { - registerModel.MemberProperties.Add(new UmbracoProperty {Alias = prop.Alias, Name = prop.Name, Value = string.Empty}); - } + Html.RequiresJs("/umbraco_client/ui/jquery.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); } - - - +@Html.RenderJsHere() @using (Html.BeginUmbracoForm("HandleRegisterMember")) { diff --git a/src/Umbraco.Web/UmbracoControllers/LoginController.cs b/src/Umbraco.Web/Controllers/LoginController.cs similarity index 90% rename from src/Umbraco.Web/UmbracoControllers/LoginController.cs rename to src/Umbraco.Web/Controllers/LoginController.cs index 0b58073c70..df6675dfd8 100644 --- a/src/Umbraco.Web/UmbracoControllers/LoginController.cs +++ b/src/Umbraco.Web/Controllers/LoginController.cs @@ -1,10 +1,10 @@ using System.Linq; using System.Web.Mvc; using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; using Umbraco.Web.Mvc; -using Umbraco.Web.UmbracoModels; -namespace Umbraco.Web.UmbracoControllers +namespace Umbraco.Web.Controllers { public class LoginController : SurfaceController { diff --git a/src/Umbraco.Web/Controllers/LoginStatusController.cs b/src/Umbraco.Web/Controllers/LoginStatusController.cs new file mode 100644 index 0000000000..428348f9bb --- /dev/null +++ b/src/Umbraco.Web/Controllers/LoginStatusController.cs @@ -0,0 +1,30 @@ +using System.Linq; +using System.Web.Mvc; +using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Web.Controllers +{ + public class LoginStatusController : SurfaceController + { + [HttpPost] + public ActionResult HandleLogout([Bind(Prefix = "loginStatusModel")]LoginStatusModel model) + { + // TODO: Use new Member API + if (ModelState.IsValid) + { + if (Member.IsLoggedOn()) + { + var memberId = Member.CurrentMemberId(); + Member.RemoveMemberFromCache(memberId); + Member.ClearMemberFromClient(memberId); + } + + return Redirect("/"); + } + + return CurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/UmbracoControllers/RegisterController.cs b/src/Umbraco.Web/Controllers/RegisterController.cs similarity index 94% rename from src/Umbraco.Web/UmbracoControllers/RegisterController.cs rename to src/Umbraco.Web/Controllers/RegisterController.cs index e3b9e66d3b..402a88b1b9 100644 --- a/src/Umbraco.Web/UmbracoControllers/RegisterController.cs +++ b/src/Umbraco.Web/Controllers/RegisterController.cs @@ -3,10 +3,10 @@ using System.Web.Mvc; using System.Xml; using umbraco.BusinessLogic; using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; using Umbraco.Web.Mvc; -using Umbraco.Web.UmbracoModels; -namespace Umbraco.Web.UmbracoControllers +namespace Umbraco.Web.Controllers { public class RegisterController : SurfaceController { diff --git a/src/Umbraco.Web/UmbracoModels/LoginModel.cs b/src/Umbraco.Web/Models/LoginModel.cs similarity index 80% rename from src/Umbraco.Web/UmbracoModels/LoginModel.cs rename to src/Umbraco.Web/Models/LoginModel.cs index 4cd627e490..f0cea26b0e 100644 --- a/src/Umbraco.Web/UmbracoModels/LoginModel.cs +++ b/src/Umbraco.Web/Models/LoginModel.cs @@ -1,7 +1,6 @@ using System.ComponentModel.DataAnnotations; -using System.Linq; -namespace Umbraco.Web.UmbracoModels +namespace Umbraco.Web.Models { public class LoginModel { diff --git a/src/Umbraco.Web/Models/LoginStatusModel.cs b/src/Umbraco.Web/Models/LoginStatusModel.cs new file mode 100644 index 0000000000..853d265c5e --- /dev/null +++ b/src/Umbraco.Web/Models/LoginStatusModel.cs @@ -0,0 +1,24 @@ +using umbraco.cms.businesslogic.member; + +namespace Umbraco.Web.Models +{ + public class LoginStatusModel + { + public LoginStatusModel() + { + //TODO Use new Member API + if (Member.IsLoggedOn()) + { + this.Name = Member.GetCurrentMember().Text; + this.Username = Member.GetCurrentMember().LoginName; + this.Email = Member.GetCurrentMember().Email; + this.IsLoggedIn = true; + } + } + + public string Name { get; set; } + public string Username { get; set; } + public string Email { get; set; } + public bool IsLoggedIn { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/RegisterModel.cs b/src/Umbraco.Web/Models/RegisterModel.cs new file mode 100644 index 0000000000..276170bb6f --- /dev/null +++ b/src/Umbraco.Web/Models/RegisterModel.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using umbraco.cms.businesslogic.member; +using Umbraco.Core; + +namespace Umbraco.Web.Models +{ + public class RegisterModel + { + [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")] + public string Email { get; set; } + + [Required] + public string Password { get; set; } + + public string MemberTypeAlias { get; set; } + + public List MemberProperties { get; set; } + + public void FillModel(RegisterModel registerModel, IDictionary macroParameters) + { + registerModel.MemberTypeAlias = macroParameters.GetValueAsString("memberTypeAlias", "UmbracoMember"); + + registerModel.MemberProperties = new List(); + + var memberType = MemberType.GetByAlias(registerModel.MemberTypeAlias); + + var memberTypeProperties = memberType.PropertyTypes.ToList(); + + if (memberTypeProperties.Where(memberType.MemberCanEdit).Any()) + { + memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList(); + } + + foreach (var prop in memberTypeProperties) + { + registerModel.MemberProperties.Add(new UmbracoProperty { Alias = prop.Alias, Name = prop.Name, Value = string.Empty }); + } + } + } + + public class UmbracoProperty + { + public string Alias { get; set; } + public string Value { get; set; } + public string Name { get; set; } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 0674411598..486ec8cad1 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -291,11 +291,13 @@ + - - - + + + + @@ -395,7 +397,7 @@ ASPXCodeBehind - + diff --git a/src/Umbraco.Web/UmbracoModels/RegisterModel.cs b/src/Umbraco.Web/UmbracoModels/RegisterModel.cs deleted file mode 100644 index 498b68db90..0000000000 --- a/src/Umbraco.Web/UmbracoModels/RegisterModel.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; - -namespace Umbraco.Web.UmbracoModels -{ - public class RegisterModel - { - [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")] - public string Email { get; set; } - - [Required] - public string Password { get; set; } - - public string MemberTypeAlias { get; set; } - - public List MemberProperties { get; set; } - } - - public class UmbracoProperty - { - public string Alias { get; set; } - public string Value { get; set; } - public string Name { get; set; } - } -} From 49637e62febd58b8578a28593cfa40b7482c2f50 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 28 Aug 2013 17:52:06 +0200 Subject: [PATCH 04/14] Updated, more robust versions of the Member template/snippets --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 1 + .../PartialViews/Templates/EditProfile.cshtml | 52 +++++++++++++++ .../PartialViews/Templates/Login.cshtml | 1 + .../PartialViews/Templates/LoginStatus.cshtml | 1 + .../Templates/RegisterMember.cshtml | 25 +++++--- .../Controllers/LoginStatusController.cs | 10 ++- .../Controllers/ProfileController.cs | 50 +++++++++++++++ .../Controllers/RegisterController.cs | 13 +++- src/Umbraco.Web/Models/LoginStatusModel.cs | 12 ++-- src/Umbraco.Web/Models/ProfileModel.cs | 64 +++++++++++++++++++ src/Umbraco.Web/Models/RegisterModel.cs | 60 ++++++++--------- src/Umbraco.Web/Umbraco.Web.csproj | 3 + src/Umbraco.Web/UmbracoProperty.cs | 9 +++ 13 files changed, 254 insertions(+), 47 deletions(-) create mode 100644 src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EditProfile.cshtml create mode 100644 src/Umbraco.Web/Controllers/ProfileController.cs create mode 100644 src/Umbraco.Web/Models/ProfileModel.cs create mode 100644 src/Umbraco.Web/UmbracoProperty.cs diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 3a7efed60c..c39964e6da 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2138,6 +2138,7 @@ + diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EditProfile.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EditProfile.cshtml new file mode 100644 index 0000000000..27457c2f7e --- /dev/null +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/EditProfile.cshtml @@ -0,0 +1,52 @@ +@inherits Umbraco.Web.Macros.PartialViewMacroPage + +@using System.Web.Mvc.Html +@using ClientDependency.Core.Mvc +@using umbraco.cms.businesslogic.member +@using Umbraco.Web +@using Umbraco.Web.Models +@using Umbraco.Web.Controllers + +@{ + var profileModel = new ProfileModel(); + + Html.EnableClientValidation(); + Html.EnableUnobtrusiveJavaScript(); + Html.RequiresJs("/umbraco_client/ui/jquery.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.min.js"); + Html.RequiresJs("/umbraco_client/Application/JQuery/jquery.validate.unobtrusive.min.js"); +} + +@if (Member.IsLoggedOn()) +{ + @Html.RenderJsHere() + + using (Html.BeginUmbracoForm("HandleUpdateProfile")) + { +
+ Edit profile + + @Html.LabelFor(m => profileModel.Name) + @Html.TextBoxFor(m => profileModel.Name) + @Html.ValidationMessageFor(m => profileModel.Name) +
+ + @Html.LabelFor(m => profileModel.Email) + @Html.TextBoxFor(m => profileModel.Email) + @Html.ValidationMessageFor(m => profileModel.Email) +
+ + @for (var i = 0; i < profileModel.MemberProperties.Count; i++) + { + @Html.LabelFor(m => profileModel.MemberProperties[i].Value, profileModel.MemberProperties[i].Name) + @Html.EditorFor(m => profileModel.MemberProperties[i].Value) + @Html.HiddenFor(m => profileModel.MemberProperties[i].Alias) +
+ } + + @Html.HiddenFor(m => profileModel.MemberTypeAlias) + + +
+ } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml index 62b9632ad5..5eb4529001 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/Login.cshtml @@ -2,6 +2,7 @@ @using System.Web.Mvc.Html @using ClientDependency.Core.Mvc +@using Umbraco.Web @using Umbraco.Web.Models @using Umbraco.Web.Controllers diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml index 72d63e2857..d889c67391 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/LoginStatus.cshtml @@ -1,5 +1,6 @@ @inherits Umbraco.Web.Macros.PartialViewMacroPage @using ClientDependency.Core.Mvc +@using Umbraco.Web @using Umbraco.Web.Models @using Umbraco.Web.Controllers diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml index 2c94c04acc..6574c56690 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViews/Templates/RegisterMember.cshtml @@ -2,13 +2,13 @@ @using System.Web.Mvc.Html @using ClientDependency.Core.Mvc +@using Umbraco.Web @using Umbraco.Web.Models @using Umbraco.Web.Controllers @{ var registerModel = new RegisterModel(); - registerModel.FillModel(registerModel, Model.MacroParameters); - + Html.EnableClientValidation(); Html.EnableUnobtrusiveJavaScript(); Html.RequiresJs("/umbraco_client/ui/jquery.js"); @@ -23,6 +23,11 @@
Register Member + @Html.LabelFor(m => registerModel.Name) + @Html.TextBoxFor(m => registerModel.Name) + @Html.ValidationMessageFor(m => registerModel.Name) +
+ @Html.LabelFor(m => registerModel.Email) @Html.TextBoxFor(m => registerModel.Email) @Html.ValidationMessageFor(m => registerModel.Email) @@ -33,14 +38,16 @@ @Html.ValidationMessageFor(m => registerModel.Password)
- @for (var i = 0; i < registerModel.MemberProperties.Count; i++) - { - @Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name) - @Html.EditorFor(m => registerModel.MemberProperties[i].Value) - @Html.HiddenFor(m => registerModel.MemberProperties[i].Alias) -
+ @if (registerModel.MemberProperties != null) { + for (var i = 0; i < registerModel.MemberProperties.Count; i++) + { + @Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name) + @Html.EditorFor(m => registerModel.MemberProperties[i].Value) + @Html.HiddenFor(m => registerModel.MemberProperties[i].Alias) +
+ } } - + @Html.HiddenFor(m => registerModel.MemberTypeAlias) diff --git a/src/Umbraco.Web/Controllers/LoginStatusController.cs b/src/Umbraco.Web/Controllers/LoginStatusController.cs index 428348f9bb..4dbe5836db 100644 --- a/src/Umbraco.Web/Controllers/LoginStatusController.cs +++ b/src/Umbraco.Web/Controllers/LoginStatusController.cs @@ -16,9 +16,13 @@ namespace Umbraco.Web.Controllers { if (Member.IsLoggedOn()) { - var memberId = Member.CurrentMemberId(); - Member.RemoveMemberFromCache(memberId); - Member.ClearMemberFromClient(memberId); + var member = Member.GetCurrentMember(); + if (member != null) + { + var memberId = member.Id; + Member.RemoveMemberFromCache(memberId); + Member.ClearMemberFromClient(memberId); + } } return Redirect("/"); diff --git a/src/Umbraco.Web/Controllers/ProfileController.cs b/src/Umbraco.Web/Controllers/ProfileController.cs new file mode 100644 index 0000000000..cfa2d387ca --- /dev/null +++ b/src/Umbraco.Web/Controllers/ProfileController.cs @@ -0,0 +1,50 @@ +using System.Linq; +using System.Web.Mvc; +using System.Xml; +using umbraco.cms.businesslogic.member; +using Umbraco.Web.Models; +using Umbraco.Web.Mvc; + +namespace Umbraco.Web.Controllers +{ + public class ProfileController : SurfaceController + { + [HttpPost] + public ActionResult HandleUpdateProfile([Bind(Prefix="profileModel")]ProfileModel model) + { + //TODO: Use new Member API + if (ModelState.IsValid) + { + var member = Member.GetCurrentMember(); + if (member != null) + { + if (model.Name != null) + { + member.Text = model.Name; + } + + member.Email = model.Email; + member.LoginName = model.Email; + + if (model.MemberProperties != null) + { + foreach (var property in model.MemberProperties.Where(p => p.Value != null)) + { + member.getProperty(property.Alias).Value = property.Value; + } + } + + member.Save(); + + member.XmlGenerate(new XmlDocument()); + + Member.AddMemberToCache(member); + + Response.Redirect("/"); + } + } + + return CurrentUmbracoPage(); + } + } +} diff --git a/src/Umbraco.Web/Controllers/RegisterController.cs b/src/Umbraco.Web/Controllers/RegisterController.cs index 402a88b1b9..ef9c8d9e03 100644 --- a/src/Umbraco.Web/Controllers/RegisterController.cs +++ b/src/Umbraco.Web/Controllers/RegisterController.cs @@ -21,13 +21,22 @@ namespace Umbraco.Web.Controllers var mt = MemberType.GetByAlias(model.MemberTypeAlias) ?? MemberType.MakeNew(user, model.MemberTypeAlias); var member = Member.MakeNew(model.Email, mt, user); + + if (model.Name != null) + { + member.Text = model.Name; + } + member.Email = model.Email; member.LoginName = model.Email; member.Password = model.Password; - foreach (var property in model.MemberProperties) + if (model.MemberProperties != null) { - member.getProperty(property.Alias).Value = property.Value; + foreach (var property in model.MemberProperties.Where(p => p.Value != null)) + { + member.getProperty(property.Alias).Value = property.Value; + } } member.Save(); diff --git a/src/Umbraco.Web/Models/LoginStatusModel.cs b/src/Umbraco.Web/Models/LoginStatusModel.cs index 853d265c5e..9be7602541 100644 --- a/src/Umbraco.Web/Models/LoginStatusModel.cs +++ b/src/Umbraco.Web/Models/LoginStatusModel.cs @@ -9,10 +9,14 @@ namespace Umbraco.Web.Models //TODO Use new Member API if (Member.IsLoggedOn()) { - this.Name = Member.GetCurrentMember().Text; - this.Username = Member.GetCurrentMember().LoginName; - this.Email = Member.GetCurrentMember().Email; - this.IsLoggedIn = true; + var member = Member.GetCurrentMember(); + if (member != null) + { + this.Name = member.Text; + this.Username = member.LoginName; + this.Email = member.Email; + this.IsLoggedIn = true; + } } } diff --git a/src/Umbraco.Web/Models/ProfileModel.cs b/src/Umbraco.Web/Models/ProfileModel.cs new file mode 100644 index 0000000000..437a53972c --- /dev/null +++ b/src/Umbraco.Web/Models/ProfileModel.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using umbraco.cms.businesslogic.member; + +namespace Umbraco.Web.Models +{ + public class ProfileModel + { + public ProfileModel() + { + if (Member.IsLoggedOn()) + { + //TODO Use new Member API + var member = Member.GetCurrentMember(); + if (member != null) + { + this.Name = member.Text; + + this.Email = member.Email; + + this.MemberProperties = new List(); + + var memberType = MemberType.GetByAlias(member.ContentType.Alias); + var memberTypeProperties = memberType.PropertyTypes.ToList(); + + if (memberTypeProperties.Where(memberType.MemberCanEdit).Any()) + { + memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList(); + } + + foreach (var prop in memberTypeProperties) + { + + var value = string.Empty; + var propValue = member.getProperty(prop.Alias); + if (propValue != null) + { + value = propValue.Value.ToString(); + } + + this.MemberProperties.Add(new UmbracoProperty + { + Alias = prop.Alias, + Name = prop.Name, + Value = value + }); + } + } + } + } + + [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")] + public string Email { get; set; } + + public string Name { get; set; } + + public string MemberTypeAlias { get; set; } + + public List MemberProperties { get; set; } + } +} diff --git a/src/Umbraco.Web/Models/RegisterModel.cs b/src/Umbraco.Web/Models/RegisterModel.cs index 276170bb6f..be3c314ebe 100644 --- a/src/Umbraco.Web/Models/RegisterModel.cs +++ b/src/Umbraco.Web/Models/RegisterModel.cs @@ -2,12 +2,40 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using umbraco.cms.businesslogic.member; -using Umbraco.Core; namespace Umbraco.Web.Models { public class RegisterModel { + public RegisterModel() + { + this.MemberTypeAlias = "UmbracoMember"; + + var memberType = MemberType.GetByAlias(this.MemberTypeAlias); + + if (memberType != null) + { + this.MemberProperties = new List(); + + var memberTypeProperties = memberType.PropertyTypes.ToList(); + + if (memberTypeProperties.Where(memberType.MemberCanEdit).Any()) + { + memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList(); + } + + foreach (var prop in memberTypeProperties) + { + this.MemberProperties.Add(new UmbracoProperty + { + Alias = prop.Alias, + Name = prop.Name, + Value = string.Empty + }); + } + } + } + [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")] @@ -16,36 +44,10 @@ namespace Umbraco.Web.Models [Required] public string Password { get; set; } + public string Name { get; set; } + public string MemberTypeAlias { get; set; } public List MemberProperties { get; set; } - - public void FillModel(RegisterModel registerModel, IDictionary macroParameters) - { - registerModel.MemberTypeAlias = macroParameters.GetValueAsString("memberTypeAlias", "UmbracoMember"); - - registerModel.MemberProperties = new List(); - - var memberType = MemberType.GetByAlias(registerModel.MemberTypeAlias); - - var memberTypeProperties = memberType.PropertyTypes.ToList(); - - if (memberTypeProperties.Where(memberType.MemberCanEdit).Any()) - { - memberTypeProperties = memberTypeProperties.Where(memberType.MemberCanEdit).ToList(); - } - - foreach (var prop in memberTypeProperties) - { - registerModel.MemberProperties.Add(new UmbracoProperty { Alias = prop.Alias, Name = prop.Name, Value = string.Empty }); - } - } - } - - public class UmbracoProperty - { - public string Alias { get; set; } - public string Value { get; set; } - public string Name { get; set; } } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 486ec8cad1..b0fab44ff0 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -291,10 +291,12 @@ + + @@ -398,6 +400,7 @@ ASPXCodeBehind + diff --git a/src/Umbraco.Web/UmbracoProperty.cs b/src/Umbraco.Web/UmbracoProperty.cs new file mode 100644 index 0000000000..4e7f17953e --- /dev/null +++ b/src/Umbraco.Web/UmbracoProperty.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Web +{ + public class UmbracoProperty + { + public string Alias { get; set; } + public string Value { get; set; } + public string Name { get; set; } + } +} From 02566589fe7e9f792c0e87807e3ce5c1890b0d27 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Wed, 28 Aug 2013 17:52:44 +0200 Subject: [PATCH 05/14] Added admin permission for change doctype action to the OOB installer --- .../Persistence/Migrations/Initial/BaseDataCreation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index b50102396a..a2963343e3 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -146,7 +146,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial private void CreateUmbracoUserTypeData() { - _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F" }); + _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 1, Alias = "admin", Name = "Administrators", DefaultPermissions = "CADMOSKTPIURZ:5F7" }); _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 2, Alias = "writer", Name = "Writer", DefaultPermissions = "CAH:F" }); _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 3, Alias = "editor", Name = "Editors", DefaultPermissions = "CADMOSKTPUZ:5F" }); _database.Insert("umbracoUserType", "id", false, new UserTypeDto { Id = 4, Alias = "translator", Name = "Translator", DefaultPermissions = "AF" }); From 3fc4f3685950d3436f58b081cfa1cbf7e878b878 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 26 Aug 2013 15:47:48 +0200 Subject: [PATCH 06/14] U4-2549 - fix issue with last chance content finder Conflicts: src/Umbraco.Web/Umbraco.Web.csproj --- .../config/404handlers.Release.config | 2 +- src/Umbraco.Web.UI/config/404handlers.config | 2 +- src/Umbraco.Web/Routing/AliasUrlProvider.cs | 21 ++- .../ContentFinderByNotFoundHandlers.cs | 132 +++++++----------- ...ntentLastChanceFinderByNotFoundHandlers.cs | 101 ++++++++++++++ .../Routing/NotFoundHandlerHelper.cs | 101 ++++++++++++-- src/Umbraco.Web/Umbraco.Web.csproj | 1 + src/Umbraco.Web/WebBootManager.cs | 38 +++-- 8 files changed, 279 insertions(+), 119 deletions(-) create mode 100644 src/Umbraco.Web/Routing/ContentLastChanceFinderByNotFoundHandlers.cs diff --git a/src/Umbraco.Web.UI/config/404handlers.Release.config b/src/Umbraco.Web.UI/config/404handlers.Release.config index 11bdbaf8ef..770f7ca64b 100644 --- a/src/Umbraco.Web.UI/config/404handlers.Release.config +++ b/src/Umbraco.Web.UI/config/404handlers.Release.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/config/404handlers.config b/src/Umbraco.Web.UI/config/404handlers.config index 69bf6f1dd0..b6dd88fa8b 100644 --- a/src/Umbraco.Web.UI/config/404handlers.config +++ b/src/Umbraco.Web.UI/config/404handlers.config @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web/Routing/AliasUrlProvider.cs b/src/Umbraco.Web/Routing/AliasUrlProvider.cs index f8e270a16c..d8846afd60 100644 --- a/src/Umbraco.Web/Routing/AliasUrlProvider.cs +++ b/src/Umbraco.Web/Routing/AliasUrlProvider.cs @@ -88,14 +88,25 @@ namespace Umbraco.Web.Routing #region Utilities - private bool FindByUrlAliasEnabled + private static bool FindByUrlAliasEnabled { get { - var hasFinder = ContentFinderResolver.Current.ContainsType(); - var hasHandler = ContentFinderResolver.Current.ContainsType() - && NotFoundHandlerHelper.CustomHandlerTypes.Contains(typeof(global::umbraco.SearchForAlias)); - return hasFinder || hasHandler; + // finder + if (ContentFinderResolver.Current.ContainsType()) + return true; + + // handler wrapped into a finder + if (ContentFinderResolver.Current.ContainsType>()) + return true; + + // handler wrapped into special finder + if (ContentFinderResolver.Current.ContainsType() + && NotFoundHandlerHelper.IsNotFoundHandlerEnabled()) + return true; + + // anything else, we can't detect + return false; } } diff --git a/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs b/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs index 6c10a45dd7..cb80429167 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByNotFoundHandlers.cs @@ -29,115 +29,77 @@ namespace Umbraco.Web.Routing #region Copied over and adapted from presentation.requestHandler - void HandlePageNotFound(PublishedContentRequest docRequest) + private static void HandlePageNotFound(PublishedContentRequest docRequest) { var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers(); LogHelper.Debug("Running for legacy url='{0}'.", () => url); - foreach (var handler in GetNotFoundHandlers()) + foreach (var handler in NotFoundHandlerHelper.GetNotFoundHandlers()) { - IContentFinder finder = null; var handlerName = handler.GetType().FullName; - LogHelper.Debug("Handler '{0}'.", () => handlerName); - // replace with our own implementation - if (handler is global::umbraco.SearchForAlias) - finder = new ContentFinderByUrlAlias(); - else if (handler is global::umbraco.SearchForProfile) - finder = new ContentFinderByProfile(); - else if (handler is global::umbraco.SearchForTemplate) - finder = new ContentFinderByNiceUrlAndTemplate(); - else if (handler is global::umbraco.handle404) - finder = new ContentFinderByLegacy404(); - + var finder = NotFoundHandlerHelper.SubsituteFinder(handler); if (finder != null) { var finderName = finder.GetType().FullName; LogHelper.Debug("Replace handler '{0}' by new finder '{1}'.", () => handlerName, () => finderName); - if (finder.TryFindContent(docRequest)) - { - // do NOT set docRequest.PublishedContent again here as - // it would clear any template that the finder might have set - LogHelper.Debug("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id); - if (docRequest.Is404) - LogHelper.Debug("Finder '{0}' set status to 404.", () => finderName); - // if we found a document, break, don't look at more handler -- we're done - break; - } + // can't find a document => continue with other handlers + if (finder.TryFindContent(docRequest) == false) + continue; - // if we did not find a document, continue, look at other handlers - continue; - } + // found a document => break, don't run other handlers, we're done - // else it's a legacy handler, run + // in theory an IContentFinder can return true yet set no document + // but none of the substitued finders (see SubstituteFinder) do it. - if (handler.Execute(url) && handler.redirectID > 0) - { - var redirectId = handler.redirectID; - docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId); + // do NOT set docRequest.PublishedContent again here + // as it would clear any template that the finder might have set - if (!docRequest.HasPublishedContent) - { - LogHelper.Debug("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId); - break; - } + LogHelper.Debug("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id); + if (docRequest.Is404) + LogHelper.Debug("Finder '{0}' set status to 404.", () => finderName); - LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId); - - if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404) - { - LogHelper.Debug("Handler '{0}' set status code to 404.", () => handlerName); - docRequest.Is404 = true; - } - - //// check for caching - //if (handler.CacheUrl) - //{ - // if (url.StartsWith("/")) - // url = "/" + url; - - // var cacheKey = (currentDomain == null ? "" : currentDomain.Name) + url; - // var culture = currentDomain == null ? null : currentDomain.Language.CultureAlias; - // SetCache(cacheKey, new CacheEntry(handler.redirectID.ToString(), culture)); - - // HttpContext.Current.Trace.Write("NotFoundHandler", - // string.Format("Added to cache '{0}', {1}.", url, handler.redirectID)); - //} - - // if we found a document, break, don't look at more handler -- we're done + LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handlerName, () => docRequest.PublishedContent.Id); break; } - // if we did not find a document, continue, look at other handlers + // else it's a legacy handler: run + + // can't find a document => continue with other handlers + if (handler.Execute(url) == false || handler.redirectID <= 0) + continue; + + // found a document ID => ensure it's a valid document + var redirectId = handler.redirectID; + docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId); + + if (docRequest.HasPublishedContent == false) + { + // the handler said it could handle the url, and returned a content ID + // yet that content ID is invalid... should we run the other handlers? + // I don't think so, not here, let the "last chance" finder take care. + // so, break. + + LogHelper.Debug("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId); + break; + } + + // found a valid document => break, don't run other handlers, we're done + + LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId); + + if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404) + { + LogHelper.Debug("Handler '{0}' set status code to 404.", () => handlerName); + docRequest.Is404 = true; + } + + break; } } - IEnumerable GetNotFoundHandlers() - { - // instanciate new handlers - // using definition cache - - var handlers = new List(); - - foreach (var type in NotFoundHandlerHelper.CustomHandlerTypes) - { - try - { - var handler = Activator.CreateInstance(type) as INotFoundHandler; - if (handler != null) - handlers.Add(handler); - } - catch (Exception e) - { - LogHelper.Error(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e); - } - } - - return handlers; - } - #endregion } } \ No newline at end of file diff --git a/src/Umbraco.Web/Routing/ContentLastChanceFinderByNotFoundHandlers.cs b/src/Umbraco.Web/Routing/ContentLastChanceFinderByNotFoundHandlers.cs new file mode 100644 index 0000000000..115e8cabc0 --- /dev/null +++ b/src/Umbraco.Web/Routing/ContentLastChanceFinderByNotFoundHandlers.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Models; +using umbraco.interfaces; + +namespace Umbraco.Web.Routing +{ + /// + /// Provides an implementation of that runs legacy INotFoundHandler in "last chance" situation. + /// + public class ContentLastChanceFinderByNotFoundHandlers : IContentFinder + { + // notes + // + // at the moment we load the legacy INotFoundHandler + // excluding those that have been replaced by proper finders, + // and run them. + + /// + /// Tries to find and assign an Umbraco document to a PublishedContentRequest. + /// + /// The PublishedContentRequest. + /// A value indicating whether an Umbraco document was found and assigned. + public bool TryFindContent(PublishedContentRequest docRequest) + { + HandlePageNotFound(docRequest); + return docRequest.HasPublishedContent; + } + + #region Copied over and adapted from presentation.requestHandler + + private static void HandlePageNotFound(PublishedContentRequest docRequest) + { + var url = NotFoundHandlerHelper.GetLegacyUrlForNotFoundHandlers(); + LogHelper.Debug("Running for legacy url='{0}'.", () => url); + + var handler = NotFoundHandlerHelper.GetNotFoundLastChanceHandler(); + var handlerName = handler.GetType().FullName; + LogHelper.Debug("Handler '{0}'.", () => handlerName); + + var finder = NotFoundHandlerHelper.SubsituteFinder(handler); + if (finder != null) + { + var finderName = finder.GetType().FullName; + LogHelper.Debug("Replace handler '{0}' by new finder '{1}'.", () => handlerName, () => finderName); + + // can't find a document => exit + if (finder.TryFindContent(docRequest) == false) + return; + + // found a document => we're done + + // in theory an IContentFinder can return true yet set no document + // but none of the substitued finders (see SubstituteFinder) do it. + + // do NOT set docRequest.PublishedContent again here + // as it would clear any template that the finder might have set + + LogHelper.Debug("Finder '{0}' found node with id={1}.", () => finderName, () => docRequest.PublishedContent.Id); + if (docRequest.Is404) + LogHelper.Debug("Finder '{0}' set status to 404.", () => finderName); + + LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handlerName, () => docRequest.PublishedContent.Id); + return; + } + + // else it's a legacy handler, run + + // can't find a document => exit + if (handler.Execute(url) == false || handler.redirectID <= 0) + return; + + // found a document ID => ensure it's a valid document + var redirectId = handler.redirectID; + docRequest.PublishedContent = docRequest.RoutingContext.UmbracoContext.ContentCache.GetById(redirectId); + + if (docRequest.HasPublishedContent == false) + { + // the handler said it could handle the url, and returned a content ID + // yet that content ID is invalid... exit. + + LogHelper.Debug("Handler '{0}' found node with id={1} which is not valid.", () => handlerName, () => redirectId); + return; + } + + // found a valid document => return + + LogHelper.Debug("Handler '{0}' found valid node with id={1}.", () => handlerName, () => redirectId); + + if (docRequest.RoutingContext.UmbracoContext.HttpContext.Response.StatusCode == 404) + { + LogHelper.Debug("Handler '{0}' set status code to 404.", () => handlerName); + docRequest.Is404 = true; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs index 4287b215d3..36d4a55bc9 100644 --- a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs @@ -1,9 +1,12 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Web; using System.Xml; using System.Reflection; +using Umbraco.Core; using Umbraco.Core.Logging; +using umbraco.interfaces; namespace Umbraco.Web.Routing { @@ -36,14 +39,14 @@ namespace Umbraco.Web.Routing return url; // code from requestModule.UmbracoRewrite - string tmp = httpContext.Request.Path.ToLower(); + var tmp = httpContext.Request.Path.ToLower(); // note: requestModule.UmbracoRewrite also did some stripping of &umbPage // from the querystring... that was in v3.x to fix some issues with pre-forms // auth. Paul Sterling confirmed in jan. 2013 that we can get rid of it. // code from requestHandler.cleanUrl - string root = Core.IO.SystemDirectories.Root.ToLower(); + var root = Core.IO.SystemDirectories.Root.ToLower(); if (!string.IsNullOrEmpty(root) && tmp.StartsWith(root)) tmp = tmp.Substring(root.Length); tmp = tmp.TrimEnd('/'); @@ -55,7 +58,7 @@ namespace Umbraco.Web.Routing // code from UmbracoDefault.Page_PreInit if (tmp != "" && httpContext.Request["umbPageID"] == null) { - string tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty); + var tryIntParse = tmp.Replace("/", "").Replace(".aspx", string.Empty); int result; if (int.TryParse(tryIntParse, out result)) tmp = tmp.Replace(".aspx", string.Empty); @@ -77,7 +80,8 @@ namespace Umbraco.Web.Routing return tmp; } - static IEnumerable _customHandlerTypes; + private static IEnumerable _customHandlerTypes; + private static Type _customLastChanceHandlerType; static void InitializeNotFoundHandlers() { @@ -87,6 +91,8 @@ namespace Umbraco.Web.Routing LogHelper.Debug("Registering custom handlers."); var customHandlerTypes = new List(); + Type customLastChanceHandlerType = null; + var hasLast = false; var customHandlers = new XmlDocument(); customHandlers.Load(Core.IO.IOHelper.MapPath(Core.IO.SystemFiles.NotFoundhandlersConfig)); @@ -96,12 +102,23 @@ namespace Umbraco.Web.Routing var assemblyName = n.Attributes.GetNamedItem("assembly").Value; var typeName = n.Attributes.GetNamedItem("type").Value; - string ns = assemblyName; + var ns = assemblyName; var nsAttr = n.Attributes.GetNamedItem("namespace"); - if (nsAttr != null && !string.IsNullOrWhiteSpace(nsAttr.Value)) + if (nsAttr != null && string.IsNullOrWhiteSpace(nsAttr.Value) == false) ns = nsAttr.Value; - LogHelper.Debug("Registering '{0}.{1},{2}'.", () => ns, () => typeName, () => assemblyName); + var lcAttr = n.Attributes.GetNamedItem("last"); + var last = lcAttr != null && lcAttr.Value != null && lcAttr.Value.InvariantEquals("true"); + + if (last) // there can only be one last chance handler in the config file + { + if (hasLast) + throw new Exception(); + hasLast = true; + } + + LogHelper.Debug("Registering '{0}.{1},{2}'{3}", () => ns, () => typeName, () => assemblyName, + () => last ? " (last)." : "."); Type type = null; try @@ -114,19 +131,79 @@ namespace Umbraco.Web.Routing LogHelper.Error("Error registering handler, ignoring.", e); } - if (type != null) + if (type == null) continue; + + if (last) + _customLastChanceHandlerType = type; + else customHandlerTypes.Add(type); } - _customHandlerTypes = customHandlerTypes; + _customHandlerTypes = customHandlerTypes.ToArray(); } - public static IEnumerable CustomHandlerTypes + public static IEnumerable GetNotFoundHandlers() { - get + // instanciate new handlers + // using definition cache + + var handlers = new List(); + + foreach (var type in _customHandlerTypes) { - return _customHandlerTypes; + try + { + var handler = Activator.CreateInstance(type) as INotFoundHandler; + if (handler != null) + handlers.Add(handler); + } + catch (Exception e) + { + LogHelper.Error(string.Format("Error instanciating handler {0}, ignoring.", type.FullName), e); + } } + + return handlers; } + + public static bool IsNotFoundHandlerEnabled() + { + return _customHandlerTypes.Contains(typeof (T)); + } + + public static INotFoundHandler GetNotFoundLastChanceHandler() + { + if (_customLastChanceHandlerType == null) return null; + + try + { + var handler = Activator.CreateInstance(_customLastChanceHandlerType) as INotFoundHandler; + if (handler != null) + return handler; + } + catch (Exception e) + { + LogHelper.Error(string.Format("Error instanciating handler {0}, ignoring.", _customLastChanceHandlerType.FullName), e); + } + + return null; + } + + public static IContentFinder SubsituteFinder(INotFoundHandler handler) + { + IContentFinder finder = null; + + if (handler is global::umbraco.SearchForAlias) + finder = new ContentFinderByUrlAlias(); + else if (handler is global::umbraco.SearchForProfile) + finder = new ContentFinderByProfile(); + else if (handler is global::umbraco.SearchForTemplate) + finder = new ContentFinderByNiceUrlAndTemplate(); + else if (handler is global::umbraco.handle404) + finder = new ContentFinderByLegacy404(); + + return finder; + } + } } diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b0fab44ff0..66be5f0a6b 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -298,6 +298,7 @@ + diff --git a/src/Umbraco.Web/WebBootManager.cs b/src/Umbraco.Web/WebBootManager.cs index b2507f2174..35869fb76b 100644 --- a/src/Umbraco.Web/WebBootManager.cs +++ b/src/Umbraco.Web/WebBootManager.cs @@ -302,23 +302,31 @@ namespace Umbraco.Web typeof(DefaultUrlProvider) ); - // the legacy 404 will run from within ContentFinderByNotFoundHandlers below - // so for the time being there is no last chance finder - ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver(); + ContentLastChanceFinderResolver.Current = new ContentLastChanceFinderResolver( + // handled by ContentLastChanceFinderByNotFoundHandlers for the time being + // soon as we get rid of INotFoundHandler support, we must enable this + //new ContentFinderByLegacy404() + + // implement INotFoundHandler support... remove once we get rid of it + new ContentLastChanceFinderByNotFoundHandlers()); ContentFinderResolver.Current = new ContentFinderResolver( - // add all known resolvers in the correct order, devs can then modify this list - // on application startup either by binding to events or in their own global.asax - typeof (ContentFinderByPageIdQuery), - typeof (ContentFinderByNiceUrl), - typeof (ContentFinderByIdPath), - // these will be handled by ContentFinderByNotFoundHandlers - // so they can be enabled/disabled even though resolvers are not public yet - //typeof (ContentFinderByNiceUrlAndTemplate), - //typeof (ContentFinderByProfile), - //typeof (ContentFinderByUrlAlias), - typeof (ContentFinderByNotFoundHandlers) - ); + // all built-in finders in the correct order, devs can then modify this list + // on application startup via an application event handler. + typeof (ContentFinderByPageIdQuery), + typeof (ContentFinderByNiceUrl), + typeof (ContentFinderByIdPath), + + // these will be handled by ContentFinderByNotFoundHandlers so they can be enabled/disabled + // via the config file... soon as we get rid of INotFoundHandler support, we must enable + // them here. + //typeof (ContentFinderByNiceUrlAndTemplate), + //typeof (ContentFinderByProfile), + //typeof (ContentFinderByUrlAlias), + + // implement INotFoundHandler support... remove once we get rid of it + typeof (ContentFinderByNotFoundHandlers) + ); SiteDomainHelperResolver.Current = new SiteDomainHelperResolver(new SiteDomainHelper()); From 36c281a19a16b9459ff02faaf41963a7a18601c8 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 29 Aug 2013 10:08:54 +1000 Subject: [PATCH 07/14] updated ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9496a86e70..51405dd753 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,6 @@ build/_BuildOutput/ tools/NDepend/ src/*.vspx src/*.psess +NDependOut/* +*.ndproj +QueryResult.htm From 9fc3efd73a7b6bb0fe7ccac36f900c6714734a39 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 29 Aug 2013 11:59:07 +1000 Subject: [PATCH 08/14] Fixes U4-2713 Property Editor Value Converters don't get applied to Umbraco.TypedMedia --- src/Umbraco.Core/PublishedContentHelper.cs | 18 ++++++++-- .../PublishedContent/PublishedMediaTests.cs | 35 ++++++++++++++++++- src/Umbraco.Web/PublishedContentExtensions.cs | 5 ++- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/PublishedContentHelper.cs b/src/Umbraco.Core/PublishedContentHelper.cs index 1e7fc1ef18..8a3242c831 100644 --- a/src/Umbraco.Core/PublishedContentHelper.cs +++ b/src/Umbraco.Core/PublishedContentHelper.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Xml.Linq; using Umbraco.Core.Configuration; using Umbraco.Core.Dynamics; +using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; @@ -43,8 +44,9 @@ namespace Umbraco.Core /// /// /// + /// /// - internal static Guid GetDataType(ApplicationContext applicationContext, string docTypeAlias, string propertyAlias) + internal static Guid GetDataType(ApplicationContext applicationContext, string docTypeAlias, string propertyAlias, PublishedItemType itemType) { if (GetDataTypeCallback != null) return GetDataTypeCallback(docTypeAlias, propertyAlias); @@ -52,7 +54,19 @@ namespace Umbraco.Core var key = new Tuple(docTypeAlias, propertyAlias); return PropertyTypeCache.GetOrAdd(key, tuple => { - var result = applicationContext.Services.ContentTypeService.GetContentType(docTypeAlias); + IContentTypeComposition result = null; + switch (itemType) + { + case PublishedItemType.Content: + result = applicationContext.Services.ContentTypeService.GetContentType(docTypeAlias); + break; + case PublishedItemType.Media: + applicationContext.Services.ContentTypeService.GetMediaType(docTypeAlias); + break; + default: + throw new ArgumentOutOfRangeException("itemType"); + } + if (result == null) return Guid.Empty; //SD: we need to check for 'any' here because the collection is backed by KeyValuePair which is a struct diff --git a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs index 2086b9b5d0..efa50075bf 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedMediaTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text.RegularExpressions; +using System.Web; using System.Xml.Linq; using System.Xml.XPath; using Examine; @@ -16,6 +17,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.UmbracoExamine; using Umbraco.Web; using Umbraco.Web.PublishedCache; @@ -68,6 +70,38 @@ namespace Umbraco.Tests.PublishedContent return GetNode(id, GetUmbracoContext("/test", 1234)); } + [Test] + public void Get_Property_Value_Uses_Converter() + { + var mType = MockedContentTypes.CreateImageMediaType(); + //lets add an RTE to this + mType.PropertyGroups.First().PropertyTypes.Add( + new PropertyType(new Guid(), DataTypeDatabaseType.Nvarchar) + { + Alias = "content", + Name = "Rich Text", + DataTypeDefinitionId = -87 //tiny mce + }); + ServiceContext.ContentTypeService.Save(mType); + var media = MockedMedia.CreateMediaImage(mType, -1); + media.Properties["content"].Value = "
This is some content
"; + ServiceContext.MediaService.Save(media); + + var publishedMedia = GetNode(media.Id); + + var propVal = publishedMedia.GetPropertyValue("content"); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal.GetType())); + Assert.AreEqual("
This is some content
", propVal.ToString()); + + var propVal2 = publishedMedia.GetPropertyValue("content"); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal2.GetType())); + Assert.AreEqual("
This is some content
", propVal2.ToString()); + + var propVal3 = publishedMedia.GetPropertyValue("Content"); + Assert.IsTrue(TypeHelper.IsTypeAssignableFrom(propVal3.GetType())); + Assert.AreEqual("
This is some content
", propVal3.ToString()); + } + [Test] public void Ensure_Children_Sorted_With_Examine() { @@ -339,7 +373,6 @@ namespace Umbraco.Tests.PublishedContent Assert.AreEqual(mChild1.Id, publishedSubChild1.Parent.Id); } - [Test] public void Ancestors_Without_Examine() { diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index a6655c55ce..b36a9d7880 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -153,7 +153,10 @@ namespace Umbraco.Web //Here we need to put the value through the IPropertyEditorValueConverter's //get the data type id for the current property - var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, doc.DocumentTypeAlias, alias); + var dataType = PublishedContentHelper.GetDataType( + ApplicationContext.Current, doc.DocumentTypeAlias, alias, + doc.ItemType); + //convert the string value to a known type var converted = PublishedContentHelper.ConvertPropertyValue(p.Value, dataType, doc.DocumentTypeAlias, alias); return converted.Success From 581f3a1893b4741f28a8407bb46da523aab07fea Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 29 Aug 2013 12:01:30 +1000 Subject: [PATCH 09/14] Fixes build errors --- src/Umbraco.Web/Models/DynamicPublishedContent.cs | 5 +++-- src/Umbraco.Web/PublishedContentExtensions.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs index 35f2040410..3ff0732f99 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs @@ -236,10 +236,11 @@ namespace Umbraco.Web.Models } //get the data type id for the current property - var dataType = Umbraco.Core.PublishedContentHelper.GetDataType( + var dataType = PublishedContentHelper.GetDataType( ApplicationContext.Current, userProperty.DocumentTypeAlias, - userProperty.Alias); + userProperty.Alias, + ItemType); //convert the string value to a known type var converted = Umbraco.Core.PublishedContentHelper.ConvertPropertyValue(result, dataType, userProperty.DocumentTypeAlias, userProperty.Alias); diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index b36a9d7880..29d7e1f22c 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -191,7 +191,7 @@ namespace Umbraco.Web //before we try to convert it manually, lets see if the PropertyEditorValueConverter does this for us //Here we need to put the value through the IPropertyEditorValueConverter's //get the data type id for the current property - var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, prop.DocumentTypeAlias, alias); + var dataType = PublishedContentHelper.GetDataType(ApplicationContext.Current, prop.DocumentTypeAlias, alias, prop.ItemType); //convert the value to a known type var converted = PublishedContentHelper.ConvertPropertyValue(p.Value, dataType, prop.DocumentTypeAlias, alias); object parsedLinksVal; From 232c81543a79d33d31932cb86519730b1486bb72 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 29 Aug 2013 12:11:48 +1000 Subject: [PATCH 10/14] Fixes the rest of U4-2713 Property Editor Value Converters don't get applied to Umbraco.TypedMedia --- src/Umbraco.Core/PublishedContentHelper.cs | 6 +++--- src/Umbraco.Web.UI/config/ClientDependency.config | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/PublishedContentHelper.cs b/src/Umbraco.Core/PublishedContentHelper.cs index 8a3242c831..86513ede02 100644 --- a/src/Umbraco.Core/PublishedContentHelper.cs +++ b/src/Umbraco.Core/PublishedContentHelper.cs @@ -36,7 +36,7 @@ namespace Umbraco.Core ///
internal static Func GetDataTypeCallback = null; - private static readonly ConcurrentDictionary, Guid> PropertyTypeCache = new ConcurrentDictionary, Guid>(); + private static readonly ConcurrentDictionary, Guid> PropertyTypeCache = new ConcurrentDictionary, Guid>(); /// /// Return the GUID Id for the data type assigned to the document type with the property alias @@ -51,7 +51,7 @@ namespace Umbraco.Core if (GetDataTypeCallback != null) return GetDataTypeCallback(docTypeAlias, propertyAlias); - var key = new Tuple(docTypeAlias, propertyAlias); + var key = new Tuple(docTypeAlias, propertyAlias, itemType); return PropertyTypeCache.GetOrAdd(key, tuple => { IContentTypeComposition result = null; @@ -61,7 +61,7 @@ namespace Umbraco.Core result = applicationContext.Services.ContentTypeService.GetContentType(docTypeAlias); break; case PublishedItemType.Media: - applicationContext.Services.ContentTypeService.GetMediaType(docTypeAlias); + result = applicationContext.Services.ContentTypeService.GetMediaType(docTypeAlias); break; default: throw new ArgumentOutOfRangeException("itemType"); diff --git a/src/Umbraco.Web.UI/config/ClientDependency.config b/src/Umbraco.Web.UI/config/ClientDependency.config index a95c67b06d..3b80c0d7dd 100644 --- a/src/Umbraco.Web.UI/config/ClientDependency.config +++ b/src/Umbraco.Web.UI/config/ClientDependency.config @@ -10,7 +10,7 @@ NOTES: * Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config * A new version will invalidate both client and server cache and create new persisted files --> - +