diff --git a/src/Umbraco.Core/Cache/CacheKeys.cs b/src/Umbraco.Core/Cache/CacheKeys.cs
index d4dd6f48f0..1278ff0e33 100644
--- a/src/Umbraco.Core/Cache/CacheKeys.cs
+++ b/src/Umbraco.Core/Cache/CacheKeys.cs
@@ -27,7 +27,7 @@ namespace Umbraco.Core.Cache
public const string MemberLibraryCacheKey = "UL_GetMember";
public const string MemberBusinessLogicCacheKey = "MemberCacheItem_";
-
+
public const string TemplateFrontEndCacheKey = "template";
public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache";
diff --git a/src/Umbraco.Core/Models/IMemberGroup.cs b/src/Umbraco.Core/Models/IMemberGroup.cs
index f865a7d991..5c3741997b 100644
--- a/src/Umbraco.Core/Models/IMemberGroup.cs
+++ b/src/Umbraco.Core/Models/IMemberGroup.cs
@@ -1,4 +1,5 @@
-using Umbraco.Core.Models.EntityBase;
+using System.Collections.Generic;
+using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Models
{
@@ -16,5 +17,10 @@ namespace Umbraco.Core.Models
/// Profile of the user who created this Entity
///
int CreatorId { get; set; }
+
+ ///
+ /// Some entities may expose additional data that other's might not, this custom data will be available in this collection
+ ///
+ IDictionary AdditionalData { get; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/MemberGroup.cs b/src/Umbraco.Core/Models/MemberGroup.cs
index 5d77c92385..e52448a11d 100644
--- a/src/Umbraco.Core/Models/MemberGroup.cs
+++ b/src/Umbraco.Core/Models/MemberGroup.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
@@ -12,6 +13,11 @@ namespace Umbraco.Core.Models
[DataContract(IsReference = true)]
public class MemberGroup : Entity, IMemberGroup
{
+ public MemberGroup()
+ {
+ AdditionalData = new Dictionary();
+ }
+
private string _name;
private int _creatorId;
@@ -26,6 +32,14 @@ namespace Umbraco.Core.Models
{
SetPropertyValueAndDetectChanges(o =>
{
+ if (_name != value)
+ {
+ //if the name has changed, add the value to the additional data,
+ //this is required purely for event handlers to know the previous name of the group
+ //so we can keep the public access up to date.
+ AdditionalData["previousName"] = _name;
+ }
+
_name = value;
return _name;
}, _name, NameSelector);
@@ -45,6 +59,8 @@ namespace Umbraco.Core.Models
}
}
+ public IDictionary AdditionalData { get; private set; }
+
///
/// Method to call when Entity is being saved
///
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberGroupRepository.cs
index 591d621403..2750457271 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberGroupRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberGroupRepository.cs
@@ -5,11 +5,18 @@ namespace Umbraco.Core.Persistence.Repositories
{
public interface IMemberGroupRepository : IRepositoryQueryable
{
+ ///
+ /// Gets a member group by it's name
+ ///
+ ///
+ ///
+ IMemberGroup GetByName(string name);
+
///
/// Creates the new member group if it doesn't already exist
///
///
- void CreateIfNotExists(string roleName);
+ IMemberGroup CreateIfNotExists(string roleName);
///
/// Returns the member groups for a given member
diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs
index 3ae62f62f9..4b9d39c99c 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MemberGroupRepository.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
@@ -9,6 +10,8 @@ using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Persistence.UnitOfWork;
+using Umbraco.Core.Services;
+using Umbraco.Core.Cache;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -16,12 +19,20 @@ namespace Umbraco.Core.Persistence.Repositories
internal class MemberGroupRepository : PetaPocoRepositoryBase, IMemberGroupRepository
{
- public MemberGroupRepository(IDatabaseUnitOfWork work) : base(work)
+ private readonly CacheHelper _cacheHelper;
+
+ public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper)
+ : base(work)
{
+ if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
+ _cacheHelper = cacheHelper;
}
- public MemberGroupRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache)
+ public MemberGroupRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, CacheHelper cacheHelper)
+ : base(work, cache)
{
+ if (cacheHelper == null) throw new ArgumentNullException("cacheHelper");
+ _cacheHelper = cacheHelper;
}
private readonly MemberGroupFactory _modelFactory = new MemberGroupFactory();
@@ -86,6 +97,11 @@ namespace Umbraco.Core.Persistence.Repositories
{
var list = new[]
{
+ "DELETE FROM umbracoUser2NodeNotify WHERE nodeId = @Id",
+ "DELETE FROM umbracoUser2NodePermission WHERE nodeId = @Id",
+ "DELETE FROM umbracoRelation WHERE parentId = @Id",
+ "DELETE FROM umbracoRelation WHERE childId = @Id",
+ "DELETE FROM cmsTagRelationship WHERE nodeId = @Id",
"DELETE FROM cmsMember2MemberGroup WHERE MemberGroup = @Id",
"DELETE FROM umbracoNode WHERE id = @Id"
};
@@ -117,26 +133,52 @@ namespace Umbraco.Core.Persistence.Repositories
var dto = _modelFactory.BuildDto(entity);
Database.Update(dto);
-
+
((ICanBeDirty)entity).ResetDirtyProperties();
}
- public void CreateIfNotExists(string roleName)
+ public IMemberGroup GetByName(string name)
+ {
+ return _cacheHelper.RuntimeCache.GetCacheItem(
+ string.Format("{0}.{1}", typeof (IMemberGroup).FullName, name),
+ () =>
+ {
+ var qry = new Query().Where(group => group.Name.Equals(name));
+ var result = GetByQuery(qry);
+ return result.FirstOrDefault();
+ },
+ //cache for 5 mins since that is the default in the RuntimeCacheProvider
+ TimeSpan.FromMinutes(5),
+ //sliding is true
+ true);
+ }
+
+ public IMemberGroup CreateIfNotExists(string roleName)
{
using (var transaction = Database.GetTransaction())
{
var qry = new Query().Where(group => group.Name.Equals(roleName));
var result = GetByQuery(qry);
- if (result.Any()) return;
+ if (result.Any()) return null;
- PersistNewItem(new MemberGroup
+ var grp = new MemberGroup
{
Name = roleName
- });
+ };
+ PersistNewItem(grp);
+
+ if (SavingMemberGroup.IsRaisedEventCancelled(new SaveEventArgs(grp), this))
+ {
+ return null;
+ }
transaction.Complete();
- }
+
+ SavedMemberGroup.RaiseEvent(new SaveEventArgs(grp), this);
+
+ return grp;
+ }
}
public IEnumerable GetMemberGroupsForMember(int memberId)
@@ -244,10 +286,18 @@ namespace Umbraco.Core.Persistence.Repositories
.Where("umbracoNode." + SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName("text") + " in (@names)", new { names = roleNames });
var existingRoles = Database.Fetch(existingSql).Select(x => x.Text);
var missingRoles = roleNames.Except(existingRoles);
- foreach (var m in missingRoles)
+ var missingGroups = missingRoles.Select(x => new MemberGroup {Name = x}).ToArray();
+
+ if (SavingMemberGroup.IsRaisedEventCancelled(new SaveEventArgs(missingGroups), this))
{
- PersistNewItem(new MemberGroup { Name = m });
+ return;
}
+ foreach (var m in missingGroups)
+ {
+ PersistNewItem(m);
+ }
+ SavedMemberGroup.RaiseEvent(new SaveEventArgs(missingGroups), this);
+
//now go get all the dto's for roles with these role names
var rolesForNames = Database.Fetch(existingSql).ToArray();
@@ -318,5 +368,15 @@ namespace Umbraco.Core.Persistence.Repositories
[Column("MemberGroup")]
public int MemberGroupId { get; set; }
}
+
+ ///
+ /// Occurs before Save
+ ///
+ internal static event TypedEventHandler> SavingMemberGroup;
+
+ ///
+ /// Occurs after Save
+ ///
+ internal static event TypedEventHandler> SavedMemberGroup;
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
index 935c199749..0030ae5d66 100644
--- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs
+++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
@@ -166,7 +166,7 @@ namespace Umbraco.Core.Persistence
internal virtual IMemberGroupRepository CreateMemberGroupRepository(IDatabaseUnitOfWork uow)
{
- return new MemberGroupRepository(uow, _disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current);
+ return new MemberGroupRepository(uow, _disableAllCache ? (IRepositoryCacheProvider)NullCacheProvider.Current : RuntimeCacheProvider.Current, _cacheHelper);
}
internal virtual IEntityRepository CreateEntityRepository(IDatabaseUnitOfWork uow)
diff --git a/src/Umbraco.Core/Services/IMemberGroupService.cs b/src/Umbraco.Core/Services/IMemberGroupService.cs
new file mode 100644
index 0000000000..966bb87e4c
--- /dev/null
+++ b/src/Umbraco.Core/Services/IMemberGroupService.cs
@@ -0,0 +1,14 @@
+using System.Collections.Generic;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Core.Services
+{
+ public interface IMemberGroupService : IService
+ {
+ IEnumerable GetAll();
+ IMemberGroup GetById(int id);
+ IMemberGroup GetByName(string name);
+ void Save(IMemberGroup memberGroup, bool raiseEvents = true);
+ void Delete(IMemberGroup memberGroup);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/MemberGroupService.cs b/src/Umbraco.Core/Services/MemberGroupService.cs
new file mode 100644
index 0000000000..ae12614d56
--- /dev/null
+++ b/src/Umbraco.Core/Services/MemberGroupService.cs
@@ -0,0 +1,138 @@
+using System.Collections.Generic;
+using System.Linq;
+using Umbraco.Core.Events;
+using Umbraco.Core.Models;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Querying;
+using Umbraco.Core.Persistence.Repositories;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Core.Services
+{
+ public class MemberGroupService : IMemberGroupService
+ {
+ private readonly RepositoryFactory _repositoryFactory;
+ private readonly IDatabaseUnitOfWorkProvider _uowProvider;
+
+ public MemberGroupService(RepositoryFactory repositoryFactory)
+ : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
+ {
+ }
+
+ public MemberGroupService(IDatabaseUnitOfWorkProvider provider)
+ : this(provider, new RepositoryFactory())
+ {
+ }
+
+ public MemberGroupService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory)
+ {
+ _repositoryFactory = repositoryFactory;
+ _uowProvider = provider;
+
+ //Proxy events!
+ MemberGroupRepository.SavedMemberGroup += MemberGroupRepository_SavedMemberGroup;
+ MemberGroupRepository.SavingMemberGroup += MemberGroupRepository_SavingMemberGroup;
+ }
+
+ #region Proxied event handlers
+ void MemberGroupRepository_SavingMemberGroup(IMemberGroupRepository sender, SaveEventArgs e)
+ {
+ if (Saving.IsRaisedEventCancelled(new SaveEventArgs(e.SavedEntities), this))
+ {
+ e.Cancel = true;
+ }
+ }
+
+ void MemberGroupRepository_SavedMemberGroup(IMemberGroupRepository sender, SaveEventArgs e)
+ {
+ Saved.RaiseEvent(new SaveEventArgs(e.SavedEntities, false), this);
+ }
+ #endregion
+
+ public IEnumerable GetAll()
+ {
+ using (var repository = _repositoryFactory.CreateMemberGroupRepository(_uowProvider.GetUnitOfWork()))
+ {
+ return repository.GetAll();
+ }
+ }
+
+ public IMemberGroup GetById(int id)
+ {
+ using (var repository = _repositoryFactory.CreateMemberGroupRepository(_uowProvider.GetUnitOfWork()))
+ {
+ return repository.Get(id);
+ }
+ }
+
+ public IMemberGroup GetByName(string name)
+ {
+ using (var repository = _repositoryFactory.CreateMemberGroupRepository(_uowProvider.GetUnitOfWork()))
+ {
+ return repository.GetByName(name);
+ }
+ }
+
+ public void Save(IMemberGroup memberGroup, bool raiseEvents = true)
+ {
+ if (raiseEvents)
+ {
+ if (Saving.IsRaisedEventCancelled(new SaveEventArgs(memberGroup), this))
+ {
+ return;
+ }
+ }
+
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
+ {
+ repository.AddOrUpdate(memberGroup);
+ uow.Commit();
+ }
+
+ if (raiseEvents)
+ Saved.RaiseEvent(new SaveEventArgs(memberGroup, false), this);
+ }
+
+ public void Delete(IMemberGroup memberGroup)
+ {
+ if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(memberGroup), this))
+ return;
+
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
+ {
+ repository.Delete(memberGroup);
+ uow.Commit();
+ }
+
+ Deleted.RaiseEvent(new DeleteEventArgs(memberGroup, false), this);
+ }
+
+ ///
+ /// Occurs before Delete of a member group
+ ///
+ public static event TypedEventHandler> Deleting;
+
+ ///
+ /// Occurs after Delete of a member group
+ ///
+ public static event TypedEventHandler> Deleted;
+
+ ///
+ /// Occurs before Save of a member group
+ ///
+ ///
+ /// We need to proxy these events because the events need to take place at the repo level
+ ///
+ public static event TypedEventHandler> Saving;
+
+ ///
+ /// Occurs after Save of a member group
+ ///
+ ///
+ /// We need to proxy these events because the events need to take place at the repo level
+ ///
+ public static event TypedEventHandler> Saved;
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs
index ac6d652219..08b94380bb 100644
--- a/src/Umbraco.Core/Services/MemberService.cs
+++ b/src/Umbraco.Core/Services/MemberService.cs
@@ -19,26 +19,31 @@ namespace Umbraco.Core.Services
///
/// Represents the MemberService.
///
- internal class MemberService : IMemberService
+ public class MemberService : IMemberService
{
private readonly RepositoryFactory _repositoryFactory;
+ private readonly IMemberGroupService _memberGroupService;
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
- public MemberService(RepositoryFactory repositoryFactory)
- : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
+ public MemberService(RepositoryFactory repositoryFactory, IMemberGroupService memberGroupService)
+ : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory, memberGroupService)
{
}
- public MemberService(IDatabaseUnitOfWorkProvider provider)
- : this(provider, new RepositoryFactory())
+ public MemberService(IDatabaseUnitOfWorkProvider provider, IMemberGroupService memberGroupService)
+ : this(provider, new RepositoryFactory(), memberGroupService)
{
}
- public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory)
+ public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IMemberGroupService memberGroupService)
{
+ if (provider == null) throw new ArgumentNullException("provider");
+ if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
+ if (memberGroupService == null) throw new ArgumentNullException("memberGroupService");
_repositoryFactory = repositoryFactory;
+ _memberGroupService = memberGroupService;
_uowProvider = provider;
}
@@ -843,10 +848,11 @@ namespace Umbraco.Core.Services
{
var qry = new Query().Where(g => g.Name == roleName);
var found = repository.GetByQuery(qry).ToArray();
+
foreach (var memberGroup in found)
{
- repository.Delete(memberGroup);
- }
+ _memberGroupService.Delete(memberGroup);
+ }
return found.Any();
}
}
@@ -977,8 +983,7 @@ namespace Umbraco.Core.Services
}
#region Event Handlers
-
-
+
///
/// Occurs before Delete
///
@@ -998,7 +1003,7 @@ namespace Umbraco.Core.Services
/// Occurs after Save
///
public static event TypedEventHandler> Saved;
-
+
#endregion
/////
diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs
index 63f71bd5e2..276aedc1a5 100644
--- a/src/Umbraco.Core/Services/ServiceContext.cs
+++ b/src/Umbraco.Core/Services/ServiceContext.cs
@@ -28,6 +28,7 @@ namespace Umbraco.Core.Services
//private Lazy _sectionService;
//private Lazy _macroService;
private Lazy _memberTypeService;
+ private Lazy _memberGroupService;
private Lazy _notificationService;
///
@@ -45,6 +46,7 @@ namespace Umbraco.Core.Services
///
///
///
+ ///
public ServiceContext(
IContentService contentService,
IMediaService mediaService,
@@ -54,7 +56,8 @@ namespace Umbraco.Core.Services
ILocalizationService localizationService,
PackagingService packagingService,
IEntityService entityService,
- IRelationService relationService/*,
+ IRelationService relationService,
+ IMemberGroupService memberGroupService/*,
ISectionService sectionService,
IApplicationTreeService treeService*/)
{
@@ -67,6 +70,7 @@ namespace Umbraco.Core.Services
_packagingService = new Lazy(() => packagingService);
_entityService = new Lazy(() => entityService);
_relationService = new Lazy(() => relationService);
+ _memberGroupService = new Lazy(() => memberGroupService);
//_sectionService = new Lazy(() => sectionService);
//_treeService = new Lazy(() => treeService);
}
@@ -109,7 +113,7 @@ namespace Umbraco.Core.Services
_userService = new Lazy(() => new UserService(provider, repositoryFactory.Value));
if (_memberService == null)
- _memberService = new Lazy(() => new MemberService(provider, repositoryFactory.Value));
+ _memberService = new Lazy(() => new MemberService(provider, repositoryFactory.Value, _memberGroupService.Value));
if (_contentService == null)
_contentService = new Lazy(() => new ContentService(provider, repositoryFactory.Value, publishingStrategy));
@@ -149,6 +153,9 @@ namespace Umbraco.Core.Services
if (_memberTypeService == null)
_memberTypeService = new Lazy(() => new MemberTypeService(provider, repositoryFactory.Value, _memberService.Value));
+
+ if (_memberGroupService == null)
+ _memberGroupService = new Lazy(() => new MemberGroupService(provider, repositoryFactory.Value));
}
@@ -288,5 +295,13 @@ namespace Umbraco.Core.Services
get { return _memberTypeService.Value; }
}
+ ///
+ /// Gets the MemberGroupService
+ ///
+ public IMemberGroupService MemberGroupService
+ {
+ get { return _memberGroupService.Value; }
+ }
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 43a940a829..5682fd8ec0 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -774,6 +774,7 @@
+
@@ -786,6 +787,7 @@
+
diff --git a/src/Umbraco.Tests/MockTests.cs b/src/Umbraco.Tests/MockTests.cs
index ce049b9679..a3e387ad1e 100644
--- a/src/Umbraco.Tests/MockTests.cs
+++ b/src/Umbraco.Tests/MockTests.cs
@@ -47,7 +47,8 @@ namespace Umbraco.Tests
new RelationService(
new Mock().Object,
new RepositoryFactory(true),
- new Mock().Object)/*,
+ new Mock().Object),
+ new Mock().Object/*,
new Mock().Object,
new Mock().Object*/);
Assert.Pass();
@@ -66,26 +67,27 @@ namespace Umbraco.Tests
var appCtx = new ApplicationContext(
new DatabaseContext(new Mock().Object),
new ServiceContext(
- new Mock().Object,
- new Mock().Object,
- new Mock().Object,
- new Mock().Object,
- new Mock().Object,
- new Mock().Object,
- new PackagingService(
new Mock().Object,
- new Mock().Object,
new Mock().Object,
+ new Mock().Object,
new Mock().Object,
new Mock().Object,
new Mock().Object,
- new RepositoryFactory(true),
- new Mock().Object),
- new Mock().Object,
- new RelationService(
- new Mock().Object,
- new RepositoryFactory(true),
- new Mock().Object)),
+ new PackagingService(
+ new Mock().Object,
+ new Mock().Object,
+ new Mock().Object,
+ new Mock().Object,
+ new Mock().Object,
+ new Mock().Object,
+ new RepositoryFactory(true),
+ new Mock().Object),
+ new Mock().Object,
+ new RelationService(
+ new Mock().Object,
+ new RepositoryFactory(true),
+ new Mock().Object),
+ new Mock().Object),
CacheHelper.CreateDisabledCacheHelper());
Assert.Pass();
}
diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs
index 584091f1eb..3937dcb8c9 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/MemberRepositoryTest.cs
@@ -32,7 +32,7 @@ namespace Umbraco.Tests.Persistence.Repositories
private MemberRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out MemberTypeRepository memberTypeRepository, out MemberGroupRepository memberGroupRepository)
{
memberTypeRepository = new MemberTypeRepository(unitOfWork, NullCacheProvider.Current);
- memberGroupRepository = new MemberGroupRepository(unitOfWork, NullCacheProvider.Current);
+ memberGroupRepository = new MemberGroupRepository(unitOfWork, NullCacheProvider.Current, CacheHelper.CreateDisabledCacheHelper());
var repository = new MemberRepository(unitOfWork, NullCacheProvider.Current, memberTypeRepository, memberGroupRepository);
return repository;
}
diff --git a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
index ca2861ab5c..791617d8a6 100644
--- a/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
+++ b/src/Umbraco.Web/Cache/CacheRefresherEventHandler.cs
@@ -113,6 +113,8 @@ namespace Umbraco.Web.Cache
MemberService.Saved += MemberServiceSaved;
MemberService.Deleted += MemberServiceDeleted;
+ MemberGroupService.Saved += MemberGroupService_Saved;
+ MemberGroupService.Deleted += MemberGroupService_Deleted;
//Bind to media events
@@ -555,7 +557,7 @@ namespace Umbraco.Web.Cache
#region Member event handlers
- void MemberServiceDeleted(IMemberService sender, Core.Events.DeleteEventArgs e)
+ static void MemberServiceDeleted(IMemberService sender, Core.Events.DeleteEventArgs e)
{
foreach (var m in e.DeletedEntities.ToArray())
{
@@ -563,7 +565,7 @@ namespace Umbraco.Web.Cache
}
}
- void MemberServiceSaved(IMemberService sender, Core.Events.SaveEventArgs e)
+ static void MemberServiceSaved(IMemberService sender, Core.Events.SaveEventArgs e)
{
foreach (var m in e.SavedEntities.ToArray())
{
@@ -572,5 +574,24 @@ namespace Umbraco.Web.Cache
}
#endregion
+
+ #region Member group event handlers
+
+ static void MemberGroupService_Deleted(IMemberGroupService sender, Core.Events.DeleteEventArgs e)
+ {
+ foreach (var m in e.DeletedEntities.ToArray())
+ {
+ DistributedCache.Instance.RemoveMemberGroupCache(m.Id);
+ }
+ }
+
+ static void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs e)
+ {
+ foreach (var m in e.SavedEntities.ToArray())
+ {
+ DistributedCache.Instance.RemoveMemberGroupCache(m.Id);
+ }
+ }
+ #endregion
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs
index f07bc02b1d..e76a8f448a 100644
--- a/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs
+++ b/src/Umbraco.Web/Cache/ContentTypeCacheRefresher.cs
@@ -17,7 +17,7 @@ namespace Umbraco.Web.Cache
{
///
- /// A cache refresher to ensure content type cache is updated when members change
+ /// A cache refresher to ensure content type cache is updated when content types change - this is applicable to content, media and member types
///
///
/// This is not intended to be used directly in your code
diff --git a/src/Umbraco.Web/Cache/DistributedCache.cs b/src/Umbraco.Web/Cache/DistributedCache.cs
index 1f7307b289..b66dd2174a 100644
--- a/src/Umbraco.Web/Cache/DistributedCache.cs
+++ b/src/Umbraco.Web/Cache/DistributedCache.cs
@@ -40,6 +40,7 @@ namespace Umbraco.Web.Cache
public const string TemplateRefresherId = "DD12B6A0-14B9-46e8-8800-C154F74047C8";
public const string PageCacheRefresherId = "27AB3022-3DFA-47b6-9119-5945BC88FD66";
public const string MemberCacheRefresherId = "E285DF34-ACDC-4226-AE32-C0CB5CF388DA";
+ public const string MemberGroupCacheRefresherId = "187F236B-BD21-4C85-8A7C-29FBA3D6C00C";
public const string MediaCacheRefresherId = "B29286DD-2D40-4DDB-B325-681226589FEC";
public const string MacroCacheRefresherId = "7B1E683C-5F34-43dd-803D-9699EA1E98CA";
public const string UserCacheRefresherId = "E057AF6D-2EE6-41F4-8045-3694010F0AA6";
diff --git a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs
index a1339ec8cd..faede0bffc 100644
--- a/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs
+++ b/src/Umbraco.Web/Cache/DistributedCacheExtensions.cs
@@ -237,7 +237,7 @@ namespace Umbraco.Web.Cache
#region Member cache
///
- /// Refreshes the cache amongst servers for a member
+ /// Refreshes the cache among servers for a member
///
///
///
@@ -247,7 +247,7 @@ namespace Umbraco.Web.Cache
}
///
- /// Removes the cache amongst servers for a member
+ /// Removes the cache among servers for a member
///
///
///
@@ -258,6 +258,29 @@ namespace Umbraco.Web.Cache
#endregion
+ #region Member group cache
+ ///
+ /// Refreshes the cache among servers for a member group
+ ///
+ ///
+ ///
+ public static void RefreshMemberGroupCache(this DistributedCache dc, int memberGroupId)
+ {
+ dc.Refresh(new Guid(DistributedCache.MemberGroupCacheRefresherId), memberGroupId);
+ }
+
+ ///
+ /// Removes the cache among servers for a member group
+ ///
+ ///
+ ///
+ public static void RemoveMemberGroupCache(this DistributedCache dc, int memberGroupId)
+ {
+ dc.Remove(new Guid(DistributedCache.MemberGroupCacheRefresherId), memberGroupId);
+ }
+
+ #endregion
+
#region Media Cache
///
diff --git a/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs
new file mode 100644
index 0000000000..df1423ef1e
--- /dev/null
+++ b/src/Umbraco.Web/Cache/MemberGroupCacheRefresher.cs
@@ -0,0 +1,115 @@
+using System;
+using System.Linq;
+using System.Web.Script.Serialization;
+using Umbraco.Core;
+using Umbraco.Core.Cache;
+using Umbraco.Core.Models;
+using Umbraco.Core.Persistence.Caching;
+
+namespace Umbraco.Web.Cache
+{
+ public sealed class MemberGroupCacheRefresher : JsonCacheRefresherBase
+ {
+ #region Static helpers
+
+ ///
+ /// Converts the json to a JsonPayload object
+ ///
+ ///
+ ///
+ private static JsonPayload[] DeserializeFromJsonPayload(string json)
+ {
+ var serializer = new JavaScriptSerializer();
+ var jsonObject = serializer.Deserialize(json);
+ return jsonObject;
+ }
+
+ ///
+ /// Creates the custom Json payload used to refresh cache amongst the servers
+ ///
+ ///
+ ///
+ internal static string SerializeToJsonPayload(params IMemberGroup[] groups)
+ {
+ var serializer = new JavaScriptSerializer();
+ var items = groups.Select(FromMemberGroup).ToArray();
+ var json = serializer.Serialize(items);
+ return json;
+ }
+
+ ///
+ /// Converts a macro to a jsonPayload object
+ ///
+ ///
+ ///
+ private static JsonPayload FromMemberGroup(IMemberGroup group)
+ {
+ if (group == null) return null;
+
+ var payload = new JsonPayload
+ {
+ Id = group.Id,
+ Name = group.Name
+ };
+ return payload;
+ }
+
+ #endregion
+
+ #region Sub classes
+
+ private class JsonPayload
+ {
+ public string Name { get; set; }
+ public int Id { get; set; }
+ }
+
+ #endregion
+
+ protected override MemberGroupCacheRefresher Instance
+ {
+ get { return this; }
+ }
+
+ public override Guid UniqueIdentifier
+ {
+ get { return new Guid(DistributedCache.MemberGroupCacheRefresherId); }
+ }
+
+ public override string Name
+ {
+ get { return "Clears Member Group Cache"; }
+ }
+
+ public override void Refresh(string jsonPayload)
+ {
+ ClearCache(DeserializeFromJsonPayload(jsonPayload));
+ base.Refresh(jsonPayload);
+ }
+
+ public override void Refresh(int id)
+ {
+ ClearCache(FromMemberGroup(ApplicationContext.Current.Services.MemberGroupService.GetById(id)));
+ base.Refresh(id);
+ }
+
+ public override void Remove(int id)
+ {
+ ClearCache(FromMemberGroup(ApplicationContext.Current.Services.MemberGroupService.GetById(id)));
+ base.Remove(id);
+ }
+
+ private void ClearCache(params JsonPayload[] payloads)
+ {
+ if (payloads == null) return;
+
+ payloads.ForEach(payload =>
+ {
+ ApplicationContext.Current.ApplicationCache.RuntimeCache
+ .ClearCacheByKeySearch(string.Format("{0}.{1}", typeof(IMemberGroup).FullName, payload.Name));
+ RuntimeCacheProvider.Current.Delete(typeof(IMemberGroup), payload.Id);
+ });
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Strategies/PublicAccessEventHandler.cs b/src/Umbraco.Web/Strategies/PublicAccessEventHandler.cs
new file mode 100644
index 0000000000..86b3066413
--- /dev/null
+++ b/src/Umbraco.Web/Strategies/PublicAccessEventHandler.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using umbraco.cms.businesslogic.web;
+using Umbraco.Core;
+using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Services;
+
+namespace Umbraco.Web.Strategies
+{
+ ///
+ /// Used to ensure that the access.xml file is kept up to date properly
+ ///
+ public sealed class PublicAccessEventHandler : ApplicationEventHandler
+ {
+ protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
+ {
+ base.ApplicationStarted(umbracoApplication, applicationContext);
+
+ MemberGroupService.Saved += MemberGroupService_Saved;
+ }
+
+ static void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs e)
+ {
+ foreach (var grp in e.SavedEntities)
+ {
+ //check if the name has changed
+ if (grp.AdditionalData.ContainsKey("previousName")
+ && grp.AdditionalData["previousName"] != null
+ && grp.AdditionalData["previousName"].ToString().IsNullOrWhiteSpace() == false
+ && grp.AdditionalData["previousName"].ToString() != grp.Name)
+ {
+ Access.RenameMemberShipRole(grp.AdditionalData["previousName"].ToString(), grp.Name);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index aa21df2684..e343d61cd1 100644
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -283,6 +283,7 @@
+
@@ -396,6 +397,7 @@
+
diff --git a/src/umbraco.cms/businesslogic/CMSNode.cs b/src/umbraco.cms/businesslogic/CMSNode.cs
index c92f82ec95..4052d89cc4 100644
--- a/src/umbraco.cms/businesslogic/CMSNode.cs
+++ b/src/umbraco.cms/businesslogic/CMSNode.cs
@@ -420,6 +420,11 @@ namespace umbraco.cms.businesslogic
_entity = entity;
}
+ protected internal CMSNode(IEntity entity)
+ {
+ _id = entity.Id;
+ }
+
#endregion
#region Public Methods
@@ -1138,6 +1143,13 @@ order by level,sortOrder";
_entity = content;
}
+ internal protected void PopulateCMSNodeFromUmbracoEntity(IAggregateRoot content, Guid objectType)
+ {
+ _uniqueID = content.Key;
+ _nodeObjectType = objectType;
+ _createDate = content.CreateDate;
+ }
+
#endregion
#region Private Methods
diff --git a/src/umbraco.cms/businesslogic/member/MemberGroup.cs b/src/umbraco.cms/businesslogic/member/MemberGroup.cs
index 93494bbfb7..eab3dd4aea 100644
--- a/src/umbraco.cms/businesslogic/member/MemberGroup.cs
+++ b/src/umbraco.cms/businesslogic/member/MemberGroup.cs
@@ -1,5 +1,8 @@
using System;
using System.Data;
+using System.Linq;
+using Umbraco.Core.Models;
+using Umbraco.Core.Persistence.Querying;
using umbraco.DataLayer;
using System.Collections;
using umbraco.cms.businesslogic.web;
@@ -16,8 +19,15 @@ namespace umbraco.cms.businesslogic.member
///
public class MemberGroup : CMSNode
{
- private static Guid _objectType = new Guid(Constants.ObjectTypes.MemberGroup);
- private string _oldGroupName;
+ private static readonly Guid MemberGroupObjectType = new Guid(Constants.ObjectTypes.MemberGroup);
+
+ private IMemberGroup _memberGroupItem;
+
+ internal MemberGroup(IMemberGroup memberGroup)
+ : base(memberGroup)
+ {
+ _memberGroupItem = memberGroup;
+ }
///
/// Initialize a new object of the MemberGroup class
@@ -41,13 +51,11 @@ namespace umbraco.cms.businesslogic.member
{
get
{
- return base.Text;
+ return _memberGroupItem.Name;
}
set
{
- // in order to be able to update access.xml if name changes we need to store a reference to the old name
- _oldGroupName = Text;
- base.Text = value;
+ _memberGroupItem.Name = value;
}
}
@@ -57,17 +65,23 @@ namespace umbraco.cms.businesslogic.member
[Obsolete("Use System.Web.Security.Role.DeleteRole")]
public override void delete()
{
- DeleteEventArgs e = new DeleteEventArgs();
+ var e = new DeleteEventArgs();
FireBeforeDelete(e);
- if (!e.Cancel) {
- // delete member specific data!
- SqlHelper.ExecuteNonQuery("Delete from cmsMember2MemberGroup where memberGroup = @id",
- SqlHelper.CreateParameter("@id", Id));
+ if (e.Cancel) return;
- // Delete all content and cmsnode specific data!
- base.delete();
- FireAfterDelete(e);
+ if (_memberGroupItem != null)
+ {
+ ApplicationContext.Current.Services.MemberGroupService.Delete(_memberGroupItem);
}
+ else
+ {
+ var memberGroup = ApplicationContext.Current.Services.MemberGroupService.GetById(Id);
+ ApplicationContext.Current.Services.MemberGroupService.Delete(memberGroup);
+ }
+
+ // Delete all content and cmsnode specific data!
+ base.delete();
+ FireAfterDelete(e);
}
@@ -76,18 +90,13 @@ namespace umbraco.cms.businesslogic.member
///
public override void Save()
{
- SaveEventArgs e = new SaveEventArgs();
+ var e = new SaveEventArgs();
FireBeforeSave(e);
+ if (e.Cancel) return;
- // if the name has changed we need to update the public access
- if (_oldGroupName != Text)
- {
- Access.RenameMemberShipRole(_oldGroupName, Text);
- }
+ ApplicationContext.Current.Services.MemberGroupService.Save(_memberGroupItem);
- if (!e.Cancel) {
- FireAfterSave(e);
- }
+ FireAfterSave(e);
}
///
@@ -98,82 +107,51 @@ namespace umbraco.cms.businesslogic.member
{
get
{
- Guid[] tmp = getAllUniquesFromObjectType(_objectType);
- MemberGroup[] retval = new MemberGroup[tmp.Length];
-
- int i = 0;
- foreach(Guid g in tmp)
- {
- retval[i]= new MemberGroup(g);
- i++;
- }
- return retval;
+ var result = ApplicationContext.Current.Services.MemberGroupService.GetAll();
+ return result.Select(x => new MemberGroup(x)).ToArray();
}
}
- public int[] GetMembersAsIds() {
- ArrayList retval = new ArrayList();
- IRecordsReader dr = SqlHelper.ExecuteReader("select member from cmsMember2MemberGroup where memberGroup = @memberGroup",
- SqlHelper.CreateParameter("@memberGroup", Id));
- while (dr.Read()) {
- retval.Add(dr.GetInt("member"));
- }
- dr.Close();
+ public int[] GetMembersAsIds()
+ {
+ var result = ApplicationContext.Current.Services.MemberService.GetMembersInRole(_memberGroupItem.Name);
+ return result.Select(x => x.Id).ToArray();
+ }
- return (int[])retval.ToArray(typeof(int));
- }
+ [Obsolete("Use System.Web.Security.Roles.FindUsersInRole")]
+ public Member[] GetMembers()
+ {
+ var result = ApplicationContext.Current.Services.MemberService.GetMembersInRole(_memberGroupItem.Name);
+ return result.Select(x => new Member(x)).ToArray();
+ }
- [Obsolete("Use System.Web.Security.Roles.FindUsersInRole")]
- public Member[] GetMembers() {
- ArrayList retval = new ArrayList();
- IRecordsReader dr = SqlHelper.ExecuteReader("select member from cmsMember2MemberGroup where memberGroup = @memberGroup",
- SqlHelper.CreateParameter("@memberGroup", Id));
- while (dr.Read()) {
- retval.Add(new Member(dr.GetInt("member")));
- }
- dr.Close();
+ public Member[] GetMembers(string usernameToMatch)
+ {
- return (Member[])retval.ToArray(typeof(Member));
- }
+ var result = ApplicationContext.Current.Services.MemberService.FindMembersInRole(
+ _memberGroupItem.Name, usernameToMatch, StringPropertyMatchType.StartsWith);
- public Member[] GetMembers(string usernameToMatch) {
- ArrayList retval = new ArrayList();
- IRecordsReader dr = SqlHelper.ExecuteReader("select member from cmsMember2MemberGroup inner join cmsMember on cmsMember.nodeId = cmsMember2MemberGroup.member where loginName like @username and memberGroup = @memberGroup",
- SqlHelper.CreateParameter("@memberGroup", Id), SqlHelper.CreateParameter("@username", usernameToMatch + "%"));
- while (dr.Read()) {
- retval.Add(new Member(dr.GetInt("member")));
- }
- dr.Close();
+ return result.Select(x => new Member(x)).ToArray();
+ }
- return (Member[])retval.ToArray(typeof(Member));
- }
+ public bool HasMember(int memberId)
+ {
+ return SqlHelper.ExecuteScalar("select count(member) from cmsMember2MemberGroup where member = @member and memberGroup = @memberGroup",
+ SqlHelper.CreateParameter("@member", memberId),
+ SqlHelper.CreateParameter("@memberGroup", Id)) > 0;
+ }
- public bool HasMember(int memberId) {
- return SqlHelper.ExecuteScalar("select count(member) from cmsMember2MemberGroup where member = @member and memberGroup = @memberGroup",
- SqlHelper.CreateParameter("@member", memberId),
- SqlHelper.CreateParameter("@memberGroup", Id)) > 0;
- }
-
- ///
+ ///
/// Get a membergroup by it's name
///
/// Name of the membergroup
/// If a MemberGroup with the given name exists, it will return this, else: null
- public static MemberGroup GetByName(string name)
- {
- try
- {
- return
- new MemberGroup(SqlHelper.ExecuteScalar(
- "select id from umbracoNode where Text = @text and nodeObjectType = @objectType",
- SqlHelper.CreateParameter("@text", name),
- SqlHelper.CreateParameter("@objectType", _objectType)));
- }
- catch
- {
- return null;
- }
- }
+ public static MemberGroup GetByName(string name)
+ {
+ var found = ApplicationContext.Current.Services.MemberGroupService.GetByName(name);
+ if (found == null) return null;
+ return new MemberGroup(found);
+ }
///
@@ -184,15 +162,40 @@ namespace umbraco.cms.businesslogic.member
/// The new MemberGroup
public static MemberGroup MakeNew(string Name, BusinessLogic.User u)
{
- Guid newId = Guid.NewGuid();
- CMSNode.MakeNew(-1,_objectType, u.Id, 1, Name, newId);
- MemberGroup mg = new MemberGroup(newId);
- NewEventArgs e = new NewEventArgs();
+ var group = new global::Umbraco.Core.Models.MemberGroup {Name = Name};
+ ApplicationContext.Current.Services.MemberGroupService.Save(group);
+
+ var mg = new MemberGroup(group);
+ var e = new NewEventArgs();
mg.OnNew(e);
return mg;
}
- //EVENTS
+ protected override void setupNode()
+ {
+ if (Id == -1)
+ {
+ base.setupNode();
+ return;
+ }
+
+ var group = ApplicationContext.Current.Services.MemberGroupService.GetById(Id);
+
+ if (group == null)
+ throw new ArgumentException(string.Format("No Member exists with id '{0}'", Id));
+
+ SetupNode(group);
+ }
+
+ private void SetupNode(IMemberGroup group)
+ {
+ _memberGroupItem = group;
+
+ //Setting private properties
+ base.PopulateCMSNodeFromUmbracoEntity(_memberGroupItem, MemberGroupObjectType);
+ }
+
+ //EVENTS
///
/// The save event handler
///