PageRenderTime 61ms CodeModel.GetById 2ms app.highlight 50ms RepoModel.GetById 1ms app.codeStats 1ms

/src/Umbraco.Core/Services/MemberService.cs

https://github.com/ekolicic/Umbraco-CMS
C# | 1258 lines | 893 code | 139 blank | 226 comment | 86 complexity | 5368dd5e2ed2e1488f4b34523a56466e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1using System;
   2using System.Collections.Generic;
   3using System.Runtime.CompilerServices;
   4using System.Threading;
   5using System.Web.Security;
   6using System.Xml.Linq;
   7using System.Xml.Linq;
   8using Umbraco.Core.Auditing;
   9using Umbraco.Core.Configuration;
  10using Umbraco.Core.Events;
  11using Umbraco.Core.Events;
  12using Umbraco.Core.Models;
  13using Umbraco.Core.Models.EntityBase;
  14using Umbraco.Core.Models.Membership;
  15using Umbraco.Core.Models.Rdbms;
  16using Umbraco.Core.Persistence;
  17using Umbraco.Core.Persistence.Querying;
  18using Umbraco.Core.Persistence.Repositories;
  19using Umbraco.Core.Persistence.SqlSyntax;
  20using Umbraco.Core.Persistence.UnitOfWork;
  21using System.Linq;
  22using Umbraco.Core.Security;
  23
  24namespace Umbraco.Core.Services
  25{
  26
  27    /// <summary>
  28    /// Represents the MemberService.
  29    /// </summary>
  30    public class MemberService : IMemberService
  31    {
  32        private readonly RepositoryFactory _repositoryFactory;
  33        private readonly IMemberGroupService _memberGroupService;
  34        private readonly IDatabaseUnitOfWorkProvider _uowProvider;
  35        private readonly EntityXmlSerializer _entitySerializer = new EntityXmlSerializer();
  36        private readonly IDataTypeService _dataTypeService;
  37        private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
  38
  39        public MemberService(RepositoryFactory repositoryFactory, IMemberGroupService memberGroupService)
  40            : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory, memberGroupService)
  41        {
  42        }
  43
  44        public MemberService(IDatabaseUnitOfWorkProvider provider, IMemberGroupService memberGroupService)
  45            : this(provider, new RepositoryFactory(), memberGroupService)
  46        {
  47        }
  48
  49        public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IMemberGroupService memberGroupService)
  50        {
  51            if (provider == null) throw new ArgumentNullException("provider");
  52            if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
  53            if (memberGroupService == null) throw new ArgumentNullException("memberGroupService");
  54            _repositoryFactory = repositoryFactory;
  55            _memberGroupService = memberGroupService;
  56            _uowProvider = provider;
  57            _dataTypeService = new DataTypeService(provider, repositoryFactory);
  58        }
  59
  60        public MemberService(IDatabaseUnitOfWorkProvider provider, IMemberGroupService memberGroupService, IDataTypeService dataTypeService)
  61            : this(provider, new RepositoryFactory(), memberGroupService, dataTypeService)
  62        {
  63
  64        }
  65
  66        public MemberService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IMemberGroupService memberGroupService, IDataTypeService dataTypeService)
  67        {
  68            if (provider == null) throw new ArgumentNullException("provider");
  69            if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
  70            if (memberGroupService == null) throw new ArgumentNullException("memberGroupService");
  71            _repositoryFactory = repositoryFactory;
  72            _memberGroupService = memberGroupService;
  73            _uowProvider = provider;
  74            _dataTypeService = dataTypeService;
  75        }
  76
  77        #region IMemberService Implementation
  78
  79        /// <summary>
  80        /// Get the default member type from the database - first check if the type "Member" is there, if not choose the first one found
  81        /// </summary>
  82        /// <returns></returns>
  83        public string GetDefaultMemberType()
  84        {
  85            using (var repository = _repositoryFactory.CreateMemberTypeRepository(_uowProvider.GetUnitOfWork()))
  86            {
  87                var types = repository.GetAll().Select(x => x.Alias).ToArray();
  88
  89                if (types.Any() == false)
  90                {
  91                    throw new InvalidOperationException("No member types could be resolved");
  92                }
  93
  94                if (types.InvariantContains("Member"))
  95                {
  96                    return types.First(x => x.InvariantEquals("Member"));
  97                }
  98
  99                return types.First();
 100            }
 101        }
 102
 103        /// <summary>
 104        /// Checks if a member with the username exists
 105        /// </summary>
 106        /// <param name="username"></param>
 107        /// <returns></returns>
 108        public bool Exists(string username)
 109        {
 110            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 111            {
 112                return repository.Exists(username);
 113            }
 114        }
 115
 116        /// <summary>
 117        /// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method
 118        /// </summary>
 119        /// <param name="member">The member to save the password for</param>
 120        /// <param name="password"></param>
 121        /// <remarks>
 122        /// This method exists so that Umbraco developers can use one entry point to create/update members if they choose to.
 123        /// </remarks>
 124        public void SavePassword(IMember member, string password)
 125        {
 126            if (member == null) throw new ArgumentNullException("member");
 127
 128            var provider = MembershipProviderExtensions.GetMembersMembershipProvider();
 129            if (provider.IsUmbracoMembershipProvider())
 130            {
 131                provider.ChangePassword(member.Username, "", password);
 132            }
 133            else
 134            {
 135                throw new NotSupportedException("When using a non-Umbraco membership provider you must change the member password by using the MembershipProvider.ChangePassword method");
 136            }
 137
 138            //go re-fetch the member and update the properties that may have changed
 139            var result = GetByUsername(member.Username);
 140            
 141            //should never be null but it could have been deleted by another thread.
 142            if (result == null) 
 143                return;
 144            
 145            member.RawPasswordValue = result.RawPasswordValue;
 146            member.LastPasswordChangeDate = result.LastPasswordChangeDate;
 147            member.UpdateDate = member.UpdateDate;
 148        }
 149
 150        /// <summary>
 151        /// Checks if a member with the id exists
 152        /// </summary>
 153        /// <param name="id"></param>
 154        /// <returns></returns>
 155        public bool Exists(int id)
 156        {
 157            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 158            {
 159                return repository.Exists(id);
 160            }
 161        }
 162
 163        /// <summary>
 164        /// Gets a Member by its integer Id
 165        /// </summary>
 166        /// <param name="id"></param>
 167        /// <returns></returns>
 168        public IMember GetById(int id)
 169        {
 170            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 171            {
 172                return repository.Get(id);
 173            }
 174        }
 175
 176        /// <summary>
 177        /// Gets a Member by its Guid key
 178        /// </summary>
 179        /// <remarks>
 180        /// The guid key corresponds to the unique id in the database
 181        /// and the user id in the membership provider.
 182        /// </remarks>
 183        /// <param name="id"></param>
 184        /// <returns></returns>
 185        public IMember GetByKey(Guid id)
 186        {
 187            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 188            {
 189                var query = Query<IMember>.Builder.Where(x => x.Key == id);
 190                var member = repository.GetByQuery(query).FirstOrDefault();
 191                return member;
 192            }
 193        }
 194
 195        /// <summary>
 196        /// Gets a list of Members by their MemberType
 197        /// </summary>
 198        /// <param name="memberTypeAlias"></param>
 199        /// <returns></returns>
 200        public IEnumerable<IMember> GetMembersByMemberType(string memberTypeAlias)
 201        {
 202            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 203            {
 204                var query = Query<IMember>.Builder.Where(x => x.ContentTypeAlias == memberTypeAlias);
 205                var members = repository.GetByQuery(query);
 206                return members;
 207            }
 208        }
 209
 210        /// <summary>
 211        /// Gets a list of Members by their MemberType
 212        /// </summary>
 213        /// <param name="memberTypeId"></param>
 214        /// <returns></returns>
 215        public IEnumerable<IMember> GetMembersByMemberType(int memberTypeId)
 216        {
 217            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 218            {
 219                repository.Get(memberTypeId);
 220                var query = Query<IMember>.Builder.Where(x => x.ContentTypeId == memberTypeId);
 221                var members = repository.GetByQuery(query);
 222                return members;
 223            }
 224        }
 225
 226        /// <summary>
 227        /// Gets a list of Members by the MemberGroup they are part of
 228        /// </summary>
 229        /// <param name="memberGroupName"></param>
 230        /// <returns></returns>
 231        public IEnumerable<IMember> GetMembersByGroup(string memberGroupName)
 232        {
 233            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 234            {
 235                return repository.GetByMemberGroup(memberGroupName);
 236            }
 237        }
 238
 239        /// <summary>
 240        /// Gets a list of all Members
 241        /// </summary>
 242        /// <param name="ids"></param>
 243        /// <returns></returns>
 244        public IEnumerable<IMember> GetAllMembers(params int[] ids)
 245        {
 246            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 247            {
 248                return repository.GetAll(ids);
 249            }
 250        }
 251
 252        public void DeleteMembersOfType(int memberTypeId)
 253        {
 254            using (new WriteLock(Locker))
 255            {
 256                using (var uow = _uowProvider.GetUnitOfWork())
 257                {
 258                    var repository = _repositoryFactory.CreateMemberRepository(uow);
 259                    //TODO: What about content that has the contenttype as part of its composition?
 260                    var query = Query<IMember>.Builder.Where(x => x.ContentTypeId == memberTypeId);
 261                    var members = repository.GetByQuery(query).ToArray();
 262
 263                    if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMember>(members), this))
 264                        return;
 265
 266                    foreach (var member in members)
 267                    {
 268                        //Permantly delete the member
 269                        Delete(member);
 270                    }
 271                }
 272            }
 273        }
 274
 275        public IEnumerable<IMember> FindMembersByDisplayName(string displayNameToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
 276        {
 277            var uow = _uowProvider.GetUnitOfWork();
 278            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 279            {
 280                var sql = new Sql()
 281                    .Select("*")
 282                    .From<NodeDto>()
 283                    .Where<NodeDto>(dto => dto.NodeObjectType == new Guid(Constants.ObjectTypes.Member));
 284                
 285                switch (matchType)
 286                {
 287                    case StringPropertyMatchType.Exact:
 288                        sql.Where<NodeDto>(dto => dto.Text.Equals(displayNameToMatch));
 289                        break;
 290                    case StringPropertyMatchType.Contains:
 291                        sql.Where<NodeDto>(dto => dto.Text.Contains(displayNameToMatch));                        
 292                        break;
 293                    case StringPropertyMatchType.StartsWith:
 294                        sql.Where<NodeDto>(dto => dto.Text.StartsWith(displayNameToMatch));
 295                        break;
 296                    case StringPropertyMatchType.EndsWith:
 297                        sql.Where<NodeDto>(dto => dto.Text.EndsWith(displayNameToMatch));
 298                        break;
 299                    case StringPropertyMatchType.Wildcard:
 300                        sql.Where<NodeDto>(dto => dto.Text.SqlWildcard(displayNameToMatch, TextColumnType.NVarchar));                        
 301                        break;
 302                    default:
 303                        throw new ArgumentOutOfRangeException("matchType");
 304                }
 305
 306                sql.OrderBy<NodeDto>(dto => dto.Text);
 307
 308                var result = repository.GetPagedResultsByQuery<NodeDto>(sql, pageIndex, pageSize, out totalRecords,
 309                    dtos => dtos.Select(x => x.NodeId).ToArray());
 310
 311                //ensure this result is sorted correct just in case
 312                return result.OrderBy(x => x.Name);
 313            }
 314        }
 315
 316        /// <summary>
 317        /// Does a search for members that contain the specified string in their email address
 318        /// </summary>
 319        /// <param name="emailStringToMatch"></param>
 320        /// <param name="totalRecords"></param>
 321        /// <param name="matchType"></param>
 322        /// <param name="pageIndex"></param>
 323        /// <param name="pageSize"></param>
 324        /// <returns></returns>
 325        public IEnumerable<IMember> FindByEmail(string emailStringToMatch, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
 326        {
 327            var uow = _uowProvider.GetUnitOfWork();
 328            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 329            {
 330                var query = new Query<IMember>();
 331
 332                switch (matchType)
 333                {
 334                    case StringPropertyMatchType.Exact:
 335                        query.Where(member => member.Email.Equals(emailStringToMatch));
 336                        break;
 337                    case StringPropertyMatchType.Contains:
 338                        query.Where(member => member.Email.Contains(emailStringToMatch));
 339                        break;
 340                    case StringPropertyMatchType.StartsWith:
 341                        query.Where(member => member.Email.StartsWith(emailStringToMatch));
 342                        break;
 343                    case StringPropertyMatchType.EndsWith:
 344                        query.Where(member => member.Email.EndsWith(emailStringToMatch));
 345                        break;
 346                    case StringPropertyMatchType.Wildcard:
 347                        query.Where(member => member.Email.SqlWildcard(emailStringToMatch, TextColumnType.NVarchar));
 348                        break;
 349                    default:
 350                        throw new ArgumentOutOfRangeException("matchType");
 351                }
 352
 353                return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, dto => dto.Email);
 354            }
 355        }
 356
 357        public IEnumerable<IMember> FindByUsername(string login, int pageIndex, int pageSize, out int totalRecords, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
 358        {
 359            var uow = _uowProvider.GetUnitOfWork();
 360            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 361            {
 362                var query = new Query<IMember>();
 363
 364                switch (matchType)
 365                {
 366                    case StringPropertyMatchType.Exact:
 367                        query.Where(member => member.Username.Equals(login));
 368                        break;
 369                    case StringPropertyMatchType.Contains:
 370                        query.Where(member => member.Username.Contains(login));
 371                        break;
 372                    case StringPropertyMatchType.StartsWith:
 373                        query.Where(member => member.Username.StartsWith(login));
 374                        break;
 375                    case StringPropertyMatchType.EndsWith:
 376                        query.Where(member => member.Username.EndsWith(login));
 377                        break;
 378                    case StringPropertyMatchType.Wildcard:
 379                        query.Where(member => member.Email.SqlWildcard(login, TextColumnType.NVarchar));
 380                        break;
 381                    default:
 382                        throw new ArgumentOutOfRangeException("matchType");
 383                }
 384
 385                return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, dto => dto.Username);
 386            }
 387        }
 388
 389        /// <summary>
 390        /// Gets a list of Members with a certain string property value
 391        /// </summary>
 392        /// <param name="propertyTypeAlias"></param>
 393        /// <param name="value"></param>
 394        /// <param name="matchType"></param>
 395        /// <returns></returns>
 396        public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, string value, StringPropertyMatchType matchType = StringPropertyMatchType.Exact)
 397        {
 398            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 399            {
 400                IQuery<IMember> query;
 401
 402                switch (matchType)
 403                {
 404                    case StringPropertyMatchType.Exact:
 405                        query =
 406                            Query<IMember>.Builder.Where(
 407                                x =>
 408                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 409                                (((Member)x).LongStringPropertyValue.SqlEquals(value, TextColumnType.NText) ||
 410                                 ((Member)x).ShortStringPropertyValue.SqlEquals(value, TextColumnType.NVarchar)));
 411                        break;
 412                    case StringPropertyMatchType.Contains:
 413                        query =
 414                            Query<IMember>.Builder.Where(
 415                                x =>
 416                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 417                                (((Member)x).LongStringPropertyValue.SqlContains(value, TextColumnType.NText) ||
 418                                 ((Member)x).ShortStringPropertyValue.SqlContains(value, TextColumnType.NVarchar)));
 419                        break;
 420                    case StringPropertyMatchType.StartsWith:
 421                        query =
 422                            Query<IMember>.Builder.Where(
 423                                x =>
 424                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 425                                (((Member)x).LongStringPropertyValue.SqlStartsWith(value, TextColumnType.NText) ||
 426                                 ((Member)x).ShortStringPropertyValue.SqlStartsWith(value, TextColumnType.NVarchar)));
 427                        break;
 428                    case StringPropertyMatchType.EndsWith:
 429                        query =
 430                            Query<IMember>.Builder.Where(
 431                                x =>
 432                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 433                                (((Member)x).LongStringPropertyValue.SqlEndsWith(value, TextColumnType.NText) ||
 434                                 ((Member)x).ShortStringPropertyValue.SqlEndsWith(value, TextColumnType.NVarchar)));
 435                        break;
 436                    default:
 437                        throw new ArgumentOutOfRangeException("matchType");
 438                }
 439
 440                var members = repository.GetByQuery(query);
 441                return members;
 442            }
 443        }
 444
 445        /// <summary>
 446        /// Gets a list of Members with a certain integer property value
 447        /// </summary>
 448        /// <param name="propertyTypeAlias"></param>
 449        /// <param name="value"></param>
 450        /// <param name="matchType"></param>
 451        /// <returns></returns>
 452        public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, int value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact)
 453        {
 454            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 455            {
 456                IQuery<IMember> query;
 457
 458                switch (matchType)
 459                {
 460                    case ValuePropertyMatchType.Exact:
 461                        query =
 462                            Query<IMember>.Builder.Where(
 463                                x =>
 464                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 465                                ((Member)x).IntegerropertyValue == value);
 466                        break;
 467                    case ValuePropertyMatchType.GreaterThan:
 468                        query =
 469                            Query<IMember>.Builder.Where(
 470                                x =>
 471                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 472                                ((Member)x).IntegerropertyValue > value);
 473                        break;
 474                    case ValuePropertyMatchType.LessThan:
 475                        query =
 476                            Query<IMember>.Builder.Where(
 477                                x =>
 478                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 479                                ((Member)x).IntegerropertyValue < value);
 480                        break;
 481                    case ValuePropertyMatchType.GreaterThanOrEqualTo:
 482                        query =
 483                            Query<IMember>.Builder.Where(
 484                                x =>
 485                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 486                                ((Member)x).IntegerropertyValue >= value);
 487                        break;
 488                    case ValuePropertyMatchType.LessThanOrEqualTo:
 489                        query =
 490                            Query<IMember>.Builder.Where(
 491                                x =>
 492                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 493                                ((Member)x).IntegerropertyValue <= value);
 494                        break;
 495                    default:
 496                        throw new ArgumentOutOfRangeException("matchType");
 497                }
 498
 499                var members = repository.GetByQuery(query);
 500                return members;
 501            }
 502        }
 503
 504        /// <summary>
 505        /// Gets a list of Members with a certain boolean property value
 506        /// </summary>
 507        /// <param name="propertyTypeAlias"></param>
 508        /// <param name="value"></param>
 509        /// <returns></returns>
 510        public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, bool value)
 511        {
 512            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 513            {
 514                var query =
 515                    Query<IMember>.Builder.Where(
 516                        x =>
 517                            ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 518                            ((Member)x).BoolPropertyValue == value);
 519
 520                var members = repository.GetByQuery(query);
 521                return members;
 522            }
 523        }
 524
 525        /// <summary>
 526        /// Gets a list of Members with a certain date time property value
 527        /// </summary>
 528        /// <param name="propertyTypeAlias"></param>
 529        /// <param name="value"></param>
 530        /// <param name="matchType"></param>
 531        /// <returns></returns>
 532        public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value, ValuePropertyMatchType matchType = ValuePropertyMatchType.Exact)
 533        {
 534            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 535            {
 536                IQuery<IMember> query;
 537
 538                switch (matchType)
 539                {
 540                    case ValuePropertyMatchType.Exact:
 541                        query =
 542                            Query<IMember>.Builder.Where(
 543                                x =>
 544                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 545                                ((Member)x).DateTimePropertyValue == value);
 546                        break;
 547                    case ValuePropertyMatchType.GreaterThan:
 548                        query =
 549                            Query<IMember>.Builder.Where(
 550                                x =>
 551                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 552                                ((Member)x).DateTimePropertyValue > value);
 553                        break;
 554                    case ValuePropertyMatchType.LessThan:
 555                        query =
 556                            Query<IMember>.Builder.Where(
 557                                x =>
 558                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 559                                ((Member)x).DateTimePropertyValue < value);
 560                        break;
 561                    case ValuePropertyMatchType.GreaterThanOrEqualTo:
 562                        query =
 563                            Query<IMember>.Builder.Where(
 564                                x =>
 565                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 566                                ((Member)x).DateTimePropertyValue >= value);
 567                        break;
 568                    case ValuePropertyMatchType.LessThanOrEqualTo:
 569                        query =
 570                            Query<IMember>.Builder.Where(
 571                                x =>
 572                                ((Member)x).PropertyTypeAlias == propertyTypeAlias &&
 573                                ((Member)x).DateTimePropertyValue <= value);
 574                        break;
 575                    default:
 576                        throw new ArgumentOutOfRangeException("matchType");
 577                }
 578
 579                var members = repository.GetByQuery(query);
 580                return members;
 581            }
 582        }
 583
 584        #endregion
 585
 586        #region IMembershipMemberService Implementation
 587
 588        /// <summary>
 589        /// Returns the count of members based on the countType
 590        /// </summary>
 591        /// <param name="countType"></param>
 592        /// <returns></returns>
 593        /// <remarks>
 594        /// The way the Online count is done is the same way that it is done in the MS SqlMembershipProvider - We query for any members
 595        /// that have their last active date within the Membership.UserIsOnlineTimeWindow (which is in minutes). It isn't exact science
 596        /// but that is how MS have made theirs so we'll follow that principal.
 597        /// </remarks>
 598        public int GetCount(MemberCountType countType)
 599        {
 600            using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
 601            {
 602                IQuery<IMember> query;
 603
 604                switch (countType)
 605                {
 606                    case MemberCountType.All:
 607                        query = new Query<IMember>();
 608                        return repository.Count(query);
 609                    case MemberCountType.Online:
 610                        var fromDate = DateTime.Now.AddMinutes(-Membership.UserIsOnlineTimeWindow);
 611                        query =
 612                            Query<IMember>.Builder.Where(
 613                                x =>
 614                                ((Member)x).PropertyTypeAlias == Constants.Conventions.Member.LastLoginDate &&
 615                                ((Member)x).DateTimePropertyValue > fromDate);
 616                        return repository.GetCountByQuery(query);
 617                    case MemberCountType.LockedOut:
 618                        query =
 619                            Query<IMember>.Builder.Where(
 620                                x =>
 621                                ((Member)x).PropertyTypeAlias == Constants.Conventions.Member.IsLockedOut &&
 622                                ((Member)x).BoolPropertyValue == true);
 623                        return repository.GetCountByQuery(query);
 624                    case MemberCountType.Approved:
 625                        query =
 626                            Query<IMember>.Builder.Where(
 627                                x =>
 628                                ((Member)x).PropertyTypeAlias == Constants.Conventions.Member.IsApproved &&
 629                                ((Member)x).BoolPropertyValue == true);
 630                        return repository.GetCountByQuery(query);
 631                    default:
 632                        throw new ArgumentOutOfRangeException("countType");
 633                }
 634            }
 635
 636        }
 637
 638        public IEnumerable<IMember> GetAll(int pageIndex, int pageSize, out int totalRecords)
 639        {
 640            var uow = _uowProvider.GetUnitOfWork();
 641            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 642            {
 643                return repository.GetPagedResultsByQuery(null, pageIndex, pageSize, out totalRecords, member => member.Username);
 644            }
 645        }
 646
 647        /// <summary>
 648        /// Creates a member object
 649        /// </summary>
 650        /// <param name="username"></param>
 651        /// <param name="email"></param>
 652        /// <param name="name"></param>
 653        /// <param name="memberTypeAlias"></param>
 654        /// <returns></returns>
 655        public IMember CreateMember(string username, string email, string name, string memberTypeAlias)
 656        {
 657            var memberType = FindMemberTypeByAlias(memberTypeAlias);
 658            return CreateMember(username, email, name, memberType);
 659        }
 660
 661        /// <summary>
 662        /// Creates a new member object
 663        /// </summary>
 664        /// <param name="username"></param>
 665        /// <param name="email"></param>
 666        /// <param name="name"></param>
 667        /// <param name="memberType"></param>
 668        /// <returns></returns>
 669        public IMember CreateMember(string username, string email, string name, IMemberType memberType)
 670        {
 671            var member = new Member(name, email.ToLower().Trim(), username, memberType);
 672
 673            Created.RaiseEvent(new NewEventArgs<IMember>(member, false, memberType.Alias, -1), this);
 674
 675            return member;
 676        }
 677
 678        /// <summary>
 679        /// Creates a member with an Id
 680        /// </summary>
 681        /// <param name="username"></param>
 682        /// <param name="email"></param>
 683        /// <param name="name"></param>
 684        /// <param name="memberTypeAlias"></param>
 685        /// <returns></returns>
 686        public IMember CreateMemberWithIdentity(string username, string email, string name, string memberTypeAlias)
 687        {
 688            var memberType = FindMemberTypeByAlias(memberTypeAlias);
 689            return CreateMemberWithIdentity(username, email, name, memberType);
 690        }
 691
 692        /// <summary>
 693        /// Creates a member with an Id, the username will be used as their name
 694        /// </summary>
 695        /// <param name="username"></param>
 696        /// <param name="email"></param>
 697        /// <param name="memberType"></param>
 698        /// <returns></returns>
 699        public IMember CreateMemberWithIdentity(string username, string email, IMemberType memberType)
 700        {
 701            return CreateMemberWithIdentity(username, email, username, memberType);
 702        }
 703
 704        /// <summary>
 705        /// Creates a member with an Id
 706        /// </summary>
 707        /// <param name="username"></param>
 708        /// <param name="email"></param>
 709        /// <param name="name"></param>
 710        /// <param name="memberType"></param>
 711        /// <returns></returns>
 712        public IMember CreateMemberWithIdentity(string username, string email, string name, IMemberType memberType)
 713        {
 714            return CreateMemberWithIdentity(username, email, name, "", memberType);
 715        }
 716
 717        /// <summary>
 718        /// Creates and persists a new Member
 719        /// </summary>
 720        /// <param name="email"></param>
 721        /// <param name="username"></param>
 722        /// <param name="rawPasswordValue"></param>
 723        /// <param name="memberTypeAlias"></param>
 724        /// <returns></returns>
 725        IMember IMembershipMemberService<IMember>.CreateWithIdentity(string username, string email, string rawPasswordValue, string memberTypeAlias)
 726        {
 727            var memberType = FindMemberTypeByAlias(memberTypeAlias);
 728            return CreateMemberWithIdentity(username, email, username, rawPasswordValue, memberType);
 729        }
 730
 731        private IMember CreateMemberWithIdentity(string username, string email, string name, string rawPasswordValue, IMemberType memberType)
 732        {
 733            if (memberType == null) throw new ArgumentNullException("memberType");
 734
 735            var member = new Member(name, email.ToLower().Trim(), username, rawPasswordValue, memberType);
 736
 737            if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(member), this))
 738            {
 739                member.WasCancelled = true;
 740                return member;
 741            }
 742
 743            var uow = _uowProvider.GetUnitOfWork();
 744            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 745            {
 746                repository.AddOrUpdate(member);
 747                //insert the xml
 748                repository.AddOrUpdateContentXml(member, m => _entitySerializer.Serialize(_dataTypeService, m));
 749                // generate preview for blame history?
 750                if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
 751                {
 752                    repository.AddOrUpdatePreviewXml(member, m => _entitySerializer.Serialize(_dataTypeService, m));
 753                }
 754
 755                uow.Commit();
 756            }
 757
 758            Saved.RaiseEvent(new SaveEventArgs<IMember>(member, false), this);
 759            Created.RaiseEvent(new NewEventArgs<IMember>(member, false, memberType.Alias, -1), this);
 760
 761            return member;
 762        }
 763
 764        /// <summary>
 765        /// Gets a Member by its Id
 766        /// </summary>
 767        /// <remarks>
 768        /// The Id should be an integer or Guid.
 769        /// </remarks>
 770        /// <param name="id"></param>
 771        /// <returns></returns>
 772        public IMember GetByProviderKey(object id)
 773        {
 774            var asGuid = id.TryConvertTo<Guid>();
 775            if (asGuid.Success)
 776            {
 777                return GetByKey((Guid)id);
 778            }
 779            var asInt = id.TryConvertTo<int>();
 780            if (asInt.Success)
 781            {
 782                return GetById((int)id);
 783            }
 784
 785            return null;
 786        }
 787
 788        /// <summary>
 789        /// Gets a Member by its Email
 790        /// </summary>
 791        /// <param name="email"></param>
 792        /// <returns></returns>
 793        public IMember GetByEmail(string email)
 794        {
 795            var uow = _uowProvider.GetUnitOfWork();
 796            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 797            {
 798                var query = Query<IMember>.Builder.Where(x => x.Email.Equals(email));
 799                var member = repository.GetByQuery(query).FirstOrDefault();
 800
 801                return member;
 802            }
 803        }
 804
 805        /// <summary>
 806        /// Gets a Member by its Username
 807        /// </summary>
 808        /// <param name="userName"></param>
 809        /// <returns></returns>
 810        public IMember GetByUsername(string userName)
 811        {
 812            var uow = _uowProvider.GetUnitOfWork();
 813            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 814            {
 815                var query = Query<IMember>.Builder.Where(x => x.Username.Equals(userName));
 816                var member = repository.GetByQuery(query).FirstOrDefault();
 817
 818                return member;
 819            }
 820        }
 821
 822        /// <summary>
 823        /// Deletes a Member
 824        /// </summary>
 825        /// <param name="member"></param>
 826        public void Delete(IMember member)
 827        {
 828            if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMember>(member), this))
 829                return;
 830
 831            var uow = _uowProvider.GetUnitOfWork();
 832            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 833            {
 834                repository.Delete(member);
 835                uow.Commit();
 836            }
 837
 838            Deleted.RaiseEvent(new DeleteEventArgs<IMember>(member, false), this);
 839        }
 840        
 841        /// <summary>
 842        /// Saves an updated Member
 843        /// </summary>
 844        /// <param name="entity"></param>
 845        /// <param name="raiseEvents"></param>
 846        public void Save(IMember entity, bool raiseEvents = true)
 847        {
 848            if (raiseEvents)
 849            {
 850                if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(entity), this))
 851                {
 852                    return;
 853                }
 854
 855            }
 856
 857            var uow = _uowProvider.GetUnitOfWork();
 858            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 859            {
 860                repository.AddOrUpdate(entity);
 861                repository.AddOrUpdateContentXml(entity, m => _entitySerializer.Serialize(_dataTypeService, m));
 862                // generate preview for blame history?
 863                if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
 864                {
 865                    repository.AddOrUpdatePreviewXml(entity, m => _entitySerializer.Serialize(_dataTypeService, m));
 866                }
 867
 868                uow.Commit();
 869            }
 870
 871            if (raiseEvents)
 872                Saved.RaiseEvent(new SaveEventArgs<IMember>(entity, false), this);
 873        }
 874
 875        public void Save(IEnumerable<IMember> entities, bool raiseEvents = true)
 876        {
 877            var asArray = entities.ToArray();
 878
 879            if (raiseEvents)
 880            {
 881                if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(asArray), this))
 882                    return;
 883            }
 884            using (new WriteLock(Locker))
 885            {
 886                var uow = _uowProvider.GetUnitOfWork();
 887                using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 888                {
 889                    foreach (var member in asArray)
 890                    {
 891                        repository.AddOrUpdate(member);
 892                        repository.AddOrUpdateContentXml(member, m => _entitySerializer.Serialize(_dataTypeService, m));
 893                        // generate preview for blame history?
 894                        if (UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled)
 895                        {
 896                            repository.AddOrUpdatePreviewXml(member, m => _entitySerializer.Serialize(_dataTypeService, m));
 897                        }
 898                    }
 899
 900                    //commit the whole lot in one go
 901                    uow.Commit();
 902                }
 903
 904                if (raiseEvents)
 905                    Saved.RaiseEvent(new SaveEventArgs<IMember>(asArray, false), this);
 906            }
 907        }
 908
 909        #endregion
 910
 911        #region IMembershipRoleService Implementation
 912
 913        public void AddRole(string roleName)
 914        {
 915            var uow = _uowProvider.GetUnitOfWork();
 916            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
 917            {
 918                repository.CreateIfNotExists(roleName);
 919            }
 920        }
 921
 922        public IEnumerable<string> GetAllRoles()
 923        {
 924            var uow = _uowProvider.GetUnitOfWork();
 925            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
 926            {
 927                var result = repository.GetAll();
 928                return result.Select(x => x.Name).Distinct();
 929            }
 930        }
 931
 932        public IEnumerable<string> GetAllRoles(int memberId)
 933        {
 934            var uow = _uowProvider.GetUnitOfWork();
 935            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
 936            {
 937                var result = repository.GetMemberGroupsForMember(memberId);
 938                return result.Select(x => x.Name).Distinct();
 939            }
 940        }
 941
 942        public IEnumerable<string> GetAllRoles(string username)
 943        {
 944            var uow = _uowProvider.GetUnitOfWork();
 945            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
 946            {
 947                var result = repository.GetMemberGroupsForMember(username);
 948                return result.Select(x => x.Name).Distinct();
 949            }
 950        }
 951
 952        public IEnumerable<IMember> GetMembersInRole(string roleName)
 953        {
 954            var uow = _uowProvider.GetUnitOfWork();
 955            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 956            {
 957                return repository.GetByMemberGroup(roleName);
 958            }
 959        }
 960
 961        public IEnumerable<IMember> FindMembersInRole(string roleName, string usernameToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
 962        {
 963            var uow = _uowProvider.GetUnitOfWork();
 964            using (var repository = _repositoryFactory.CreateMemberRepository(uow))
 965            {
 966                return repository.FindMembersInRole(roleName, usernameToMatch, matchType);
 967            }
 968        }
 969
 970        public bool DeleteRole(string roleName, bool throwIfBeingUsed)
 971        {
 972            using (new WriteLock(Locker))
 973            {
 974                if (throwIfBeingUsed)
 975                {
 976                    var inRole = GetMembersInRole(roleName);
 977                    if (inRole.Any())
 978                    {
 979                        throw new InvalidOperationException("The role " + roleName + " is currently assigned to members");
 980                    }
 981                }
 982
 983                var uow = _uowProvider.GetUnitOfWork();
 984                using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
 985                {
 986                    var qry = new Query<IMemberGroup>().Where(g => g.Name == roleName);
 987                    var found = repository.GetByQuery(qry).ToArray();
 988
 989                    foreach (var memberGroup in found)
 990                    {
 991                        _memberGroupService.Delete(memberGroup);
 992                    }
 993                    return found.Any();
 994                }
 995            }
 996        }
 997        public void AssignRole(string username, string roleName)
 998        {
 999            AssignRoles(new[] { username }, new[] { roleName });
1000        }
1001
1002        public void AssignRoles(string[] usernames, string[] roleNames)
1003        {
1004            var uow = _uowProvider.GetUnitOfWork();
1005            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
1006            {
1007                repository.AssignRoles(usernames, roleNames);
1008            }
1009        }
1010
1011        public void DissociateRole(string username, string roleName)
1012        {
1013            DissociateRoles(new[] { username }, new[] { roleName });
1014        }
1015
1016        public void DissociateRoles(string[] usernames, string[] roleNames)
1017        {
1018            var uow = _uowProvider.GetUnitOfWork();
1019            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
1020            {
1021                repository.DissociateRoles(usernames, roleNames);
1022            }
1023        }
1024        
1025        public void AssignRole(int memberId, string roleName)
1026        {
1027            AssignRoles(new[] { memberId }, new[] { roleName });
1028        }
1029
1030        public void AssignRoles(int[] memberIds, string[] roleNames)
1031        {
1032            var uow = _uowProvider.GetUnitOfWork();
1033            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
1034            {
1035                repository.AssignRoles(memberIds, roleNames);
1036            }
1037        }
1038
1039        public void DissociateRole(int memberId, string roleName)
1040        {
1041            DissociateRoles(new[] { memberId }, new[] { roleName });
1042        }
1043
1044        public void DissociateRoles(int[] memberIds, string[] roleNames)
1045        {
1046            var uow = _uowProvider.GetUnitOfWork();
1047            using (var repository = _repositoryFactory.CreateMemberGroupRepository(uow))
1048            {
1049                repository.DissociateRoles(memberIds, roleNames);
1050            }
1051        }
1052
1053        
1054
1055        #endregion
1056
1057        private IMemberType FindMemberTypeByAlias(string memberTypeAlias)
1058        {
1059            using (var repository = _repositoryFactory.CreateMemberTypeRepository(_uowProvider.GetUnitOfWork()))
1060            {
1061                var query = Query<IMemberType>.Builder.Where(x => x.Alias == memberTypeAlias);
1062                var types = repository.GetByQuery(query);
1063
1064                if (types.Any() == false)
1065                    throw new Exception(
1066                        string.Format("No MemberType matching the passed in Alias: '{0}' was found",
1067                                      memberTypeAlias));
1068
1069                var contentType = types.First();
1070
1071                if (contentType == null)
1072                    throw new Exception(string.Format("MemberType matching the passed in Alias: '{0}' was null",
1073                                                      memberTypeAlias));
1074
1075                return contentType;
1076            }
1077        }
1078
1079        /// <summary>
1080        /// Rebuilds all xml content in the cmsContentXml table for all members
1081        /// </summary>
1082        /// <param name="memberTypeIds">
1083        /// Only rebuild the xml structures for the content type ids passed in, if none then rebuilds the structures
1084        /// for all members = USE WITH CARE!
1085        /// </param>
1086        /// <returns>True if publishing succeeded, otherwise False</returns>
1087        internal void RebuildXmlStructures(params int[] memberTypeIds)
1088        {
1089            using (new WriteLock(Locker))
1090            {
1091                var list = new List<IMember>();
1092
1093                var uow = _uowProvider.GetUnitOfWork();
1094
1095                //First we're going to get the data that needs to be inserted before clearing anything, this 
1096                //ensures that we don't accidentally leave the content xml table empty if something happens
1097                //during the lookup process.
1098
1099                if (memberTypeIds.Any() == false)
1100                {
1101                    list.AddRange(GetAllMembers());
1102                }
1103                else
1104                {
1105                    list.AddRange(memberTypeIds.SelectMany(GetMembersByMemberType));
1106                }
1107
1108                var xmlItems = new List<ContentXmlDto>();
1109                foreach (var c in list)
1110                {
1111                    var xml = _entitySerializer.Serialize(_dataTypeService, c);
1112                    xmlItems.Add(new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) });
1113                }
1114
1115                //Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
1116                using (var tr = uow.Database.GetTransaction())
1117                {
1118                    if (memberTypeIds.Any() == false)
1119                    {
1120                        //Remove all member records from the cmsContentXml table (DO NOT REMOVE Content/Media!)
1121                        var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
1122                        var subQuery = new Sql()
1123                            .Select("DISTINCT cmsContentXml.nodeId")
1124                            .From<ContentXmlDto>()
1125                            .InnerJoin<NodeDto>()
1126                            .On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
1127                            .Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType);
1128
1129                        var deleteSql = SqlSyntaxContext.SqlSyntaxProvider.GetDeleteSubquery("cmsContentXml", "nodeId", subQuery);
1130                        uow.Database.Execute(deleteSql);
1131                    }
1132                    else
1133                    {
1134                        foreach (var id in memberTypeIds)
1135                        {
1136                            var id1 = id;
1137                            var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
1138                            var subQuery = new Sql()
1139                                .Select("DISTINCT cmsContentXml.nodeId")
1140                                .From<ContentXmlDto>()
1141                                .InnerJoin<NodeDto>()
1142                                .On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
1143                                .InnerJoin<ContentDto>()
1144                                .On<ContentDto, NodeDto>(left => left.

Large files files are truncated, but you can click here to view the full file