diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs
index 64f1449399..ffa84f025e 100644
--- a/src/Umbraco.Core/Constants-Conventions.cs
+++ b/src/Umbraco.Core/Constants-Conventions.cs
@@ -236,8 +236,7 @@ namespace Umbraco.Core
},
{
PasswordQuestion,
- new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType
- .Nvarchar)
+ new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType.Nvarchar)
{
Alias = PasswordQuestion,
Name = PasswordQuestionLabel
diff --git a/src/Umbraco.Core/Models/Member.cs b/src/Umbraco.Core/Models/Member.cs
index 9425446560..78be963eac 100644
--- a/src/Umbraco.Core/Models/Member.cs
+++ b/src/Umbraco.Core/Models/Member.cs
@@ -20,6 +20,17 @@ namespace Umbraco.Core.Models
private object _providerUserKey;
private Type _userTypeKey;
+ ///
+ /// Constructor for creating a Member object
+ ///
+ /// Name of the content
+ /// ContentType for the current Content object
+ public Member(string name, IMemberType contentType)
+ : base(name, -1, contentType, new PropertyCollection())
+ {
+ _contentType = contentType;
+ }
+
internal Member(string name, string email, string username, string password, int parentId, IMemberType contentType)
: base(name, parentId, contentType, new PropertyCollection())
{
diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
index eafaf74a4f..723645b89c 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
@@ -22,14 +22,17 @@ namespace Umbraco.Core.Persistence.Repositories
{
private readonly IMemberTypeRepository _memberTypeRepository;
- public MemberRepository(IDatabaseUnitOfWork work, IMemberTypeRepository memberTypeRepository) : base(work)
+ public MemberRepository(IDatabaseUnitOfWork work, IMemberTypeRepository memberTypeRepository)
+ : base(work)
{
+ if (memberTypeRepository == null) throw new ArgumentNullException("memberTypeRepository");
_memberTypeRepository = memberTypeRepository;
}
public MemberRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IMemberTypeRepository memberTypeRepository)
: base(work, cache)
{
+ if (memberTypeRepository == null) throw new ArgumentNullException("memberTypeRepository");
_memberTypeRepository = memberTypeRepository;
}
@@ -104,11 +107,11 @@ namespace Umbraco.Core.Persistence.Repositories
sql.Select("umbracoNode.*", "cmsContent.contentType", "cmsContentType.alias AS ContentTypeAlias", "cmsContentVersion.VersionId",
"cmsContentVersion.VersionDate", "cmsContentVersion.LanguageLocale", "cmsMember.Email",
- "cmsMember.LoginName", "cmsMember.Password", "cmsPropertyData.id AS PropertyDataId", "cmsPropertyData.propertytypeid",
+ "cmsMember.LoginName", "cmsMember.Password", "cmsPropertyData.id AS PropertyDataId", "cmsPropertyData.propertytypeid",
"cmsPropertyData.dataDate", "cmsPropertyData.dataInt", "cmsPropertyData.dataNtext", "cmsPropertyData.dataNvarchar",
"cmsPropertyType.id", "cmsPropertyType.Alias", "cmsPropertyType.Description",
"cmsPropertyType.Name", "cmsPropertyType.mandatory", "cmsPropertyType.validationRegExp",
- "cmsPropertyType.helpText", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", "cmsPropertyType.propertyTypeGroupId",
+ "cmsPropertyType.helpText", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", "cmsPropertyType.propertyTypeGroupId",
"cmsPropertyType.dataTypeId", "cmsDataType.controlId", "cmsDataType.dbType")
.From()
.InnerJoin().On(left => left.NodeId, right => right.NodeId)
@@ -247,7 +250,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
property.Id = keyDictionary[property.PropertyTypeId];
}
-
+
((Member)entity).ResetDirtyProperties();
}
@@ -256,8 +259,10 @@ namespace Umbraco.Core.Persistence.Repositories
//Updates Modified date
((Member)entity).UpdatingEntity();
+ var dirtyEntity = (ICanBeDirty)entity;
+
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
- if (((ICanBeDirty)entity).IsPropertyDirty("ParentId"))
+ if (dirtyEntity.IsPropertyDirty("ParentId"))
{
var parent = Database.First("WHERE id = @ParentId", new { ParentId = ((IUmbracoEntity)entity).ParentId });
((IUmbracoEntity)entity).Path = string.Concat(parent.Path, ",", entity.Id);
@@ -293,13 +298,32 @@ namespace Umbraco.Core.Persistence.Repositories
//Updates the current version - cmsContentVersion
//Assumes a Version guid exists and Version date (modified date) has been set/updated
Database.Update(dto.ContentVersionDto);
- //Updates the cmsMember entry
- Database.Update(dto);
+
+ //Updates the cmsMember entry if it has changed
+ var changedCols = new List();
+ if (dirtyEntity.IsPropertyDirty("Email"))
+ {
+ changedCols.Add("Email");
+ }
+ if (dirtyEntity.IsPropertyDirty("Username"))
+ {
+ changedCols.Add("LoginName");
+ }
+ // DO NOT update the password if it is null or empty
+ if (dirtyEntity.IsPropertyDirty("Password") && entity.Password.IsNullOrWhiteSpace() == false)
+ {
+ changedCols.Add("Password");
+ }
+ //only update the changed cols
+ if (changedCols.Count > 0)
+ {
+ Database.Update(dto, changedCols);
+ }
//TODO ContentType for the Member entity
//Create the PropertyData for this version - cmsPropertyData
- var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
+ var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
var keyDictionary = new Dictionary();
//Add Properties
@@ -333,8 +357,8 @@ namespace Umbraco.Core.Persistence.Repositories
property.Id = keyDictionary[property.PropertyTypeId];
}
}
-
- ((ICanBeDirty)entity).ResetDirtyProperties();
+
+ dirtyEntity.ResetDirtyProperties();
}
protected override void PersistDeletedItem(IMember entity)
@@ -416,9 +440,10 @@ namespace Umbraco.Core.Persistence.Repositories
public bool Exists(string username)
{
var sql = new Sql();
+ var escapedUserName = Database.EscapeAtSymbols(username);
sql.Select("COUNT(*)")
.From()
- .Where(x => x.LoginName == username);
+ .Where(x => x.LoginName == escapedUserName);
return Database.ExecuteScalar(sql) > 0;
}
diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs
index 703e68be71..ff758236a4 100644
--- a/src/Umbraco.Core/Services/IMemberService.cs
+++ b/src/Umbraco.Core/Services/IMemberService.cs
@@ -23,6 +23,8 @@ namespace Umbraco.Core.Services
IEnumerable GetMembersByGroup(string memberGroupName);
IEnumerable GetAllMembers(params int[] ids);
+ //TODO: Need to get all members that start with a certain letter
+
void DeleteMembersOfType(int memberTypeId);
}
@@ -51,7 +53,7 @@ namespace Umbraco.Core.Services
void Delete(IMember membershipUser);
- void Save(IMember membershipUser);
+ void Save(IMember membershipUser, bool raiseEvents = true);
IEnumerable FindMembersByEmail(string emailStringToMatch);
}
diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs
index b76caadff2..803bfabd31 100644
--- a/src/Umbraco.Core/Services/MemberService.cs
+++ b/src/Umbraco.Core/Services/MemberService.cs
@@ -393,8 +393,15 @@ namespace Umbraco.Core.Services
/// Saves an updated Member
///
///
- public void Save(IMember member)
+ ///
+ public void Save(IMember member, bool raiseEvents = true)
{
+ if (raiseEvents)
+ {
+ if (Saving.IsRaisedEventCancelled(new SaveEventArgs(member), this))
+ return;
+ }
+
var uow = _uowProvider.GetUnitOfWork();
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
{
@@ -404,6 +411,9 @@ namespace Umbraco.Core.Services
var xml = member.ToXml();
CreateAndSaveMemberXml(xml, member.Id, uow.Database);
}
+
+ if (raiseEvents)
+ Saved.RaiseEvent(new SaveEventArgs(member, false), this);
}
#endregion
@@ -483,14 +493,91 @@ namespace Umbraco.Core.Services
int result = exists ? db.Update(poco) : Convert.ToInt32(db.Insert(poco));
}
+ #region Event Handlers
+
+
///
/// Occurs before Delete
- ///
+ ///
public static event TypedEventHandler> Deleting;
///
/// Occurs after Delete
///
public static event TypedEventHandler> Deleted;
+
+ ///
+ /// Occurs before Save
+ ///
+ public static event TypedEventHandler> Saving;
+
+ ///
+ /// Occurs after Save
+ ///
+ public static event TypedEventHandler> Saved;
+
+ #endregion
+
+ /////
+ ///// A helper method that will create a basic/generic member for use with a generic membership provider
+ /////
+ /////
+ //internal static IMember CreateGenericMembershipProviderMember(string name, string email, string username, string password)
+ //{
+ // var identity = int.MaxValue;
+
+ // var memType = new MemberType(-1);
+ // var propGroup = new PropertyGroup
+ // {
+ // Name = "Membership",
+ // Id = --identity
+ // };
+ // propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
+ // {
+ // Alias = Constants.Conventions.Member.Comments,
+ // Name = Constants.Conventions.Member.CommentsLabel,
+ // SortOrder = 0,
+ // Id = --identity
+ // });
+ // propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer)
+ // {
+ // Alias = Constants.Conventions.Member.IsApproved,
+ // Name = Constants.Conventions.Member.IsApprovedLabel,
+ // SortOrder = 3,
+ // Id = --identity
+ // });
+ // propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer)
+ // {
+ // Alias = Constants.Conventions.Member.IsLockedOut,
+ // Name = Constants.Conventions.Member.IsLockedOutLabel,
+ // SortOrder = 4,
+ // Id = --identity
+ // });
+ // propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date)
+ // {
+ // Alias = Constants.Conventions.Member.LastLockoutDate,
+ // Name = Constants.Conventions.Member.LastLockoutDateLabel,
+ // SortOrder = 5,
+ // Id = --identity
+ // });
+ // propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date)
+ // {
+ // Alias = Constants.Conventions.Member.LastLoginDate,
+ // Name = Constants.Conventions.Member.LastLoginDateLabel,
+ // SortOrder = 6,
+ // Id = --identity
+ // });
+ // propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date)
+ // {
+ // Alias = Constants.Conventions.Member.LastPasswordChangeDate,
+ // Name = Constants.Conventions.Member.LastPasswordChangeDateLabel,
+ // SortOrder = 7,
+ // Id = --identity
+ // });
+
+ // memType.PropertyGroups.Add(propGroup);
+
+ // return new Member(name, email, username, password, -1, memType);
+ //}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs
index 86a871df11..b2253c8dd0 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs
@@ -221,6 +221,63 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
+ [Test]
+ public void MemberRepository_Does_Not_Replace_Password_When_Null()
+ {
+ IMember sut;
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MemberTypeRepository memberTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out memberTypeRepository))
+ {
+ var memberType = MockedContentTypes.CreateSimpleMemberType();
+ memberTypeRepository.AddOrUpdate(memberType);
+ unitOfWork.Commit();
+
+ var member = MockedMember.CreateSimpleMember(memberType, "Johnny Hefty", "johnny@example.com", "123", "hefty");
+ repository.AddOrUpdate(member);
+ unitOfWork.Commit();
+
+ sut = repository.Get(member.Id);
+ //when the password is null it will not overwrite what is already there.
+ sut.Password = null;
+ repository.AddOrUpdate(sut);
+ unitOfWork.Commit();
+ sut = repository.Get(member.Id);
+
+ Assert.That(sut.Password, Is.EqualTo("123"));
+ }
+ }
+
+ [Test]
+ public void MemberRepository_Can_Update_Email_And_Login_When_Changed()
+ {
+ IMember sut;
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ MemberTypeRepository memberTypeRepository;
+ using (var repository = CreateRepository(unitOfWork, out memberTypeRepository))
+ {
+ var memberType = MockedContentTypes.CreateSimpleMemberType();
+ memberTypeRepository.AddOrUpdate(memberType);
+ unitOfWork.Commit();
+
+ var member = MockedMember.CreateSimpleMember(memberType, "Johnny Hefty", "johnny@example.com", "123", "hefty");
+ repository.AddOrUpdate(member);
+ unitOfWork.Commit();
+
+ sut = repository.Get(member.Id);
+ sut.Username = "This is new";
+ sut.Email = "thisisnew@hello.com";
+ repository.AddOrUpdate(sut);
+ unitOfWork.Commit();
+ sut = repository.Get(member.Id);
+
+ Assert.That(sut.Email, Is.EqualTo("thisisnew@hello.com"));
+ Assert.That(sut.Username, Is.EqualTo("This is new"));
+ }
+ }
+
[Test]
public void Can_Create_Correct_Subquery()
{
diff --git a/src/Umbraco.Web/Strategies/Migrations/ClearMediaXmlCacheForDeletedItemsAfterUpgrade.cs b/src/Umbraco.Web/Strategies/Migrations/ClearMediaXmlCacheForDeletedItemsAfterUpgrade.cs
new file mode 100644
index 0000000000..43269731e7
--- /dev/null
+++ b/src/Umbraco.Web/Strategies/Migrations/ClearMediaXmlCacheForDeletedItemsAfterUpgrade.cs
@@ -0,0 +1,52 @@
+using System;
+using Umbraco.Core;
+using Umbraco.Core.Logging;
+using Umbraco.Core.Persistence.Migrations;
+using Umbraco.Core.Persistence.SqlSyntax;
+using Umbraco.Core.Services;
+using umbraco.interfaces;
+
+namespace Umbraco.Web.Strategies.Migrations
+{
+ ///
+ /// This will execute after upgrading to remove any xml cache for media that are currently in the bin
+ ///
+ ///
+ /// This will execute for specific versions -
+ ///
+ /// * If current is less than or equal to 7.0.0
+ ///
+ public class ClearMediaXmlCacheForDeletedItemsAfterUpgrade : IApplicationStartupHandler
+ {
+ public ClearMediaXmlCacheForDeletedItemsAfterUpgrade()
+ {
+ MigrationRunner.Migrated += MigrationRunner_Migrated;
+ }
+
+ void MigrationRunner_Migrated(MigrationRunner sender, Core.Events.MigrationEventArgs e)
+ {
+ var target70 = new Version(7, 0, 0);
+
+ if (e.ConfiguredVersion <= target70)
+ {
+
+ var sql = @"DELETE a
+ FROM cmsContentXml a
+ INNER JOIN umbracoNode b
+ ON a.nodeId = b.id
+ WHERE nodeObjectType = 'B796F64C-1F99-4FFB-B886-4BF4BC011A9C' AND " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("path") + " like '%-21%'";
+
+// var sql = @"DELETE FROM cmsContentXml WHERE nodeId IN
+// (SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml
+// INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id
+// WHERE nodeObjectType = 'B796F64C-1F99-4FFB-B886-4BF4BC011A9C' AND " + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("path") + " like '%-21%')";
+
+ var count = e.MigrationContext.Database.Execute(sql);
+
+ LogHelper.Info("Cleared " + count + " items from the media xml cache that were trashed and not meant to be there");
+
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 3a260ca223..c1d56a5031 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -391,6 +391,7 @@
+
@@ -421,10 +422,9 @@
AssignDomain2.aspx
-
+
ASPXCodeBehind
-
ASPXCodeBehind