diff --git a/src/Umbraco.Core/Models/Membership/IUser.cs b/src/Umbraco.Core/Models/Membership/IUser.cs index 005720007d..ed4c624bbd 100644 --- a/src/Umbraco.Core/Models/Membership/IUser.cs +++ b/src/Umbraco.Core/Models/Membership/IUser.cs @@ -19,5 +19,9 @@ namespace Umbraco.Core.Models.Membership bool NoConsole { get; set; } IUserType UserType { get; } string Permissions { get; set; } + + IEnumerable UserSections { get; } + void RemoveUserSection(string sectionAlias); + void AddUserSection(string sectionAlias); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 95c81abdc7..397ad2e7e2 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -19,10 +19,12 @@ namespace Umbraco.Core.Models.Membership internal class User : UserProfile, IUser { private bool _hasIdentity; + private readonly UserSectionCollection _sectionCollection; public User(IUserType userType) { Groups = new List {userType}; + _sectionCollection = new UserSectionCollection(); } #region Implementation of IEntity @@ -92,6 +94,23 @@ namespace Umbraco.Core.Models.Membership public string Language { get; set; } [DataMember] public string Permissions { get; set; } + + public IEnumerable UserSections + { + get { return _sectionCollection; } + } + + public void RemoveUserSection(string sectionAlias) + { + //NOTE: we're casting to int here but might have to change that in the future. + _sectionCollection.Remove(new Tuple((int) Id, sectionAlias)); + } + + public void AddUserSection(string sectionAlias) + { + _sectionCollection.Add(new UserSection(this, sectionAlias)); + } + [DataMember] public bool DefaultToLiveEditing { get; set; } [DataMember] diff --git a/src/Umbraco.Core/Models/UserSection.cs b/src/Umbraco.Core/Models/UserSection.cs index dd3f27b817..5ba7e2bb0d 100644 --- a/src/Umbraco.Core/Models/UserSection.cs +++ b/src/Umbraco.Core/Models/UserSection.cs @@ -1,43 +1,97 @@ using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.Reflection; using System.Runtime.Serialization; using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Models.Membership; namespace Umbraco.Core.Models { + + internal class UserSectionCollection : KeyedCollection, UserSection>, INotifyCollectionChanged + { + protected override Tuple GetKeyForItem(UserSection item) + { + return new Tuple(item.UserId, item.SectionAlias); + } + + public event NotifyCollectionChangedEventHandler CollectionChanged; + } + /// /// Represents an allowed section for a user /// [Serializable] [DataContract(IsReference = true)] - internal class UserSection : IAggregateRoot + internal class UserSection : TracksChangesEntityBase { - private int? _userId; - private bool _hasIdentity; - - [DataMember] - public string SectionAlias { get; set; } - - //NOTE: WE cannot implement these as the columns don't exist in the db. - [IgnoreDataMember] - Guid IEntity.Key { get; set; } - [IgnoreDataMember] - DateTime IEntity.CreateDate { get; set; } - [IgnoreDataMember] - DateTime IEntity.UpdateDate { get; set; } - - [IgnoreDataMember] - public bool HasIdentity { get { return _userId != null || _hasIdentity; } } - - public int Id + public UserSection(IUser user, string sectionAlias) { - get - { - return _userId.HasValue ? _userId.Value : -1; - } + Mandate.ParameterNotNull(user, "user"); + Mandate.ParameterNotNullOrEmpty(sectionAlias, "sectionAlias"); + _userId = user.Id; + _sectionAlias = sectionAlias; + } + + private string _sectionAlias; + private object _userId; + + private static readonly PropertyInfo SectionSelector = ExpressionHelper.GetPropertyInfo(x => x.SectionAlias); + private static readonly PropertyInfo UserIdSelector = ExpressionHelper.GetPropertyInfo(x => x.UserId); + + /// + /// Gets or sets the section alias + /// + [DataMember] + public object UserId + { + get { return _userId; } set { - _userId = value; - _hasIdentity = true; + SetPropertyValueAndDetectChanges(o => + { + _userId = value; + return _userId; + }, _userId, UserIdSelector); + } + } + + /// + /// Gets or sets the section alias + /// + [DataMember] + public string SectionAlias + { + get { return _sectionAlias; } + set + { + SetPropertyValueAndDetectChanges(o => + { + _sectionAlias = value; + return _sectionAlias; + }, _sectionAlias, SectionSelector); + } + } + + protected bool Equals(UserSection other) + { + return string.Equals(_sectionAlias, other._sectionAlias) && _userId.Equals(other._userId); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((UserSection) obj); + } + + public override int GetHashCode() + { + unchecked + { + return (_sectionAlias.GetHashCode()*397) ^ _userId.GetHashCode(); } } } diff --git a/src/Umbraco.Core/Persistence/Factories/UserSectionFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserSectionFactory.cs index 12e3d1f9d7..38a02cab38 100644 --- a/src/Umbraco.Core/Persistence/Factories/UserSectionFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UserSectionFactory.cs @@ -27,11 +27,11 @@ namespace Umbraco.Core.Persistence.Factories internal static void ConfigureMappings(IConfiguration config) { config.CreateMap() - .ForMember(section => section.Id, expression => expression.MapFrom(dto => dto.UserId)) + .ForMember(section => section.UserId, expression => expression.MapFrom(dto => dto.UserId)) .ForMember(section => section.SectionAlias, expression => expression.MapFrom(dto => dto.AppAlias)); config.CreateMap() - .ForMember(dto => dto.UserId, expression => expression.MapFrom(section => section.Id)) + .ForMember(dto => dto.UserId, expression => expression.MapFrom(section => section.UserId)) .ForMember(dto => dto.AppAlias, expression => expression.MapFrom(section => section.SectionAlias)); } } diff --git a/src/Umbraco.Core/Persistence/Mappers/UserSectionMapper.cs b/src/Umbraco.Core/Persistence/Mappers/UserSectionMapper.cs index 9256803f0d..9df358a8b6 100644 --- a/src/Umbraco.Core/Persistence/Mappers/UserSectionMapper.cs +++ b/src/Umbraco.Core/Persistence/Mappers/UserSectionMapper.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.Persistence.Mappers internal override void BuildMap() { - CacheMap(src => src.Id, dto => dto.UserId); + CacheMap(src => src.UserId, dto => dto.UserId); CacheMap(src => src.SectionAlias, dto => dto.AppAlias); } diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs index 9cea6ce7bc..c32f1b33a6 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IRepositoryQueryable.cs @@ -9,8 +9,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Type of entity for which the repository is used /// Type of the Id used for this entity - public interface IRepositoryQueryable : IRepository - where TEntity : IAggregateRoot + public interface IRepositoryQueryable : IRepository { /// /// Gets all entities of the specified type and query diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserSectionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserSectionRepository.cs deleted file mode 100644 index 8acd59895f..0000000000 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IUserSectionRepository.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using Umbraco.Core.Models; - -namespace Umbraco.Core.Persistence.Repositories -{ - internal interface IUserSectionRepository : IRepository, UserSection> - { - - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index c7c5b236e6..2832ed73c6 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Persistence.Repositories { + /// /// Represent an abstract Repository, which is the base of the Repository implementations /// diff --git a/src/Umbraco.Core/Persistence/Repositories/UserSectionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UserSectionRepository.cs deleted file mode 100644 index f0b90cc566..0000000000 --- a/src/Umbraco.Core/Persistence/Repositories/UserSectionRepository.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Models; -using Umbraco.Core.Models.EntityBase; -using Umbraco.Core.Models.Rdbms; -using Umbraco.Core.Persistence.Caching; -using Umbraco.Core.Persistence.Factories; -using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Persistence.UnitOfWork; - -namespace Umbraco.Core.Persistence.Repositories -{ - internal class UserSectionRepository : PetaPocoRepositoryBase, UserSection>, IUserSectionRepository, IUnitOfWorkRepository - { - public UserSectionRepository(IDatabaseUnitOfWork work) : base(work) - { - } - - public UserSectionRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache) : base(work, cache) - { - } - - protected override UserSection PerformGet(Tuple id) - { - var sql = GetBaseQuery(false); - sql.Where(GetBaseWhereClause(), new { Id = id }); - var dto = Database.First(sql); - if (dto == null) - return null; - var factory = new UserSectionFactory(); - var entity = factory.BuildEntity(dto); - return entity; - } - - protected override IEnumerable PerformGetAll(params Tuple[] ids) - { - if (ids.Any()) - { - foreach (var id in ids) - { - yield return Get(id); - } - } - else - { - var factory = new UserSectionFactory(); - foreach (var u in Database.Fetch("WHERE user > 0") - .Select(factory.BuildEntity)) - { - yield return u; - } - } - } - - protected override IEnumerable PerformGetByQuery(IQuery query) - { - var sqlClause = GetBaseQuery(false); - var translator = new SqlTranslator(sqlClause, query); - var sql = translator.Translate(); - - var dtos = Database.Fetch(sql); - - return dtos.Select(dto => Get( - new Tuple(dto.UserId, dto.AppAlias))); - } - - protected override Sql GetBaseQuery(bool isCount) - { - var sql = new Sql(); - sql.Select(isCount ? "COUNT(*)" : "*") - .From(); - return sql; - } - - protected override string GetBaseWhereClause() - { - return "user = @Id"; - } - - protected override IEnumerable GetDeleteClauses() - { - var list = new List - { - "DELETE FROM umbracoUser2app WHERE user = @Id AND app = @Section" - }; - return list; - } - - protected override Guid NodeObjectTypeId - { - get { throw new NotImplementedException(); } - } - - protected override void PersistNewItem(UserSection entity) - { - var factory = new UserSectionFactory(); - var dto = factory.BuildDto(entity); - - var id = Convert.ToInt32(Database.Insert(dto)); - entity.Id = id; - } - - protected override void PersistUpdatedItem(UserSection entity) - { - var factory = new UserSectionFactory(); - var dto = factory.BuildDto(entity); - Database.Update(dto); - } - - protected override void PersistDeletedItem(UserSection entity) - { - var deletes = GetDeleteClauses(); - foreach (var delete in deletes) - { - //ensure that we include SectionAlias since its a composite key - Database.Execute(delete, new { Id = entity.Id, Section = entity.SectionAlias }); - } - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs index 034b375ef4..38189576a7 100644 --- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs +++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs @@ -69,14 +69,6 @@ namespace Umbraco.Core.Persistence CreateLanguageRepository(uow)); } - internal virtual IUserSectionRepository CreateUserSectionRepository(IDatabaseUnitOfWork uow) - { - return new UserSectionRepository( - uow, - //Null cache here? I dunno? - NullCacheProvider.Current); - } - public virtual ILanguageRepository CreateLanguageRepository(IDatabaseUnitOfWork uow) { return new LanguageRepository( diff --git a/src/Umbraco.Core/Services/SectionService.cs b/src/Umbraco.Core/Services/SectionService.cs index 2a895eab0a..0196f2d742 100644 --- a/src/Umbraco.Core/Services/SectionService.cs +++ b/src/Umbraco.Core/Services/SectionService.cs @@ -132,10 +132,12 @@ namespace Umbraco.Core.Services var allApps = GetSections(); var apps = new List
(); - using (var repository = _repositoryFactory.CreateUserSectionRepository(_uowProvider.GetUnitOfWork())) - { - return repository.Get(id); - } + //TODO: Sort this out + + //using (var repository = _repositoryFactory.CreateUserSectionRepository(_uowProvider.GetUnitOfWork())) + //{ + // return repository.Get(id); + //} //using (IRecordsReader appIcons = SqlHelper.ExecuteReader("select app from umbracoUser2app where [user] = @userID", SqlHelper.CreateParameter("@userID", this.Id))) //{ diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 42054baf8e..2ee2701d95 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -507,7 +507,6 @@ - @@ -521,7 +520,6 @@ - @@ -697,7 +695,6 @@ - @@ -727,6 +724,7 @@ +