diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs index 4af0c79c13..e35efb726b 100644 --- a/src/Umbraco.Core/Models/Member.cs +++ b/src/Umbraco.Core/Models/Member.cs @@ -15,7 +15,7 @@ namespace Umbraco.Core.Models public class Member : ContentBase, IMember { private readonly IMemberType _contentType; - private string _contentTypeAlias; + private readonly string _contentTypeAlias; private string _username; private string _email; private string _password; @@ -30,6 +30,7 @@ namespace Umbraco.Core.Models public Member(string name, IMemberType contentType) : base(name, -1, contentType, new PropertyCollection()) { + _contentTypeAlias = contentType.Alias; _contentType = contentType; IsApproved = true; } @@ -40,6 +41,7 @@ namespace Umbraco.Core.Models { Mandate.ParameterNotNull(contentType, "contentType"); + _contentTypeAlias = contentType.Alias; _contentType = contentType; _email = email; _username = username; @@ -52,6 +54,7 @@ namespace Umbraco.Core.Models { Mandate.ParameterNotNull(contentType, "contentType"); + _contentTypeAlias = contentType.Alias; _contentType = contentType; _email = email; _username = username; @@ -424,14 +427,6 @@ namespace Umbraco.Core.Models public virtual string ContentTypeAlias { get { return _contentTypeAlias; } - internal set - { - SetPropertyValueAndDetectChanges(o => - { - _contentTypeAlias = value; - return _contentTypeAlias; - }, _contentTypeAlias, DefaultContentTypeAliasSelector); - } } /// diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs index eb53215896..453e8b0862 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentType.cs @@ -141,9 +141,21 @@ namespace Umbraco.Core.Models.PublishedContent if (GetPublishedContentTypeCallback != null) return GetPublishedContentTypeCallback(alias); - var contentType = itemType == PublishedItemType.Content - ? (IContentTypeComposition)ApplicationContext.Current.Services.ContentTypeService.GetContentType(alias) - : (IContentTypeComposition)ApplicationContext.Current.Services.ContentTypeService.GetMediaType(alias); + IContentTypeComposition contentType; + switch (itemType) + { + case PublishedItemType.Content: + contentType = ApplicationContext.Current.Services.ContentTypeService.GetContentType(alias); + break; + case PublishedItemType.Media: + contentType = ApplicationContext.Current.Services.ContentTypeService.GetMediaType(alias); + break; + case PublishedItemType.Member: + contentType = ApplicationContext.Current.Services.MemberTypeService.Get(alias); + break; + default: + throw new ArgumentOutOfRangeException("itemType"); + } if (contentType == null) throw new Exception(string.Format("ContentTypeService failed to find a {0} type with alias \"{1}\".", diff --git a/src/Umbraco.Core/Models/PublishedItemType.cs b/src/Umbraco.Core/Models/PublishedItemType.cs index a98a3c2a75..681fec8854 100644 --- a/src/Umbraco.Core/Models/PublishedItemType.cs +++ b/src/Umbraco.Core/Models/PublishedItemType.cs @@ -13,6 +13,11 @@ namespace Umbraco.Core.Models /// /// A media. /// - Media + Media, + + /// + /// A member. + /// + Member } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs index dd7d8d9277..0cef37ce8b 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberReadOnlyFactory.cs @@ -33,7 +33,6 @@ namespace Umbraco.Core.Persistence.Factories Path = dto.Path, SortOrder = dto.SortOrder, Version = dto.VersionId, - ContentTypeAlias = dto.ContentTypeAlias, Properties = new PropertyCollection(properties) }; diff --git a/src/Umbraco.Core/TypeExtensions.cs b/src/Umbraco.Core/TypeExtensions.cs index 281901504f..d61ad60144 100644 --- a/src/Umbraco.Core/TypeExtensions.cs +++ b/src/Umbraco.Core/TypeExtensions.cs @@ -7,11 +7,59 @@ using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; +using Umbraco.Core.Strings; namespace Umbraco.Core { public static class TypeExtensions { + /// + /// Tries to return a value based on a property name for an object but ignores case sensitivity + /// + /// + /// + /// + /// + /// + /// Currenty this will only work for ProperCase and camelCase properties, see the TODO below to enable complete case insensitivity + /// + internal static Attempt GetMemberIgnoreCase(this Type type, object target, string memberName) + { + Func> getMember = + memberAlias => + { + try + { + return Attempt.Succeed( + type.InvokeMember(memberAlias, + System.Reflection.BindingFlags.GetProperty | + System.Reflection.BindingFlags.Instance | + System.Reflection.BindingFlags.Public, + null, + target, + null)); + } + catch (MissingMethodException ex) + { + return Attempt.Fail(ex); + } + }; + + //try with the current casing + var attempt = getMember(memberName); + if (attempt.Success == false) + { + //if we cannot get with the current alias, try changing it's case + attempt = memberName[0].IsUpperCase() + ? getMember(memberName.ToCleanString(CleanStringType.Ascii | CleanStringType.ConvertCase | CleanStringType.CamelCase)) + : getMember(memberName.ToCleanString(CleanStringType.Ascii | CleanStringType.ConvertCase | CleanStringType.PascalCase)); + + //TODO: If this still fails then we should get a list of properties from the object and then compare - doing the above without listing + // all properties will surely be faster than using reflection to get ALL properties first and then query against them. + } + + return attempt; + } public static object GetDefaultValue(this Type t) { diff --git a/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs b/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs new file mode 100644 index 0000000000..09437e2ddc --- /dev/null +++ b/src/Umbraco.Tests/Membership/DynamicMemberContentTests.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.Security; +using Lucene.Net.Util; +using Moq; +using NUnit.Framework; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Tests.PublishedContent; +using Umbraco.Tests.TestHelpers; +using Umbraco.Tests.TestHelpers.Entities; +using Umbraco.Web; +using Umbraco.Web.Models; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Tests.Membership +{ + [TestFixture] + public class DynamicMemberContentTests : PublishedContentTestBase + { + + protected override DatabaseBehavior DatabaseTestBehavior + { + get { return DatabaseBehavior.NoDatabasePerFixture; } + } + + public override void Initialize() + { + // required so we can access property.Value + //PropertyValueConvertersResolver.Current = new PropertyValueConvertersResolver(); + + base.Initialize(); + + // need to specify a custom callback for unit tests + // AutoPublishedContentTypes generates properties automatically + // when they are requested, but we must declare those that we + // explicitely want to be here... + + var propertyTypes = new[] + { + // AutoPublishedContentType will auto-generate other properties + new PublishedPropertyType("title", 0, Guid.Empty), + new PublishedPropertyType("bodyText", 0, Guid.Empty), + new PublishedPropertyType("author", 0, Guid.Empty) + }; + var type = new AutoPublishedContentType(0, "anything", propertyTypes); + PublishedContentType.GetPublishedContentTypeCallback = (alias) => type; + + } + + [Test] + public void Can_Get_Built_In_Properties() + { + var date = DateTime.Now; + + var m = Mock.Of( + user => user.UserName == "test username" + && user.Comment == "test comment" + && user.IsApproved == true + && user.IsLockedOut == false + && user.CreationDate == date + && user.Email == "test@email.com" + && user.LastActivityDate == date.AddMinutes(1) + && user.LastLockoutDate == date.AddMinutes(2) + && user.LastLoginDate == date.AddMinutes(3) + && user.LastPasswordChangedDate == date.AddMinutes(4) + && user.PasswordQuestion == "test question"); + + + var mpc = new MemberPublishedContent( + new Member("test name", "test@email.com", "test username", "test password", -1, + Mock.Of(type => type.Alias == "Member")), + m); + + var d = mpc.AsDynamic(); + + Assert.AreEqual("test comment", d.Comment); + Assert.AreEqual(date, d.CreationDate); + Assert.AreEqual("test@email.com", d.Email); + Assert.AreEqual(true, d.IsApproved); + Assert.AreEqual(false, d.IsLockedOut); + Assert.AreEqual(date.AddMinutes(1), d.LastActivityDate); + Assert.AreEqual(date.AddMinutes(2), d.LastLockoutDate); + Assert.AreEqual(date.AddMinutes(3), d.LastLoginDate); + Assert.AreEqual(date.AddMinutes(4), d.LastPasswordChangedDate); + Assert.AreEqual("test name", d.Name); + Assert.AreEqual("test question", d.PasswordQuestion); + Assert.AreEqual("test username", d.UserName); + + } + + [Test] + public void Can_Get_Built_In_Properties_Camel_Case() + { + var date = DateTime.Now; + + var m = Mock.Of( + user => user.UserName == "test username" + && user.Comment == "test comment" + && user.IsApproved == true + && user.IsLockedOut == false + && user.CreationDate == date + && user.Email == "test@email.com" + && user.LastActivityDate == date.AddMinutes(1) + && user.LastLockoutDate == date.AddMinutes(2) + && user.LastLoginDate == date.AddMinutes(3) + && user.LastPasswordChangedDate == date.AddMinutes(4) + && user.PasswordQuestion == "test question"); + + + var mpc = new MemberPublishedContent( + new Member("test name", "test@email.com", "test username", "test password", -1, + Mock.Of(type => type.Alias == "Member")) , + m); + + var d = mpc.AsDynamic(); + + Assert.AreEqual("test comment", d.comment); + Assert.AreEqual(date, d.creationDate); + Assert.AreEqual("test@email.com", d.email); + Assert.AreEqual(true, d.isApproved); + Assert.AreEqual(false, d.isLockedOut); + Assert.AreEqual(date.AddMinutes(1), d.lastActivityDate); + Assert.AreEqual(date.AddMinutes(2), d.lastLockoutDate); + Assert.AreEqual(date.AddMinutes(3), d.lastLoginDate); + Assert.AreEqual(date.AddMinutes(4), d.lastPasswordChangedDate); + Assert.AreEqual("test name", d.name); + Assert.AreEqual("test question", d.passwordQuestion); + Assert.AreEqual("test username", d.userName); + + } + + [Test] + public void Can_Get_Custom_Properties() + { + var date = DateTime.Now; + + var m = Mock.Of( + user => user.UserName == "test username" + && user.Comment == "test comment" + && user.IsApproved == true + && user.IsLockedOut == false + && user.CreationDate == date + && user.Email == "test@email.com" + && user.LastActivityDate == date.AddMinutes(1) + && user.LastLockoutDate == date.AddMinutes(2) + && user.LastLoginDate == date.AddMinutes(3) + && user.LastPasswordChangedDate == date.AddMinutes(4) + && user.PasswordQuestion == "test question"); + + var memberType = MockedContentTypes.CreateSimpleMemberType("Member", "Member"); + var member = MockedMember.CreateSimpleMember(memberType, "test name", "test@email.com", "test password", "test username"); + member.Properties["title"].Value = "Test Value 1"; + member.Properties["bodyText"].Value = "Test Value 2"; + member.Properties["author"].Value = "Test Value 3"; + var mpc = new MemberPublishedContent(member, m); + + var d = mpc.AsDynamic(); + + Assert.AreEqual("Test Value 1", d.title); + Assert.AreEqual("Test Value 1", d.Title); + Assert.AreEqual("Test Value 2", d.bodyText); + Assert.AreEqual("Test Value 2", d.BodyText); + Assert.AreEqual("Test Value 3", d.author); + Assert.AreEqual("Test Value 3", d.Author); + + + } + + + } +} diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index dfea551434..cc0cf95c37 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -1,4 +1,4 @@ - + Debug @@ -154,6 +154,7 @@ + diff --git a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml index 6d3c11b30a..d7625a65d8 100644 --- a/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/PartialViewMacros/Templates/EditProfile.cshtml @@ -6,7 +6,7 @@ @using Umbraco.Web.Controllers @{ - var profileModel = Members.CreateProfileModel(); + var profileModel = Members.GetCurrentMemberProfileModel(); Html.EnableClientValidation(); Html.EnableUnobtrusiveJavaScript(); diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs index ea0b12b97b..7e216dd781 100644 --- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs +++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs @@ -329,35 +329,7 @@ namespace Umbraco.Web.Models // can handle properties only when using the proper casing. So what this // does is ensure that any casing is supported. - Func> getMember = - memberAlias => - { - try - { - return Attempt.Succeed( - content.GetType().InvokeMember(memberAlias, - System.Reflection.BindingFlags.GetProperty | - System.Reflection.BindingFlags.Instance | - System.Reflection.BindingFlags.Public, - null, - content, - null)); - } - catch (MissingMethodException ex) - { - return Attempt.Fail(ex); - } - }; - - //try with the current casing - var attempt = getMember(alias); - if (!attempt.Success) - { - //if we cannot get with the current alias, try changing it's case - attempt = alias[0].IsUpperCase() - ? getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.ConvertCase | CleanStringType.CamelCase)) - : getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.ConvertCase | CleanStringType.PascalCase)); - } + var attempt = content.GetType().GetMemberIgnoreCase(content, alias); return !attempt.Success ? null diff --git a/src/Umbraco.Web/Models/ProfileModel.cs b/src/Umbraco.Web/Models/ProfileModel.cs index 7ce1593c4b..85ff095d46 100644 --- a/src/Umbraco.Web/Models/ProfileModel.cs +++ b/src/Umbraco.Web/Models/ProfileModel.cs @@ -4,14 +4,23 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web; +using System.Xml; +using System.Xml.Linq; using umbraco.cms.businesslogic.member; using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.PublishedCache; using Umbraco.Web.Security; namespace Umbraco.Web.Models { + /// + /// A readonly member profile model + /// public class ProfileModel : PostRedirectModel { + public static ProfileModel CreateModel() { var model = new ProfileModel(false); @@ -24,7 +33,7 @@ namespace Umbraco.Web.Models if (doLookup) { var helper = new MembershipHelper(ApplicationContext.Current, new HttpContextWrapper(HttpContext.Current)); - var model = helper.CreateProfileModel(); + var model = helper.GetCurrentMemberProfileModel(); MemberProperties = model.MemberProperties; } } @@ -49,7 +58,6 @@ namespace Umbraco.Web.Models /// The member's member type alias /// [ReadOnly(true)] - [Obsolete("This is not used and will be removed from the codebase in future versions")] public string MemberTypeAlias { get; set; } [ReadOnly(true)] @@ -88,7 +96,7 @@ 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; } - + public List MemberProperties { get; set; } + } } diff --git a/src/Umbraco.Web/Models/PublishedContentBase.cs b/src/Umbraco.Web/Models/PublishedContentBase.cs index 3db343c8db..2ca1978c29 100644 --- a/src/Umbraco.Web/Models/PublishedContentBase.cs +++ b/src/Umbraco.Web/Models/PublishedContentBase.cs @@ -50,7 +50,7 @@ namespace Umbraco.Web.Models _url = prop.Value.ToString(); break; default: - throw new ArgumentOutOfRangeException(); + throw new NotSupportedException(); } return _url; diff --git a/src/Umbraco.Web/Models/UmbracoProperty.cs b/src/Umbraco.Web/Models/UmbracoProperty.cs index ad907df1a0..712e6c33db 100644 --- a/src/Umbraco.Web/Models/UmbracoProperty.cs +++ b/src/Umbraco.Web/Models/UmbracoProperty.cs @@ -1,4 +1,8 @@ -namespace Umbraco.Web.Models +using System.Xml; +using Umbraco.Core; +using Umbraco.Core.Models; + +namespace Umbraco.Web.Models { /// /// A simple representation of an Umbraco property @@ -6,7 +10,8 @@ public class UmbracoProperty { public string Alias { get; set; } - public string Value { get; set; } + public object Value { get; set; } public string Name { get; set; } + } } diff --git a/src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs b/src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs new file mode 100644 index 0000000000..6de2d37812 --- /dev/null +++ b/src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.Security; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Web.Models; + +namespace Umbraco.Web.PublishedCache +{ + /// + /// Exposes a member object as IPublishedContent + /// + internal class MemberPublishedContent : PublishedContentBase + { + + private readonly IMember _member; + private readonly MembershipUser _membershipUser; + private readonly List _properties; + private readonly PublishedContentType _publishedMemberType; + + public MemberPublishedContent(IMember member, MembershipUser membershipUser) + { + if (member == null) throw new ArgumentNullException("member"); + if (membershipUser == null) throw new ArgumentNullException("membershipUser"); + + _member = member; + _membershipUser = membershipUser; + _properties = new List(); + _publishedMemberType = PublishedContentType.Get(PublishedItemType.Member, _member.ContentTypeAlias); + if (_publishedMemberType == null) + { + throw new InvalidOperationException("Could not get member type with alias " + _member.ContentTypeAlias); + } + foreach (var propType in _publishedMemberType.PropertyTypes) + { + var val = _member.Properties.Any(x => x.Alias == propType.PropertyTypeAlias) == false + ? string.Empty + : _member.Properties[propType.PropertyTypeAlias].Value; + _properties.Add(new RawValueProperty(propType, val)); + } + } + + #region Membership provider member properties + public string Email + { + get { return _membershipUser.Email; } + } + public string UserName + { + get { return _membershipUser.UserName; } + } + public string PasswordQuestion + { + get { return _membershipUser.PasswordQuestion; } + } + public string Comment + { + get { return _membershipUser.Comment; } + } + public bool IsApproved + { + get { return _membershipUser.IsApproved; } + } + public bool IsLockedOut + { + get { return _membershipUser.IsLockedOut; } + } + public DateTime LastLockoutDate + { + get { return _membershipUser.LastLockoutDate; } + } + public DateTime CreationDate + { + get { return _membershipUser.CreationDate; } + } + public DateTime LastLoginDate + { + get { return _membershipUser.LastLoginDate; } + } + public DateTime LastActivityDate + { + get { return _membershipUser.LastActivityDate; } + } + public DateTime LastPasswordChangedDate + { + get { return _membershipUser.LastPasswordChangedDate; } + } + #endregion + + #region IPublishedContent + public override PublishedItemType ItemType + { + get { return PublishedItemType.Member; } + } + + public override bool IsDraft + { + get { return false; } + } + + public override IPublishedContent Parent + { + get { return null; } + } + + public override IEnumerable Children + { + get { return Enumerable.Empty(); } + } + + public override ICollection Properties + { + get { return _properties; } + } + + public override IPublishedProperty GetProperty(string alias, bool recurse) + { + if (recurse) + { + throw new NotSupportedException(); + } + return GetProperty(alias); + } + + public override IPublishedProperty GetProperty(string alias) + { + return _properties.FirstOrDefault(x => x.PropertyTypeAlias.InvariantEquals(alias)); + } + + public override PublishedContentType ContentType + { + get { return _publishedMemberType; } + } + + public override int Id + { + get { return _member.Id; } + } + + public override int TemplateId + { + get { throw new NotSupportedException(); } + } + + public override int SortOrder + { + get { return 0; } + } + + public override string Name + { + get { return _member.Name; } + } + + public override string UrlName + { + get { throw new NotSupportedException(); } + } + + public override string DocumentTypeAlias + { + get { return _member.ContentTypeAlias; } + } + + public override int DocumentTypeId + { + get { return _member.ContentType.Id; } + } + + public override string WriterName + { + get { return _member.GetCreatorProfile().Name; } + } + + public override string CreatorName + { + get { return _member.GetCreatorProfile().Name; } + } + + public override int WriterId + { + get { return _member.CreatorId; } + } + + public override int CreatorId + { + get { return _member.CreatorId; } + } + + public override string Path + { + get { return _member.Path; } + } + + public override DateTime CreateDate + { + get { return _member.CreateDate; } + } + + public override DateTime UpdateDate + { + get { return _member.UpdateDate; } + } + + public override Guid Version + { + get { return _member.Version; } + } + + public override int Level + { + get { return _member.Level; } + } + #endregion + } +} diff --git a/src/Umbraco.Web/PublishedCache/RawValueProperty.cs b/src/Umbraco.Web/PublishedCache/RawValueProperty.cs new file mode 100644 index 0000000000..5fa95f127b --- /dev/null +++ b/src/Umbraco.Web/PublishedCache/RawValueProperty.cs @@ -0,0 +1,46 @@ +using System; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Web.PublishedCache +{ + /// + /// A published property base that uses a raw object value + /// + internal class RawValueProperty : PublishedPropertyBase + { + private readonly object _dbVal; //the value in the db + private readonly Lazy _sourceValue; + private readonly Lazy _objectValue; + private readonly Lazy _xpathValue; + + /// + /// Gets the raw value of the property. + /// + public override object DataValue { get { return _dbVal; } } + + public override bool HasValue + { + get { return _dbVal != null && _dbVal.ToString().Trim().Length > 0; } + } + + public override object Value { get { return _objectValue.Value; } } + public override object XPathValue { get { return _xpathValue.Value; } } + + public RawValueProperty(PublishedPropertyType propertyType, object propertyData) + : this(propertyType) + { + if (propertyData == null) + throw new ArgumentNullException("propertyData"); + _dbVal = propertyData; + } + + public RawValueProperty(PublishedPropertyType propertyType) + : base(propertyType) + { + _dbVal = null; + _sourceValue = new Lazy(() => PropertyType.ConvertDataToSource(_dbVal, false)); + _objectValue = new Lazy(() => PropertyType.ConvertSourceToObject(_sourceValue.Value, false)); + _xpathValue = new Lazy(() => PropertyType.ConvertSourceToXPath(_sourceValue.Value, false)); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Security/MembershipHelper.cs b/src/Umbraco.Web/Security/MembershipHelper.cs index 78f7ab09a8..c8866e624c 100644 --- a/src/Umbraco.Web/Security/MembershipHelper.cs +++ b/src/Umbraco.Web/Security/MembershipHelper.cs @@ -10,6 +10,7 @@ using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Security; using Umbraco.Web.Models; +using Umbraco.Web.PublishedCache; namespace Umbraco.Web.Security { @@ -192,11 +193,41 @@ namespace Umbraco.Web.Security return true; } + #region Querying for front-end + + public IPublishedContent GetByProviderKey(object key) + { + var result = _applicationContext.Services.MemberService.GetByProviderKey(key); + return result == null ? null : new MemberPublishedContent(result, Membership.GetUser(result.Username)); + } + + public IPublishedContent GetById(int memberId) + { + var result = _applicationContext.Services.MemberService.GetById(memberId); + return result == null ? null : new MemberPublishedContent(result, Membership.GetUser(result.Username)); + } + + public IPublishedContent GetByUsername(string username) + { + var result = _applicationContext.Services.MemberService.GetByUsername(username); + return result == null ? null : new MemberPublishedContent(result, Membership.GetUser(result.Username)); + } + + public IPublishedContent GetByEmail(string email) + { + var result = _applicationContext.Services.MemberService.GetByEmail(email); + return result == null ? null : new MemberPublishedContent(result, Membership.GetUser(result.Username)); + } + + #endregion + + #region Model Creation methods for member data editing on the front-end /// - /// Creates a new profile model filled in with the current members details if they are logged in. + /// Creates a new profile model filled in with the current members details if they are logged in which allows for editing + /// profile properties /// /// - public ProfileModel CreateProfileModel() + public ProfileModel GetCurrentMemberProfileModel() { if (IsLoggedIn() == false) { @@ -212,6 +243,7 @@ namespace Umbraco.Web.Security var model = ProfileModel.CreateModel(); model.Name = member.Name; + model.MemberTypeAlias = member.ContentTypeAlias; model.Email = membershipUser.Email; model.UserName = membershipUser.UserName; @@ -225,6 +257,7 @@ namespace Umbraco.Web.Security model.LastActivityDate = membershipUser.LastActivityDate; model.LastPasswordChangedDate = membershipUser.LastPasswordChangedDate; + var memberType = member.ContentType; var builtIns = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray(); @@ -287,7 +320,8 @@ namespace Umbraco.Web.Security model.MemberTypeAlias = string.Empty; return model; } - } + } + #endregion /// /// Returns the login status model of the currently logged in member, if no member is logged in it returns null; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index b74f0f1c14..8397bb332c 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -299,6 +299,8 @@ + + diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 6aa2754fbc..10e5ce929f 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -17,6 +17,7 @@ using Umbraco.Core.Xml; using Umbraco.Web.Models; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; +using Umbraco.Web.Security; using Umbraco.Web.Templates; using umbraco; using System.Collections.Generic; @@ -35,7 +36,8 @@ namespace Umbraco.Web { private readonly UmbracoContext _umbracoContext; private readonly IPublishedContent _currentPage; - + private readonly MembershipHelper _membershipHelper; + /// /// Custom constructor setting the current page to the parameter passed in /// @@ -46,6 +48,7 @@ namespace Umbraco.Web { if (content == null) throw new ArgumentNullException("content"); _currentPage = content; + _membershipHelper = new MembershipHelper(_umbracoContext); } /// @@ -57,6 +60,7 @@ namespace Umbraco.Web if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); if (umbracoContext.RoutingContext == null) throw new NullReferenceException("The RoutingContext on the UmbracoContext cannot be null"); _umbracoContext = umbracoContext; + _membershipHelper = new MembershipHelper(_umbracoContext); if (_umbracoContext.IsFrontEndUmbracoRequest) { _currentPage = _umbracoContext.PublishedContentRequest.PublishedContent; @@ -405,7 +409,7 @@ namespace Umbraco.Web { if (IsProtected(nodeId, path)) { - return Member.IsLoggedOn() && Access.HasAccess(nodeId, path, Membership.GetUser()); + return _membershipHelper.IsLoggedIn() && Access.HasAccess(nodeId, path, Membership.GetUser()); } return true; } @@ -416,11 +420,7 @@ namespace Umbraco.Web /// True is the current user is logged in public bool MemberIsLoggedOn() { - /* - MembershipUser u = Membership.GetUser(); - return u != null; - */ - return Member.IsLoggedOn(); + return _membershipHelper.IsLoggedIn(); } #endregion @@ -482,9 +482,51 @@ namespace Umbraco.Web #endregion - #region Content + #region Members - public IPublishedContent TypedContent(object id) + public IPublishedContent TypedMember(object id) + { + var asInt = id.TryConvertTo(); + return asInt ? _membershipHelper.GetById(asInt.Result) : _membershipHelper.GetByProviderKey(id); + } + + public IPublishedContent TypedMember(int id) + { + return _membershipHelper.GetById(id); + } + + public IPublishedContent TypedMember(string id) + { + var asInt = id.TryConvertTo(); + return asInt ? _membershipHelper.GetById(asInt.Result) : _membershipHelper.GetByProviderKey(id); + } + + public dynamic Member(object id) + { + var asInt = id.TryConvertTo(); + return asInt + ? _membershipHelper.GetById(asInt.Result).AsDynamic() + : _membershipHelper.GetByProviderKey(id).AsDynamic(); + } + + public dynamic Member(int id) + { + return _membershipHelper.GetById(id).AsDynamic(); + } + + public dynamic Member(string id) + { + var asInt = id.TryConvertTo(); + return asInt + ? _membershipHelper.GetById(asInt.Result).AsDynamic() + : _membershipHelper.GetByProviderKey(id).AsDynamic(); + } + + #endregion + + #region Content + + public IPublishedContent TypedContent(object id) { return TypedDocumentById(id, _umbracoContext.ContentCache); } diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs index 9a24e653a3..6a752cdb7a 100644 --- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs +++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicNode.cs @@ -645,36 +645,8 @@ namespace umbraco.MacroEngines private object GetReflectedProperty(string alias) { - Func> getMember = - memberAlias => - { - try - { - return Attempt.Succeed( - n.GetType().InvokeMember(memberAlias, - System.Reflection.BindingFlags.GetProperty | - System.Reflection.BindingFlags.Instance | - System.Reflection.BindingFlags.Public, - null, - n, - null)); - } - catch (MissingMethodException ex) - { - return Attempt.Fail(ex); - } - }; - - //try with the current casing - var attempt = getMember(alias); - if (!attempt.Success) - { - //if we cannot get with the current alias, try changing it's case - attempt = alias[0].IsUpperCase() - ? getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.ConvertCase | CleanStringType.CamelCase)) - : getMember(alias.ToCleanString(CleanStringType.Ascii | CleanStringType.ConvertCase | CleanStringType.PascalCase)); - } - + var attempt = n.GetType().GetMemberIgnoreCase(n, alias); + return attempt.Success ? attempt.Result : null; }