From fec55e9d1c45f64b64e1509677b692e9b4968dc9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 18 Dec 2013 17:37:46 +1100 Subject: [PATCH] Updates IMemberService with methods to search on string properties with an option to define how to match the string property, adds all supporting unit tests. --- .../Querying/StringPropertyMatchType.cs | 13 + .../Repositories/MemberRepository.cs | 2 +- src/Umbraco.Core/Services/IMemberService.cs | 24 +- src/Umbraco.Core/Services/MediaService.cs | 41 +-- src/Umbraco.Core/Services/MemberService.cs | 135 ++++++++- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Services/MemberServiceTests.cs | 258 ++++++++++++++++++ 7 files changed, 439 insertions(+), 35 deletions(-) create mode 100644 src/Umbraco.Core/Persistence/Querying/StringPropertyMatchType.cs diff --git a/src/Umbraco.Core/Persistence/Querying/StringPropertyMatchType.cs b/src/Umbraco.Core/Persistence/Querying/StringPropertyMatchType.cs new file mode 100644 index 0000000000..f4245b931a --- /dev/null +++ b/src/Umbraco.Core/Persistence/Querying/StringPropertyMatchType.cs @@ -0,0 +1,13 @@ +namespace Umbraco.Core.Persistence.Querying +{ + /// + /// Determines how to match a string property value + /// + public enum StringPropertyMatchType + { + Exact, + Contains, + StartsWith, + EndsWith + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs index 723645b89c..ba28e68f02 100644 --- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs @@ -440,7 +440,7 @@ namespace Umbraco.Core.Persistence.Repositories public bool Exists(string username) { var sql = new Sql(); - var escapedUserName = Database.EscapeAtSymbols(username); + var escapedUserName = PetaPocoExtensions.EscapeAtSymbols(username); sql.Select("COUNT(*)") .From() .Where(x => x.LoginName == escapedUserName); diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs index ff758236a4..bd6544dc29 100644 --- a/src/Umbraco.Core/Services/IMemberService.cs +++ b/src/Umbraco.Core/Services/IMemberService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Querying; namespace Umbraco.Core.Services { @@ -22,10 +23,13 @@ namespace Umbraco.Core.Services IEnumerable GetMembersByMemberType(int memberTypeId); 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); + + IEnumerable GetMembersByPropertyValue(string propertyTypeAlias, string value, StringPropertyMatchType matchType = StringPropertyMatchType.Exact); + IEnumerable GetMembersByPropertyValue(string propertyTypeAlias, int value); + IEnumerable GetMembersByPropertyValue(string propertyTypeAlias, bool value); + IEnumerable GetMembersByPropertyValue(string propertyTypeAlias, DateTime value); } /// @@ -43,6 +47,14 @@ namespace Umbraco.Core.Services /// bool Exists(string username); + /// + /// Creates and persists a new member + /// + /// + /// + /// + /// + /// IMember CreateMember(string username, string email, string password, string memberTypeAlias); IMember GetById(object id); @@ -55,6 +67,10 @@ namespace Umbraco.Core.Services void Save(IMember membershipUser, bool raiseEvents = true); - IEnumerable FindMembersByEmail(string emailStringToMatch); + void Save(IEnumerable members, bool raiseEvents = true); + + IEnumerable FindMembersByEmail(string emailStringToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith); + + IEnumerable FindMembersByUsername(string login, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/MediaService.cs b/src/Umbraco.Core/Services/MediaService.cs index 4fe58904a2..fefb70d4cb 100644 --- a/src/Umbraco.Core/Services/MediaService.cs +++ b/src/Umbraco.Core/Services/MediaService.cs @@ -760,30 +760,31 @@ namespace Umbraco.Core.Services if (Saving.IsRaisedEventCancelled(new SaveEventArgs(medias), this)) return; } + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMediaRepository(uow)) + { + foreach (var media in medias) + { + media.CreatorId = userId; + repository.AddOrUpdate(media); + } - var mediaXml = new Dictionary>(); - var uow = _uowProvider.GetUnitOfWork(); - using (var repository = _repositoryFactory.CreateMediaRepository(uow)) - { - foreach (var media in medias) - { - media.CreatorId = userId; - repository.AddOrUpdate(media); - } + //commit the whole lot in one go + uow.Commit(); - //commit the whole lot in one go - uow.Commit(); + foreach (var media in medias) + { + CreateAndSaveMediaXml(media.ToXml(), media.Id, uow.Database); + } + } - foreach (var media in medias) - { - CreateAndSaveMediaXml(media.ToXml(), media.Id, uow.Database); - } - } + if (raiseEvents) + Saved.RaiseEvent(new SaveEventArgs(medias, false), this); - if(raiseEvents) - Saved.RaiseEvent(new SaveEventArgs(medias, false), this); - - Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1); + Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1); + } } /// diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs index 803bfabd31..0f4cd7c242 100644 --- a/src/Umbraco.Core/Services/MemberService.cs +++ b/src/Umbraco.Core/Services/MemberService.cs @@ -183,16 +183,61 @@ namespace Umbraco.Core.Services /// Does a search for members that contain the specified string in their email address /// /// + /// /// - public IEnumerable FindMembersByEmail(string emailStringToMatch) + public IEnumerable FindMembersByEmail(string emailStringToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith) { var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateMemberRepository(uow)) { var query = new Query(); + switch (matchType) + { + case StringPropertyMatchType.Exact: + query.Where(member => member.Email.Equals(emailStringToMatch)); + break; + case StringPropertyMatchType.Contains: + query.Where(member => member.Email.Contains(emailStringToMatch)); + break; + case StringPropertyMatchType.StartsWith: + query.Where(member => member.Email.StartsWith(emailStringToMatch)); + break; + case StringPropertyMatchType.EndsWith: + query.Where(member => member.Email.EndsWith(emailStringToMatch)); + break; + default: + throw new ArgumentOutOfRangeException("matchType"); + } - query.Where(member => member.Email.Contains(emailStringToMatch)); + return repository.GetByQuery(query); + } + } + + public IEnumerable FindMembersByUsername(string login, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberRepository(uow)) + { + var query = new Query(); + + switch (matchType) + { + case StringPropertyMatchType.Exact: + query.Where(member => member.Username.Equals(login)); + break; + case StringPropertyMatchType.Contains: + query.Where(member => member.Username.Contains(login)); + break; + case StringPropertyMatchType.StartsWith: + query.Where(member => member.Username.StartsWith(login)); + break; + case StringPropertyMatchType.EndsWith: + query.Where(member => member.Username.EndsWith(login)); + break; + default: + throw new ArgumentOutOfRangeException("matchType"); + } return repository.GetByQuery(query); } @@ -203,17 +248,51 @@ namespace Umbraco.Core.Services /// /// /// + /// /// - public IEnumerable GetMembersByPropertyValue(string propertyTypeAlias, string value) + public IEnumerable GetMembersByPropertyValue(string propertyTypeAlias, string value, StringPropertyMatchType matchType = StringPropertyMatchType.Exact) { using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork())) { - var query = - Query.Builder.Where( - x => - ((Member)x).PropertyTypeAlias == propertyTypeAlias && - (((Member)x).LongStringPropertyValue.Contains(value) || - ((Member)x).ShortStringPropertyValue.Contains(value))); + IQuery query; + + switch (matchType) + { + case StringPropertyMatchType.Exact: + query = + Query.Builder.Where( + x => + ((Member) x).PropertyTypeAlias == propertyTypeAlias && + (((Member)x).LongStringPropertyValue.SqlEquals(value, TextColumnType.NText) || + ((Member)x).ShortStringPropertyValue.SqlEquals(value, TextColumnType.NVarchar))); + break; + case StringPropertyMatchType.Contains: + query = + Query.Builder.Where( + x => + ((Member) x).PropertyTypeAlias == propertyTypeAlias && + (((Member)x).LongStringPropertyValue.SqlContains(value, TextColumnType.NText) || + ((Member)x).ShortStringPropertyValue.SqlContains(value, TextColumnType.NVarchar))); + break; + case StringPropertyMatchType.StartsWith: + query = + Query.Builder.Where( + x => + ((Member) x).PropertyTypeAlias == propertyTypeAlias && + (((Member)x).LongStringPropertyValue.SqlStartsWith(value, TextColumnType.NText) || + ((Member)x).ShortStringPropertyValue.SqlStartsWith(value, TextColumnType.NVarchar))); + break; + case StringPropertyMatchType.EndsWith: + query = + Query.Builder.Where( + x => + ((Member) x).PropertyTypeAlias == propertyTypeAlias && + (((Member)x).LongStringPropertyValue.SqlEndsWith(value, TextColumnType.NText) || + ((Member)x).ShortStringPropertyValue.SqlEndsWith(value, TextColumnType.NVarchar))); + break; + default: + throw new ArgumentOutOfRangeException("matchType"); + } var members = repository.GetByQuery(query); return members; @@ -352,7 +431,7 @@ namespace Umbraco.Core.Services { using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork())) { - var query = Query.Builder.Where(x => x.Email == email); + var query = Query.Builder.Where(x => x.Email.Equals(email)); var member = repository.GetByQuery(query).FirstOrDefault(); return member; @@ -381,12 +460,17 @@ namespace Umbraco.Core.Services /// public void Delete(IMember member) { + if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(member), this)) + return; + var uow = _uowProvider.GetUnitOfWork(); using (var repository = _repositoryFactory.CreateMemberRepository(uow)) { repository.Delete(member); uow.Commit(); } + + Deleted.RaiseEvent(new DeleteEventArgs(member, false), this); } /// @@ -416,6 +500,37 @@ namespace Umbraco.Core.Services Saved.RaiseEvent(new SaveEventArgs(member, false), this); } + public void Save(IEnumerable members, bool raiseEvents = true) + { + if (raiseEvents) + { + if (Saving.IsRaisedEventCancelled(new SaveEventArgs(members), this)) + return; + } + using (new WriteLock(Locker)) + { + var uow = _uowProvider.GetUnitOfWork(); + using (var repository = _repositoryFactory.CreateMemberRepository(uow)) + { + foreach (var member in members) + { + repository.AddOrUpdate(member); + } + + //commit the whole lot in one go + uow.Commit(); + + foreach (var member in members) + { + CreateAndSaveMemberXml(member.ToXml(), member.Id, uow.Database); + } + } + + if (raiseEvents) + Saved.RaiseEvent(new SaveEventArgs(members, false), this); + } + } + #endregion /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 48e9d5c5be..7d400f5abc 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -201,6 +201,7 @@ + diff --git a/src/Umbraco.Tests/Services/MemberServiceTests.cs b/src/Umbraco.Tests/Services/MemberServiceTests.cs index 7ddbe972ec..54fa355ce5 100644 --- a/src/Umbraco.Tests/Services/MemberServiceTests.cs +++ b/src/Umbraco.Tests/Services/MemberServiceTests.cs @@ -1,6 +1,9 @@ +using System.Linq; using NUnit.Framework; using Umbraco.Core.Models; using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.Querying; +using Umbraco.Core.Services; using Umbraco.Tests.TestHelpers.Entities; namespace Umbraco.Tests.Services @@ -46,5 +49,260 @@ namespace Umbraco.Tests.Services var xml = DatabaseContext.Database.FirstOrDefault("WHERE nodeId = @Id", new { Id = member.Id }); Assert.IsNotNull(xml); } + + [Test] + public void Exists_By_Username() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + + Assert.IsTrue(ServiceContext.MemberService.Exists("test")); + Assert.IsFalse(ServiceContext.MemberService.Exists("notFound")); + } + + [Test] + public void Exists_By_Id() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + + Assert.IsTrue(ServiceContext.MemberService.Exists(member.Id)); + Assert.IsFalse(ServiceContext.MemberService.Exists(9876)); + } + + [Test] + public void Get_By_Email() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + + Assert.IsNotNull(ServiceContext.MemberService.GetByEmail(member.Email)); + Assert.IsNull(ServiceContext.MemberService.GetByEmail("do@not.find")); + } + + [Test] + public void Get_By_Username() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + + Assert.IsNotNull(ServiceContext.MemberService.GetByUsername(member.Username)); + Assert.IsNull(ServiceContext.MemberService.GetByUsername("notFound")); + } + + [Test] + public void Get_By_Object_Id() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + IMember member = MockedMember.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test"); + ServiceContext.MemberService.Save(member); + + Assert.IsNotNull(ServiceContext.MemberService.GetById((object)member.Id)); + Assert.IsNull(ServiceContext.MemberService.GetById((object)9876)); + } + + [Test] + public void Find_By_Email_Starts_With() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //don't find this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello","hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByEmail("tes", StringPropertyMatchType.StartsWith); + + Assert.AreEqual(10, found.Count()); + } + + [Test] + public void Find_By_Email_Ends_With() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //include this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByEmail("test.com", StringPropertyMatchType.EndsWith); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Find_By_Email_Contains() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //include this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByEmail("test", StringPropertyMatchType.Contains); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Find_By_Email_Exact() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //include this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByEmail("hello@test.com", StringPropertyMatchType.Exact); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Find_By_Login_Starts_With() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //don't find this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByUsername("tes", StringPropertyMatchType.StartsWith); + + Assert.AreEqual(10, found.Count()); + } + + [Test] + public void Find_By_Login_Ends_With() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //include this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByUsername("llo", StringPropertyMatchType.EndsWith); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Find_By_Login_Contains() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //include this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hellotest"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByUsername("test", StringPropertyMatchType.Contains); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Find_By_Login_Exact() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + //include this + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.FindMembersByUsername("hello", StringPropertyMatchType.Exact); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Get_By_Property_Value_Exact() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.GetMembersByPropertyValue( + "title", "hello member", StringPropertyMatchType.Exact); + + Assert.AreEqual(1, found.Count()); + } + + [Test] + public void Get_By_Property_Value_Contains() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.GetMembersByPropertyValue( + "title", " member", StringPropertyMatchType.Contains); + + Assert.AreEqual(11, found.Count()); + } + + [Test] + public void Get_By_Property_Value_Starts_With() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.GetMembersByPropertyValue( + "title", "Member No", StringPropertyMatchType.StartsWith); + + Assert.AreEqual(10, found.Count()); + } + + [Test] + public void Get_By_Property_Value_Ends_With() + { + IMemberType memberType = MockedContentTypes.CreateSimpleMemberType(); + ServiceContext.MemberTypeService.Save(memberType); + var members = MockedMember.CreateSimpleMember(memberType, 10); + ServiceContext.MemberService.Save(members); + var customMember = MockedMember.CreateSimpleMember(memberType, "hello", "hello@test.com", "hello", "hello"); + customMember.SetValue("title", "title of mine"); + ServiceContext.MemberService.Save(customMember); + + var found = ServiceContext.MemberService.GetMembersByPropertyValue( + "title", "mine", StringPropertyMatchType.EndsWith); + + Assert.AreEqual(1, found.Count()); + } + + } } \ No newline at end of file