Fixes up issues with editing the member profile and registering a member with our snippets including specifying a custom member type.

This commit is contained in:
Shannon
2014-03-13 14:10:05 +11:00
parent 85a74e4fa7
commit 221bfa5f3d
8 changed files with 166 additions and 44 deletions

View File

@@ -48,6 +48,13 @@
@for (var i = 0; i < profileModel.MemberProperties.Count; i++)
{
@Html.LabelFor(m => profileModel.MemberProperties[i].Value, profileModel.MemberProperties[i].Name)
@*
By default this will render a textbox but if you want to change the editor template for this property you can
easily change it. For example, if you wanted to render a custom editor for this field called "MyEditor" you would
create a file at ~/Views/Shared/EditorTemplates/MyEditor.cshtml", then you will change the next line of code to
render your specific editor template like:
@Html.EditorFor(m => profileModel.MemberProperties[i].Value, "MyEditor")
*@
@Html.EditorFor(m => profileModel.MemberProperties[i].Value)
@Html.HiddenFor(m => profileModel.MemberProperties[i].Alias)
<br />

View File

@@ -78,6 +78,13 @@ else
for (var i = 0; i < registerModel.MemberProperties.Count; i++)
{
@Html.LabelFor(m => registerModel.MemberProperties[i].Value, registerModel.MemberProperties[i].Name)
@*
By default this will render a textbox but if you want to change the editor template for this property you can
easily change it. For example, if you wanted to render a custom editor for this field called "MyEditor" you would
create a file at ~/Views/Shared/EditorTemplates/MyEditor.cshtml", then you will change the next line of code to
render your specific editor template like:
@Html.EditorFor(m => profileModel.MemberProperties[i].Value, "MyEditor")
*@
@Html.EditorFor(m => registerModel.MemberProperties[i].Value)
@Html.HiddenFor(m => registerModel.MemberProperties[i].Alias)
<br />

View File

@@ -4,6 +4,7 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Xml;
using System.Xml.Linq;
using umbraco.cms.businesslogic.member;
@@ -18,6 +19,7 @@ namespace Umbraco.Web.Models
/// <summary>
/// A readonly member profile model
/// </summary>
[ModelBinder(typeof(ProfileModelBinder))]
public class ProfileModel : PostRedirectModel
{
@@ -96,7 +98,18 @@ namespace Umbraco.Web.Models
/// <remarks>
/// Adding items to this list on the front-end will not add properties to the member in the database.
/// </remarks>
public List<UmbracoProperty> MemberProperties { get; set; }
public List<UmbracoProperty> MemberProperties { get; set; }
/// <summary>
/// A custom model binder for MVC because the default ctor performs a lookup!
/// </summary>
internal class ProfileModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return ProfileModel.CreateModel();
}
}
}
}

View File

@@ -4,12 +4,14 @@ using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using umbraco.cms.businesslogic.member;
using Umbraco.Core;
using Umbraco.Web.Security;
namespace Umbraco.Web.Models
{
[ModelBinder(typeof(RegisterModelBinder))]
public class RegisterModel : PostRedirectModel
{
/// <summary>
@@ -58,6 +60,7 @@ namespace Umbraco.Web.Models
/// <summary>
/// The member type alias to use to register the member
/// </summary>
[Editable(false)]
public string MemberTypeAlias { get; set; }
/// <summary>
@@ -90,5 +93,16 @@ namespace Umbraco.Web.Models
/// </summary>
public bool LoginOnSuccess { get; set; }
/// <summary>
/// A custom model binder for MVC because the default ctor performs a lookup!
/// </summary>
internal class RegisterModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return RegisterModel.CreateModel();
}
}
}
}

View File

@@ -1,4 +1,6 @@
using System.Xml;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Xml;
using Umbraco.Core;
using Umbraco.Core.Models;
@@ -9,9 +11,30 @@ namespace Umbraco.Web.Models
/// </summary>
public class UmbracoProperty
{
[Editable(false)]
public string Alias { get; set; }
public object Value { get; set; }
//NOTE: This has to be a string currently, if it is an object it will bind as an array which we don't want.
// If we want to have this as an 'object' with a true type on it, we have to create a custom model binder
// for an UmbracoProperty and then bind with the correct type based on the property type for this alias. This
// would be a bit long winded and perhaps unnecessary. The reason is because it is always posted as a string anyways
// and when we set this value on the property object that gets sent to the database we do a TryConvertTo to the
// real type anyways.
[DataType(DataType.Text)]
public string Value { get; set; }
[ReadOnly(true)]
public string Name { get; set; }
//TODO: Perhaps one day we'll ship with our own EditorTempates but for now developers can just render their own inside the view
///// <summary>
///// This can dynamically be set to a custom template name to change
///// the editor type for this property
///// </summary>
//[ReadOnly(true)]
//public string EditorTemplate { get; set; }
}
}

View File

@@ -7,6 +7,22 @@ namespace Umbraco.Web.Mvc
{
internal static class ControllerExtensions
{
internal static object GetDataTokenInViewContextHierarchy(this ControllerContext controllerContext, string dataTokenName)
{
if (controllerContext.RouteData.DataTokens.ContainsKey(dataTokenName))
{
return controllerContext.RouteData.DataTokens[dataTokenName];
}
if (controllerContext.ParentActionViewContext != null)
{
//recurse!
return controllerContext.ParentActionViewContext.GetDataTokenInViewContextHierarchy(dataTokenName);
}
return null;
}
/// <summary>
/// Return the controller name from the controller type
/// </summary>

View File

@@ -94,19 +94,17 @@ namespace Umbraco.Web.Mvc
/// <returns></returns>
private bool ShouldFindView(ControllerContext controllerContext, bool isPartial)
{
var umbracoToken = controllerContext.GetDataTokenInViewContextHierarchy("umbraco");
//first check if we're rendering a partial view for the back office, or surface controller, etc...
//anything that is not IUmbracoRenderModel as this should only pertain to Umbraco views.
if (isPartial
&& controllerContext.RouteData.DataTokens.ContainsKey("umbraco")
&& !(controllerContext.RouteData.DataTokens["umbraco"] is RenderModel))
if (isPartial && umbracoToken is RenderModel)
{
return true;
}
//only find views if we're rendering the umbraco front end
if (controllerContext.RouteData.DataTokens.ContainsKey("umbraco")
&& controllerContext.RouteData.DataTokens["umbraco"] != null
&& controllerContext.RouteData.DataTokens["umbraco"] is RenderModel)
if (umbracoToken is RenderModel)
{
return true;
}

View File

@@ -129,16 +129,20 @@ namespace Umbraco.Web.Security
{
model.Username = (model.UsernameIsEmail || model.Username == null) ? model.Email : model.Username;
var membershipUser = Membership.CreateUser(model.Username, model.Password, model.Email,
//TODO: Support q/a http://issues.umbraco.org/issue/U4-3213
null, null,
true, out status);
MembershipUser membershipUser;
if (status != MembershipCreateStatus.Success) return null;
//update their real name
if (Membership.Provider.IsUmbracoMembershipProvider())
{
membershipUser = ((UmbracoMembershipProviderBase)Membership.Provider).CreateUser(
model.MemberTypeAlias,
model.Username, model.Password, model.Email,
//TODO: Support q/a http://issues.umbraco.org/issue/U4-3213
null, null,
true, null, out status);
if (status != MembershipCreateStatus.Success) return null;
var member = _applicationContext.Services.MemberService.GetByUsername(membershipUser.UserName);
member.Name = model.Name;
@@ -155,7 +159,12 @@ namespace Umbraco.Web.Security
}
else
{
//TODO: Support this scenario!
membershipUser = Membership.CreateUser(model.Username, model.Password, model.Email,
//TODO: Support q/a http://issues.umbraco.org/issue/U4-3213
null, null,
true, out status);
if (status != MembershipCreateStatus.Success) return null;
}
//Set member online
@@ -282,23 +291,8 @@ namespace Umbraco.Web.Security
var builtIns = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray();
foreach (var prop in memberType.PropertyTypes
.Where(x => builtIns.Contains(x.Alias) == false && memberType.MemberCanEditProperty(x.Alias)))
{
var value = string.Empty;
var propValue = member.Properties[prop.Alias];
if (propValue != null)
{
value = propValue.Value.ToString();
}
model.MemberProperties = GetMemberPropertiesViewModel(memberType, builtIns, member).ToList();
model.MemberProperties.Add(new UmbracoProperty
{
Alias = prop.Alias,
Name = prop.Name,
Value = value
});
}
return model;
}
@@ -321,17 +315,10 @@ namespace Umbraco.Web.Security
if (memberType == null)
throw new InvalidOperationException("Could not find a member type with alias " + memberTypeAlias);
var props = memberType.PropertyTypes
.Where(x => memberType.MemberCanEditProperty(x.Alias))
.Select(prop => new UmbracoProperty
{
Alias = prop.Alias,
Name = prop.Name,
Value = string.Empty
}).ToList();
var builtIns = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray();
var model = RegisterModel.CreateModel();
model.MemberProperties = props;
model.MemberTypeAlias = memberTypeAlias;
model.MemberProperties = GetMemberPropertiesViewModel(memberType, builtIns).ToList();
return model;
}
else
@@ -340,7 +327,64 @@ namespace Umbraco.Web.Security
model.MemberTypeAlias = string.Empty;
return model;
}
}
}
private IEnumerable<UmbracoProperty> GetMemberPropertiesViewModel(IMemberType memberType, IEnumerable<string> builtIns, IMember member = null)
{
var viewProperties = new List<UmbracoProperty>();
foreach (var prop in memberType.PropertyTypes
.Where(x => builtIns.Contains(x.Alias) == false && memberType.MemberCanEditProperty(x.Alias)))
{
var value = string.Empty;
if (member != null)
{
var propValue = member.Properties[prop.Alias];
if (propValue != null)
{
value = propValue.Value.ToString();
}
}
var viewProperty = new UmbracoProperty
{
Alias = prop.Alias,
Name = prop.Name,
Value = value
};
//TODO: Perhaps one day we'll ship with our own EditorTempates but for now developers
// can just render their own.
////This is a rudimentary check to see what data template we should render
//// if developers want to change the template they can do so dynamically in their views or controllers
//// for a given property.
////These are the default built-in MVC template types: “Boolean”, “Decimal”, “EmailAddress”, “HiddenInput”, “Html”, “Object”, “String”, “Text”, and “Url”
//// by default we'll render a text box since we've defined that metadata on the UmbracoProperty.Value property directly.
//if (prop.DataTypeId == new Guid(Constants.PropertyEditors.TrueFalse))
//{
// viewProperty.EditorTemplate = "UmbracoBoolean";
//}
//else
//{
// switch (prop.DataTypeDatabaseType)
// {
// case DataTypeDatabaseType.Integer:
// viewProperty.EditorTemplate = "Decimal";
// break;
// case DataTypeDatabaseType.Ntext:
// viewProperty.EditorTemplate = "Text";
// break;
// case DataTypeDatabaseType.Date:
// case DataTypeDatabaseType.Nvarchar:
// break;
// }
//}
viewProperties.Add(viewProperty);
}
return viewProperties;
}
#endregion
/// <summary>