diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs
index 4f44af016c..33748ae46b 100644
--- a/src/Umbraco.Core/ApplicationContext.cs
+++ b/src/Umbraco.Core/ApplicationContext.cs
@@ -35,12 +35,9 @@ namespace Umbraco.Core
///
///
///
- internal ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, bool enableCache)
+ public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, bool enableCache)
: this(enableCache)
{
- if (dbContext == null) throw new ArgumentNullException("dbContext");
- if (serviceContext == null) throw new ArgumentNullException("serviceContext");
-
_databaseContext = dbContext;
_services = serviceContext;
}
@@ -57,7 +54,7 @@ namespace Umbraco.Core
/// Constructor used to specify if we will enable application cache or not
///
///
- internal ApplicationContext(bool enableCache)
+ public ApplicationContext(bool enableCache)
{
//create a new application cache from the HttpRuntime.Cache
ApplicationCache = HttpRuntime.Cache == null
@@ -65,7 +62,55 @@ namespace Umbraco.Core
: new CacheHelper(HttpRuntime.Cache, enableCache);
}
- ///
+ ///
+ /// A method used to set and/or ensure that a global ApplicationContext singleton is created.
+ ///
+ ///
+ /// The instance to set on the global application singleton
+ ///
+ /// If set to true and the singleton is already set, it will be replaced
+ ///
+ ///
+ /// This is NOT thread safe
+ ///
+ public static ApplicationContext EnsureContext(ApplicationContext appContext, bool replaceContext)
+ {
+ if (ApplicationContext.Current != null)
+ {
+ if (!replaceContext)
+ return ApplicationContext.Current;
+ }
+ ApplicationContext.Current = appContext;
+ return ApplicationContext.Current;
+ }
+
+ ///
+ /// A method used to create and ensure that a global ApplicationContext singleton is created.
+ ///
+ ///
+ ///
+ /// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
+ /// startup if for some reason the boot manager is not the umbraco boot manager.
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// This is NOT thread safe
+ ///
+ public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, bool enableCache, bool replaceContext)
+ {
+ if (ApplicationContext.Current != null)
+ {
+ if (!replaceContext)
+ return ApplicationContext.Current;
+ }
+ var ctx = new ApplicationContext(dbContext, serviceContext, enableCache);
+ ApplicationContext.Current = ctx;
+ return ApplicationContext.Current;
+ }
+
+ ///
/// Singleton accessor
///
public static ApplicationContext Current { get; internal set; }
diff --git a/src/Umbraco.Core/Constants-Conventions.cs b/src/Umbraco.Core/Constants-Conventions.cs
index b8161b9480..81cec10f94 100644
--- a/src/Umbraco.Core/Constants-Conventions.cs
+++ b/src/Umbraco.Core/Constants-Conventions.cs
@@ -99,6 +99,10 @@ namespace Umbraco.Core
///
public static class Member
{
+ public static readonly string UmbracoMemberProviderName = "UmbracoMembershipProvider";
+
+ public static readonly string UmbracoRoleProviderName = "UmbracoRoleProvider";
+
///
/// Property alias for a Members Password Question
///
diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs
index dbbc476ae9..4d5170ec80 100644
--- a/src/Umbraco.Core/DatabaseContext.cs
+++ b/src/Umbraco.Core/DatabaseContext.cs
@@ -28,7 +28,7 @@ namespace Umbraco.Core
private string _providerName;
private DatabaseSchemaResult _result;
- internal DatabaseContext(IDatabaseFactory factory)
+ public DatabaseContext(IDatabaseFactory factory)
{
_factory = factory;
}
diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs
index 738a896155..9a5e735e9e 100644
--- a/src/Umbraco.Core/Models/ContentBase.cs
+++ b/src/Umbraco.Core/Models/ContentBase.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
@@ -50,6 +51,7 @@ namespace Umbraco.Core.Models
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
_properties = properties;
_properties.EnsurePropertyTypes(PropertyTypes);
+ _additionalData = new Dictionary();
}
///
@@ -73,6 +75,7 @@ namespace Umbraco.Core.Models
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
_properties = properties;
_properties.EnsurePropertyTypes(PropertyTypes);
+ _additionalData = new Dictionary();
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
@@ -253,6 +256,16 @@ namespace Umbraco.Core.Models
}
}
+ private readonly IDictionary _additionalData;
+ ///
+ /// Some entities may expose additional data that other's might not, this custom data will be available in this collection
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ IDictionary IUmbracoEntity.AdditionalData
+ {
+ get { return _additionalData; }
+ }
+
///
/// List of PropertyGroups available on this Content object
///
diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs
index e8d2effbc1..94000e41c9 100644
--- a/src/Umbraco.Core/Models/ContentTypeBase.cs
+++ b/src/Umbraco.Core/Models/ContentTypeBase.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
@@ -42,6 +43,7 @@ namespace Umbraco.Core.Models
_allowedContentTypes = new List();
_propertyGroups = new PropertyGroupCollection();
_propertyTypes = new PropertyTypeCollection();
+ _additionalData = new Dictionary();
}
protected ContentTypeBase(IContentTypeBase parent)
@@ -52,6 +54,7 @@ namespace Umbraco.Core.Models
_allowedContentTypes = new List();
_propertyGroups = new PropertyGroupCollection();
_propertyTypes = new PropertyTypeCollection();
+ _additionalData = new Dictionary();
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
@@ -314,6 +317,16 @@ namespace Umbraco.Core.Models
}
}
+ private readonly IDictionary _additionalData;
+ ///
+ /// Some entities may expose additional data that other's might not, this custom data will be available in this collection
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ IDictionary IUmbracoEntity.AdditionalData
+ {
+ get { return _additionalData; }
+ }
+
///
/// Gets or sets a list of integer Ids for allowed ContentTypes
///
diff --git a/src/Umbraco.Core/Models/DataTypeDefinition.cs b/src/Umbraco.Core/Models/DataTypeDefinition.cs
index f7068a3b6e..00966496f3 100644
--- a/src/Umbraco.Core/Models/DataTypeDefinition.cs
+++ b/src/Umbraco.Core/Models/DataTypeDefinition.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.ComponentModel;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
@@ -31,6 +33,7 @@ namespace Umbraco.Core.Models
{
_parentId = parentId;
_controlId = controlId;
+ _additionalData = new Dictionary();
}
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo(x => x.Name);
@@ -160,9 +163,11 @@ namespace Umbraco.Core.Models
_trashed = value;
return _trashed;
}, _trashed, TrashedSelector);
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ _additionalData["Trashed"] = value;
}
}
-
+
///
/// Id of the DataType control
///
@@ -177,6 +182,8 @@ namespace Umbraco.Core.Models
_controlId = value;
return _controlId;
}, _controlId, ControlIdSelector);
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ _additionalData["ControlId"] = value;
}
}
@@ -194,9 +201,22 @@ namespace Umbraco.Core.Models
_databaseType = value;
return _databaseType;
}, _databaseType, DatabaseTypeSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ _additionalData["DatabaseType"] = value;
}
}
+ private readonly IDictionary _additionalData;
+ ///
+ /// Some entities may expose additional data that other's might not, this custom data will be available in this collection
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ IDictionary IUmbracoEntity.AdditionalData
+ {
+ get { return _additionalData; }
+ }
+
internal override void AddingEntity()
{
base.AddingEntity();
diff --git a/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs b/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs
index 62130fdab9..397f4518a9 100644
--- a/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs
+++ b/src/Umbraco.Core/Models/EntityBase/IUmbracoEntity.cs
@@ -1,4 +1,6 @@
-namespace Umbraco.Core.Models.EntityBase
+using System.Collections.Generic;
+
+namespace Umbraco.Core.Models.EntityBase
{
public interface IUmbracoEntity : IAggregateRoot
{
@@ -41,5 +43,10 @@
/// Not all entities support being trashed, they'll always return false.
///
bool Trashed { get; }
+
+ ///
+ /// 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/Member.cs b/src/Umbraco.Core/Models/Member.cs
index 335beb9ee4..5fd48da994 100644
--- a/src/Umbraco.Core/Models/Member.cs
+++ b/src/Umbraco.Core/Models/Member.cs
@@ -427,7 +427,7 @@ namespace Umbraco.Core.Models
public override void ChangeTrashedState(bool isTrashed, int parentId = -20)
{
- throw new NotImplementedException("Members can't be trashed as no Recycle Bin exists, so use of this method is invalid");
+ throw new NotSupportedException("Members can't be trashed as no Recycle Bin exists, so use of this method is invalid");
}
/* Internal experiment - only used for mapping queries.
diff --git a/src/Umbraco.Core/Models/Membership/UmbracoMembershipMember.cs b/src/Umbraco.Core/Models/Membership/UmbracoMembershipMember.cs
index 06e50ecd9b..d55cc77f66 100644
--- a/src/Umbraco.Core/Models/Membership/UmbracoMembershipMember.cs
+++ b/src/Umbraco.Core/Models/Membership/UmbracoMembershipMember.cs
@@ -2,6 +2,8 @@
namespace Umbraco.Core.Models.Membership
{
+ //TODO: THere's still a bunch of properties that don't exist in this use that need to be mapped somehow.
+
internal class UmbracoMembershipMember : MembershipUser
{
private readonly IMember _member;
@@ -21,5 +23,44 @@ namespace Umbraco.Core.Models.Membership
get { return _member.Email; }
set { _member.Email = value; }
}
+
+ public override object ProviderUserKey
+ {
+ get { return _member.Key; }
+ }
+
+ public override System.DateTime CreationDate
+ {
+ get { return _member.CreateDate; }
+ }
+
+ public override string UserName
+ {
+ get { return _member.Username; }
+ }
+
+ public override string Comment
+ {
+ get { return _member.Comments; }
+ set { _member.Comments = value; }
+ }
+
+ public override bool IsApproved
+ {
+ get { return _member.IsApproved; }
+ set { _member.IsApproved = value; }
+ }
+
+ public override bool IsLockedOut
+ {
+ get { return _member.IsLockedOut; }
+ }
+
+ public override System.DateTime LastLoginDate
+ {
+ get { return _member.LastLoginDate; }
+ set { _member.LastLoginDate = value; }
+ }
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/PagedResult.cs b/src/Umbraco.Core/Models/PagedResult.cs
new file mode 100644
index 0000000000..2e35da9a96
--- /dev/null
+++ b/src/Umbraco.Core/Models/PagedResult.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+
+namespace Umbraco.Core.Models
+{
+ ///
+ /// Represents a paged result for a model collection
+ ///
+ ///
+ [DataContract(Name = "pagedCollection", Namespace = "")]
+ public class PagedResult
+ {
+ public PagedResult(long totalItems, long pageNumber, long pageSize)
+ {
+ TotalItems = totalItems;
+ PageNumber = pageNumber;
+ PageSize = pageSize;
+
+ if (pageSize > 0)
+ {
+ TotalPages = (long) Math.Ceiling(totalItems/(Decimal) pageSize);
+ }
+ else
+ {
+ TotalPages = 1;
+ }
+ }
+
+ [DataMember(Name = "pageNumber")]
+ public long PageNumber { get; private set; }
+
+ [DataMember(Name = "pageSize")]
+ public long PageSize { get; private set; }
+
+ [DataMember(Name = "totalPages")]
+ public long TotalPages { get; private set; }
+
+ [DataMember(Name = "totalItems")]
+ public long TotalItems { get; private set; }
+
+ [DataMember(Name = "items")]
+ public IEnumerable Items { get; set; }
+
+ ///
+ /// Calculates the skip size based on the paged parameters specified
+ ///
+ ///
+ /// Returns 0 if the page number or page size is zero
+ ///
+ internal int SkipSize
+ {
+ get
+ {
+ if (PageNumber > 0 && PageSize > 0)
+ {
+ return Convert.ToInt32((PageNumber - 1)*PageSize);
+ }
+ return 0;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs
index 451c0fe9c1..0a8302dea1 100644
--- a/src/Umbraco.Core/Models/UmbracoEntity.cs
+++ b/src/Umbraco.Core/Models/UmbracoEntity.cs
@@ -44,10 +44,12 @@ namespace Umbraco.Core.Models
public UmbracoEntity()
{
+ AdditionalData = new Dictionary();
}
public UmbracoEntity(bool trashed)
{
+ AdditionalData = new Dictionary();
Trashed = trashed;
}
@@ -142,6 +144,9 @@ namespace Umbraco.Core.Models
}
}
+ public IDictionary AdditionalData { get; private set; }
+
+
public bool HasChildren
{
get { return _hasChildren; }
@@ -152,6 +157,9 @@ namespace Umbraco.Core.Models
_hasChildren = value;
return _hasChildren;
}, _hasChildren, HasChildrenSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["HasChildren"] = value;
}
}
@@ -164,7 +172,10 @@ namespace Umbraco.Core.Models
{
_isPublished = value;
return _isPublished;
- }, _isPublished, IsPublishedSelector);
+ }, _isPublished, IsPublishedSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["IsPublished"] = value;
}
}
@@ -178,6 +189,9 @@ namespace Umbraco.Core.Models
_isDraft = value;
return _isDraft;
}, _isDraft, IsDraftSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["IsDraft"] = value;
}
}
@@ -191,6 +205,9 @@ namespace Umbraco.Core.Models
_hasPendingChanges = value;
return _hasPendingChanges;
}, _hasPendingChanges, HasPendingChangesSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["HasPendingChanges"] = value;
}
}
@@ -204,6 +221,9 @@ namespace Umbraco.Core.Models
_contentTypeAlias = value;
return _contentTypeAlias;
}, _contentTypeAlias, ContentTypeAliasSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["ContentTypeAlias"] = value;
}
}
@@ -217,6 +237,9 @@ namespace Umbraco.Core.Models
_contentTypeIcon = value;
return _contentTypeIcon;
}, _contentTypeIcon, ContentTypeIconSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["ContentTypeIcon"] = value;
}
}
@@ -230,6 +253,9 @@ namespace Umbraco.Core.Models
_contentTypeThumbnail = value;
return _contentTypeThumbnail;
}, _contentTypeThumbnail, ContentTypeThumbnailSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["ContentTypeThumbnail"] = value;
}
}
@@ -242,10 +268,16 @@ namespace Umbraco.Core.Models
{
_nodeObjectTypeId = value;
return _nodeObjectTypeId;
- }, _nodeObjectTypeId, NodeObjectTypeIdSelector);
+ }, _nodeObjectTypeId, NodeObjectTypeIdSelector);
+
+ //This is a custom property that is not exposed in IUmbracoEntity so add it to the additional data
+ AdditionalData["NodeObjectTypeId"] = value;
}
}
+ ///
+ /// Some entities may expose additional data that other's might not, this custom data will be available in this collection
+ ///
public IList UmbracoProperties { get; set; }
internal class UmbracoProperty
diff --git a/src/Umbraco.Core/Persistence/Factories/IEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/IEntityFactory.cs
index 6053090178..a0d8823d68 100644
--- a/src/Umbraco.Core/Persistence/Factories/IEntityFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/IEntityFactory.cs
@@ -1,5 +1,7 @@
namespace Umbraco.Core.Persistence.Factories
{
+ //TODO: Not sure why we need this interface as it's never referenced in code.
+
internal interface IEntityFactory
where TEntity : class
where TDto : class
diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
index d7b8247364..226294be0f 100644
--- a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
@@ -8,6 +8,45 @@ namespace Umbraco.Core.Persistence.Factories
{
internal class UmbracoEntityFactory : IEntityFactory
{
+ internal UmbracoEntity BuildEntityFromDynamic(dynamic d)
+ {
+ var entity = new UmbracoEntity(d.trashed)
+ {
+ CreateDate = d.createDate,
+ CreatorId = d.nodeUser,
+ Id = d.id,
+ Key = d.uniqueID,
+ Level = d.level,
+ Name = d.text,
+ NodeObjectTypeId = d.nodeObjectType,
+ ParentId = d.parentID,
+ Path = d.path,
+ SortOrder = d.sortOrder,
+ HasChildren = d.children > 0,
+ ContentTypeAlias = d.alias ?? string.Empty,
+ ContentTypeIcon = d.icon ?? string.Empty,
+ ContentTypeThumbnail = d.thumbnail ?? string.Empty,
+ UmbracoProperties = new List()
+ };
+
+ var asDictionary = (IDictionary)d;
+
+ var publishedVersion = default(Guid);
+ //some content items don't have a published version
+ if (asDictionary.ContainsKey("publishedVersion") && asDictionary["publishedVersion"] != null)
+ {
+ Guid.TryParse(d.publishedVersion.ToString(), out publishedVersion);
+ }
+ var newestVersion = default(Guid);
+ Guid.TryParse(d.newestVersion.ToString(), out newestVersion);
+
+ entity.IsPublished = publishedVersion != default(Guid) || (newestVersion != default(Guid) && publishedVersion == newestVersion);
+ entity.IsDraft = newestVersion != default(Guid) && (publishedVersion == default(Guid) || publishedVersion != newestVersion);
+ entity.HasPendingChanges = (publishedVersion != default(Guid) && newestVersion != default(Guid)) && publishedVersion != newestVersion;
+
+ return entity;
+ }
+
public UmbracoEntity BuildEntity(EntityRepository.UmbracoEntityDto dto)
{
var entity = new UmbracoEntity(dto.Trashed)
diff --git a/src/Umbraco.Core/Persistence/IDatabaseFactory.cs b/src/Umbraco.Core/Persistence/IDatabaseFactory.cs
index 87c146fa0f..b0efb7f94a 100644
--- a/src/Umbraco.Core/Persistence/IDatabaseFactory.cs
+++ b/src/Umbraco.Core/Persistence/IDatabaseFactory.cs
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Persistence
///
/// Used to create the UmbracoDatabase for use in the DatabaseContext
///
- internal interface IDatabaseFactory : IDisposable
+ public interface IDatabaseFactory : IDisposable
{
UmbracoDatabase CreateDatabase();
}
diff --git a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs
index eb10bf7f87..f249ca4577 100644
--- a/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs
+++ b/src/Umbraco.Core/Persistence/PetaPocoExtensions.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Data;
using System.Linq;
+using System.Text.RegularExpressions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
@@ -17,6 +18,19 @@ namespace Umbraco.Core.Persistence
internal static event CreateTableEventHandler NewTable;
+ ///
+ /// This will escape single @ symbols for peta poco values so it doesn't think it's a parameter
+ ///
+ ///
+ ///
+ ///
+ public static string EscapeAtSymbols(this Database db, string value)
+ {
+ //this fancy regex will only match a single @ not a double, etc...
+ var regex = new Regex("(?(this Database db)
where T : new()
{
diff --git a/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs b/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs
index a9129498c5..f02ca8e1b1 100644
--- a/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs
+++ b/src/Umbraco.Core/Persistence/Relators/PropertyTypePropertyGroupRelator.cs
@@ -38,7 +38,11 @@ namespace Umbraco.Core.Persistence.Relators
// Setup the new current MemberTypeReadOnlyDto
Current = a;
Current.PropertyTypes = new List();
- Current.PropertyTypes.Add(p);
+ //this can be null since we are doing a left join
+ if (p.Id.HasValue)
+ {
+ Current.PropertyTypes.Add(p);
+ }
Current.PropertyTypeGroups = new List();
if (g.Id.HasValue)
diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
index 8651068030..bbfea4082a 100644
--- a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
@@ -1,12 +1,18 @@
using System;
using System.Collections.Generic;
+using System.Dynamic;
+using System.Globalization;
using System.Linq;
+using System.Reflection;
+using System.Text;
using Umbraco.Core.Models;
+using Umbraco.Core;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
+using Umbraco.Core.Strings;
namespace Umbraco.Core.Persistence.Repositories
{
@@ -124,15 +130,43 @@ namespace Umbraco.Core.Persistence.Repositories
var translator = new SqlTranslator(sqlClause, query);
var sql = translator.Translate().Append(GetGroupBy(isContent, isMedia));
- var dtos = isMedia
- ? _work.Database.Fetch(
- new UmbracoEntityRelator().Map, sql)
- : _work.Database.Fetch(sql);
-
var factory = new UmbracoEntityFactory();
- var list = dtos.Select(factory.BuildEntity).Cast().ToList();
- return list;
+ if (isMedia)
+ {
+ //treat media differently for now
+ var dtos = _work.Database.Fetch(
+ new UmbracoEntityRelator().Map, sql);
+ return dtos.Select(factory.BuildEntity).Cast().ToArray();
+ }
+ else
+ {
+ //use dynamic so that we can get ALL properties from the SQL
+ //we'll have to stitch stuff together manually but we can get our
+ //additional data to put in the dictionary.
+ var dtos = _work.Database.Fetch(sql);
+ var entityProps = TypeHelper.GetPublicProperties(typeof (IUmbracoEntity)).Select(x => x.Name).ToArray();
+ var result = new List();
+ foreach (var d in dtos)
+ {
+ //build the initial entity
+ IUmbracoEntity entity = factory.BuildEntityFromDynamic(d);
+
+ //convert the dynamic row to dictionary
+ var asDictionary = (IDictionary) d;
+
+ //figure out what extra properties we have that are not on the IUmbracoEntity and add them to additional data
+ foreach (var k in asDictionary.Keys
+ .Select(x => new {orig = x, title = x.ConvertCase(StringAliasCaseType.PascalCase)})
+ .Where(x => entityProps.InvariantContains(x.title) == false))
+ {
+ entity.AdditionalData[k.title] = asDictionary[k.orig];
+ }
+
+ result.Add(entity);
+ }
+ return result;
+ }
}
#endregion
@@ -159,11 +193,12 @@ namespace Umbraco.Core.Persistence.Repositories
if (isContent || isMedia)
{
- columns.Add("published.versionId as publishedVerison");
+ columns.Add("published.versionId as publishedVersion");
columns.Add("latest.versionId as newestVersion");
columns.Add("contenttype.alias");
columns.Add("contenttype.icon");
columns.Add("contenttype.thumbnail");
+ columns.Add("contenttype.isContainer");
}
if (isMedia)
@@ -251,6 +286,7 @@ namespace Umbraco.Core.Persistence.Repositories
columns.Add("contenttype.alias");
columns.Add("contenttype.icon");
columns.Add("contenttype.thumbnail");
+ columns.Add("contenttype.isContainer");
}
if (isMedia)
@@ -287,7 +323,7 @@ namespace Umbraco.Core.Persistence.Repositories
[Column("children")]
public int Children { get; set; }
- [Column("publishedVerison")]
+ [Column("publishedVersion")]
public Guid PublishedVersion { get; set; }
[Column("newestVersion")]
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs
index be959da07c..55f3099640 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IMemberRepository.cs
@@ -11,5 +11,6 @@ namespace Umbraco.Core.Persistence.Repositories
///
///
IEnumerable GetByMemberGroup(string groupName);
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
index caa92f94ef..b8024939b0 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MemberRepository.cs
@@ -298,11 +298,19 @@ namespace Umbraco.Core.Persistence.Repositories
//TODO ContentType for the Member entity
//Create the PropertyData for this version - cmsPropertyData
- var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
- var propertyDataDtos = propertyFactory.BuildDto(((Member)entity).Properties);
+ var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
var keyDictionary = new Dictionary();
//Add Properties
+ // - don't try to save the property if it doesn't exist (or doesn't have an ID) on the content type
+ // - this can occur if the member type doesn't contain the built-in properties that the
+ // - member object contains.
+ var existingProperties = entity.Properties
+ .Where(property => entity.ContentType.PropertyTypes.Any(x => x.Alias == property.Alias && x.HasIdentity))
+ .ToList();
+
+ var propertyDataDtos = propertyFactory.BuildDto(existingProperties);
+
foreach (var propertyDataDto in propertyDataDtos)
{
if (propertyDataDto.Id > 0)
diff --git a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs
index 9ee215d4f7..73ba016264 100644
--- a/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/MemberTypeRepository.cs
@@ -108,7 +108,7 @@ namespace Umbraco.Core.Persistence.Repositories
.From()
.InnerJoin().On(left => left.NodeId, right => right.NodeId)
.LeftJoin().On(left => left.ContentTypeId, right => right.NodeId)
- .InnerJoin().On(left => left.PropertyTypeId, right => right.Id)
+ .LeftJoin().On(left => left.PropertyTypeId, right => right.Id)
.LeftJoin().On(left => left.DataTypeId, right => right.DataTypeId)
.LeftJoin().On(left => left.ContentTypeNodeId, right => right.NodeId)
.Where(x => x.NodeObjectType == NodeObjectTypeId);
@@ -122,7 +122,7 @@ namespace Umbraco.Core.Persistence.Repositories
.From()
.InnerJoin().On(left => left.NodeId, right => right.NodeId)
.LeftJoin().On(left => left.ContentTypeId, right => right.NodeId)
- .InnerJoin().On(left => left.PropertyTypeId, right => right.Id)
+ .LeftJoin().On(left => left.PropertyTypeId, right => right.Id)
.LeftJoin().On(left => left.DataTypeId, right => right.DataTypeId)
.LeftJoin().On(left => left.ContentTypeNodeId, right => right.NodeId)
.Where(x => x.NodeObjectType == NodeObjectTypeId);
diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
index 710dc27d87..ab0a5e8e65 100644
--- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs
+++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence
}
- internal RepositoryFactory(bool disableAllCache)
+ public RepositoryFactory(bool disableAllCache)
{
_disableAllCache = disableAllCache;
}
diff --git a/src/Umbraco.Core/Properties/AssemblyInfo.cs b/src/Umbraco.Core/Properties/AssemblyInfo.cs
index f58744b9f5..641fde43a1 100644
--- a/src/Umbraco.Core/Properties/AssemblyInfo.cs
+++ b/src/Umbraco.Core/Properties/AssemblyInfo.cs
@@ -43,4 +43,5 @@ using System.Security.Permissions;
[assembly: InternalsVisibleTo("Concorde.Sync")]
[assembly: InternalsVisibleTo("Umbraco.Belle")]
-[assembly: InternalsVisibleTo("Umbraco.VisualStudio")]
\ No newline at end of file
+[assembly: InternalsVisibleTo("Umbraco.VisualStudio")]
+[assembly: InternalsVisibleTo("umbraco.providers")]
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs
index 882aa86b4e..7e103c687b 100644
--- a/src/Umbraco.Core/Services/EntityService.cs
+++ b/src/Umbraco.Core/Services/EntityService.cs
@@ -10,7 +10,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
{
- public class EntityService : IService
+ public class EntityService : IService, IEntityService
{
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private readonly RepositoryFactory _repositoryFactory;
diff --git a/src/Umbraco.Core/Services/IEntityService.cs b/src/Umbraco.Core/Services/IEntityService.cs
new file mode 100644
index 0000000000..c32d755c3f
--- /dev/null
+++ b/src/Umbraco.Core/Services/IEntityService.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.EntityBase;
+
+namespace Umbraco.Core.Services
+{
+ public interface IEntityService
+ {
+ ///
+ /// Gets an UmbracoEntity by its Id, and optionally loads the complete object graph.
+ ///
+ ///
+ /// By default this will load the base type with a minimum set of properties.
+ ///
+ /// Id of the object to retrieve
+ /// Optional bool to load the complete object graph when set to False.
+ /// An
+ IUmbracoEntity Get(int id, bool loadBaseType = true);
+
+ ///
+ /// Gets an UmbracoEntity by its Id and UmbracoObjectType, and optionally loads the complete object graph.
+ ///
+ ///
+ /// By default this will load the base type with a minimum set of properties.
+ ///
+ /// Id of the object to retrieve
+ /// UmbracoObjectType of the entity to retrieve
+ /// Optional bool to load the complete object graph when set to False.
+ /// An
+ IUmbracoEntity Get(int id, UmbracoObjectTypes umbracoObjectType, bool loadBaseType = true);
+
+ ///
+ /// Gets an UmbracoEntity by its Id and specified Type. Optionally loads the complete object graph.
+ ///
+ ///
+ /// By default this will load the base type with a minimum set of properties.
+ ///
+ /// Type of the model to retrieve. Must be based on an
+ /// Id of the object to retrieve
+ /// Optional bool to load the complete object graph when set to False.
+ /// An
+ IUmbracoEntity Get(int id, bool loadBaseType = true) where T : IUmbracoEntity;
+
+ ///
+ /// Gets the parent of entity by its id
+ ///
+ /// Id of the entity to retrieve the Parent for
+ /// An
+ IUmbracoEntity GetParent(int id);
+
+ ///
+ /// Gets the parent of entity by its id and UmbracoObjectType
+ ///
+ /// Id of the entity to retrieve the Parent for
+ /// UmbracoObjectType of the parent to retrieve
+ /// An
+ IUmbracoEntity GetParent(int id, UmbracoObjectTypes umbracoObjectType);
+
+ ///
+ /// Gets a collection of children by the parents Id
+ ///
+ /// Id of the parent to retrieve children for
+ /// An enumerable list of objects
+ IEnumerable GetChildren(int parentId);
+
+ ///
+ /// Gets a collection of children by the parents Id and UmbracoObjectType
+ ///
+ /// Id of the parent to retrieve children for
+ /// UmbracoObjectType of the children to retrieve
+ /// An enumerable list of objects
+ IEnumerable GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType);
+
+ ///
+ /// Gets a collection of descendents by the parents Id
+ ///
+ /// Id of entity to retrieve descendents for
+ /// An enumerable list of objects
+ IEnumerable GetDescendents(int id);
+
+ ///
+ /// Gets a collection of descendents by the parents Id
+ ///
+ /// Id of entity to retrieve descendents for
+ /// UmbracoObjectType of the descendents to retrieve
+ /// An enumerable list of objects
+ IEnumerable GetDescendents(int id, UmbracoObjectTypes umbracoObjectType);
+
+ ///
+ /// Gets a collection of the entities at the root, which corresponds to the entities with a Parent Id of -1.
+ ///
+ /// UmbracoObjectType of the root entities to retrieve
+ /// An enumerable list of objects
+ IEnumerable GetRootEntities(UmbracoObjectTypes umbracoObjectType);
+
+ ///
+ /// Gets a collection of all of a given type.
+ ///
+ /// Type of the entities to retrieve
+ /// An enumerable list of objects
+ IEnumerable GetAll() where T : IUmbracoEntity;
+
+ ///
+ /// Gets a collection of all of a given type.
+ ///
+ /// UmbracoObjectType of the entities to return
+ /// An enumerable list of objects
+ IEnumerable GetAll(UmbracoObjectTypes umbracoObjectType);
+
+ ///
+ /// Gets a collection of
+ ///
+ /// Guid id of the UmbracoObjectType
+ /// An enumerable list of objects
+ IEnumerable GetAll(Guid objectTypeId);
+
+ ///
+ /// Gets the UmbracoObjectType from the integer id of an IUmbracoEntity.
+ ///
+ /// Id of the entity
+ ///
+ UmbracoObjectTypes GetObjectType(int id);
+
+ ///
+ /// Gets the UmbracoObjectType from an IUmbracoEntity.
+ ///
+ ///
+ ///
+ UmbracoObjectTypes GetObjectType(IUmbracoEntity entity);
+
+ ///
+ /// Gets the Type of an entity by its Id
+ ///
+ /// Id of the entity
+ /// Type of the entity
+ Type GetEntityType(int id);
+
+ ///
+ /// Gets the Type of an entity by its
+ ///
+ ///
+ /// Type of the entity
+ Type GetEntityType(UmbracoObjectTypes umbracoObjectType);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/IMemberService.cs b/src/Umbraco.Core/Services/IMemberService.cs
index a6a2a14424..8894c419fc 100644
--- a/src/Umbraco.Core/Services/IMemberService.cs
+++ b/src/Umbraco.Core/Services/IMemberService.cs
@@ -35,5 +35,7 @@ namespace Umbraco.Core.Services
void Delete(IMember membershipUser);
void Save(IMember membershipUser);
+
+ IEnumerable FindMembersByEmail(string emailStringToMatch);
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/IMemberTypeService.cs b/src/Umbraco.Core/Services/IMemberTypeService.cs
new file mode 100644
index 0000000000..c2cbb8ab40
--- /dev/null
+++ b/src/Umbraco.Core/Services/IMemberTypeService.cs
@@ -0,0 +1,15 @@
+using System.Collections.Generic;
+using Umbraco.Core.Models;
+
+namespace Umbraco.Core.Services
+{
+ internal interface IMemberTypeService : IService
+ {
+ ///
+ /// Gets a list of all available objects
+ ///
+ /// Optional list of ids
+ /// An Enumerable list of objects
+ IEnumerable GetAllMemberTypes(params int[] ids);
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/MemberService.cs b/src/Umbraco.Core/Services/MemberService.cs
index 914ef70e60..87eee84863 100644
--- a/src/Umbraco.Core/Services/MemberService.cs
+++ b/src/Umbraco.Core/Services/MemberService.cs
@@ -108,6 +108,25 @@ namespace Umbraco.Core.Services
}
}
+ ///
+ /// Does a search for members that contain the specified string in their email address
+ ///
+ ///
+ ///
+ public IEnumerable FindMembersByEmail(string emailStringToMatch)
+ {
+ var uow = _uowProvider.GetUnitOfWork();
+ using (var repository = _repositoryFactory.CreateMemberRepository(uow))
+ {
+ var query = new Query();
+
+
+ query.Where(member => member.Email.Contains(emailStringToMatch));
+
+ return repository.GetByQuery(query);
+ }
+ }
+
///
/// Gets a list of Members with a certain string property value
///
diff --git a/src/Umbraco.Core/Services/MemberTypeService.cs b/src/Umbraco.Core/Services/MemberTypeService.cs
new file mode 100644
index 0000000000..99b90b83d4
--- /dev/null
+++ b/src/Umbraco.Core/Services/MemberTypeService.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using Umbraco.Core.Models;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.UnitOfWork;
+
+namespace Umbraco.Core.Services
+{
+ internal class MemberTypeService : IMemberTypeService
+ {
+ private readonly IDatabaseUnitOfWorkProvider _uowProvider;
+ private readonly RepositoryFactory _repositoryFactory;
+
+ public MemberTypeService()
+ : this(new PetaPocoUnitOfWorkProvider(), new RepositoryFactory())
+ {}
+
+ public MemberTypeService(RepositoryFactory repositoryFactory)
+ : this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
+ { }
+
+ public MemberTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory)
+ {
+ if (provider == null) throw new ArgumentNullException("provider");
+ if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
+ _uowProvider = provider;
+ _repositoryFactory = repositoryFactory;
+ }
+
+ public IEnumerable GetAllMemberTypes(params int[] ids)
+ {
+ using (var repository = _repositoryFactory.CreateMemberTypeRepository(_uowProvider.GetUnitOfWork()))
+ {
+ return repository.GetAll(ids);
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/RelationService.cs b/src/Umbraco.Core/Services/RelationService.cs
index 83d09023ab..29a42da115 100644
--- a/src/Umbraco.Core/Services/RelationService.cs
+++ b/src/Umbraco.Core/Services/RelationService.cs
@@ -13,10 +13,10 @@ namespace Umbraco.Core.Services
{
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
private readonly RepositoryFactory _repositoryFactory;
- private readonly EntityService _entityService;
+ private readonly IEntityService _entityService;
public RelationService(IDatabaseUnitOfWorkProvider uowProvider, RepositoryFactory repositoryFactory,
- EntityService entityService)
+ IEntityService entityService)
{
_uowProvider = uowProvider;
_repositoryFactory = repositoryFactory;
diff --git a/src/Umbraco.Core/Services/ServiceContext.cs b/src/Umbraco.Core/Services/ServiceContext.cs
index cc850d94ba..b6ccfc3d81 100644
--- a/src/Umbraco.Core/Services/ServiceContext.cs
+++ b/src/Umbraco.Core/Services/ServiceContext.cs
@@ -12,41 +12,67 @@ namespace Umbraco.Core.Services
///
public class ServiceContext
{
- private Lazy _contentService;
- private Lazy _userService;
- private Lazy _memberService;
- private Lazy _mediaService;
- private Lazy _contentTypeService;
- private Lazy _dataTypeService;
- private Lazy _fileService;
- private Lazy _localizationService;
+ private Lazy _contentService;
+ private Lazy _userService;
+ private Lazy _memberService;
+ private Lazy _mediaService;
+ private Lazy _contentTypeService;
+ private Lazy _dataTypeService;
+ private Lazy _fileService;
+ private Lazy _localizationService;
private Lazy _packagingService;
private Lazy _serverRegistrationService;
- private Lazy _entityService;
+ private Lazy _entityService;
private Lazy _relationService;
+ private Lazy _memberTypeService;
- ///
- /// Constructor
- ///
- ///
- ///
- ///
- internal ServiceContext(IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider, IUnitOfWorkProvider fileUnitOfWorkProvider, BasePublishingStrategy publishingStrategy)
- {
- BuildServiceCache(dbUnitOfWorkProvider, fileUnitOfWorkProvider, publishingStrategy,
- //this needs to be lazy because when we create the service context it's generally before the
- //resolvers have been initialized!
- new Lazy(() => RepositoryResolver.Current.Factory));
- }
+ ///
+ /// public ctor - will generally just be used for unit testing
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ServiceContext(IContentService contentService, IMediaService mediaService, IContentTypeService contentTypeService, IDataTypeService dataTypeService, IFileService fileService, ILocalizationService localizationService, PackagingService packagingService, IEntityService entityService, RelationService relationService)
+ {
+ _contentService = new Lazy(() => contentService);
+ _mediaService = new Lazy(() => mediaService);
+ _contentTypeService = new Lazy(() => contentTypeService);
+ _dataTypeService = new Lazy(() => dataTypeService);
+ _fileService = new Lazy(() => fileService);
+ _localizationService = new Lazy(() => localizationService);
+ _packagingService = new Lazy(() => packagingService);
+ _entityService = new Lazy(() => entityService);
+ _relationService = new Lazy(() => relationService);
+ }
+
+ ///
+ /// Constructor used to instantiate the core services
+ ///
+ ///
+ ///
+ ///
+ internal ServiceContext(IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider, IUnitOfWorkProvider fileUnitOfWorkProvider, BasePublishingStrategy publishingStrategy)
+ {
+ BuildServiceCache(dbUnitOfWorkProvider, fileUnitOfWorkProvider, publishingStrategy,
+ //this needs to be lazy because when we create the service context it's generally before the
+ //resolvers have been initialized!
+ new Lazy(() => RepositoryResolver.Current.Factory));
+ }
///
/// Builds the various services
///
- private void BuildServiceCache(
- IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider,
- IUnitOfWorkProvider fileUnitOfWorkProvider,
- BasePublishingStrategy publishingStrategy,
- Lazy repositoryFactory)
+ private void BuildServiceCache(
+ IDatabaseUnitOfWorkProvider dbUnitOfWorkProvider,
+ IUnitOfWorkProvider fileUnitOfWorkProvider,
+ BasePublishingStrategy publishingStrategy,
+ Lazy repositoryFactory)
{
var provider = dbUnitOfWorkProvider;
var fileProvider = fileUnitOfWorkProvider;
@@ -54,38 +80,41 @@ namespace Umbraco.Core.Services
if (_serverRegistrationService == null)
_serverRegistrationService = new Lazy(() => new ServerRegistrationService(provider, repositoryFactory.Value));
- if (_userService == null)
- _userService = new Lazy(() => new UserService(provider, repositoryFactory.Value));
+ if (_userService == null)
+ _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));
if (_contentService == null)
- _contentService = new Lazy(() => new ContentService(provider, repositoryFactory.Value, publishingStrategy));
+ _contentService = new Lazy(() => new ContentService(provider, repositoryFactory.Value, publishingStrategy));
- if(_mediaService == null)
- _mediaService = new Lazy(() => new MediaService(provider, repositoryFactory.Value));
+ if (_mediaService == null)
+ _mediaService = new Lazy(() => new MediaService(provider, repositoryFactory.Value));
- if(_contentTypeService == null)
- _contentTypeService = new Lazy(() => new ContentTypeService(provider, repositoryFactory.Value, _contentService.Value, _mediaService.Value));
+ if (_contentTypeService == null)
+ _contentTypeService = new Lazy(() => new ContentTypeService(provider, repositoryFactory.Value, _contentService.Value, _mediaService.Value));
- if(_dataTypeService == null)
- _dataTypeService = new Lazy(() => new DataTypeService(provider, repositoryFactory.Value));
+ if (_dataTypeService == null)
+ _dataTypeService = new Lazy(() => new DataTypeService(provider, repositoryFactory.Value));
- if(_fileService == null)
- _fileService = new Lazy(() => new FileService(fileProvider, provider, repositoryFactory.Value));
+ if (_fileService == null)
+ _fileService = new Lazy(() => new FileService(fileProvider, provider, repositoryFactory.Value));
- if(_localizationService == null)
- _localizationService = new Lazy(() => new LocalizationService(provider, repositoryFactory.Value));
+ if (_localizationService == null)
+ _localizationService = new Lazy(() => new LocalizationService(provider, repositoryFactory.Value));
- if(_packagingService == null)
+ if (_packagingService == null)
_packagingService = new Lazy(() => new PackagingService(_contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _fileService.Value, _localizationService.Value, repositoryFactory.Value, provider));
if (_entityService == null)
- _entityService = new Lazy(() => new EntityService(provider, repositoryFactory.Value, _contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value));
+ _entityService = new Lazy(() => new EntityService(provider, repositoryFactory.Value, _contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value));
- if(_relationService == null)
+ if (_relationService == null)
_relationService = new Lazy(() => new RelationService(provider, repositoryFactory.Value, _entityService.Value));
+
+ if (_memberTypeService == null)
+ _memberTypeService = new Lazy(() => new MemberTypeService(provider, repositoryFactory.Value));
}
///
@@ -99,7 +128,7 @@ namespace Umbraco.Core.Services
///
/// Gets the
///
- public EntityService EntityService
+ public IEntityService EntityService
{
get { return _entityService.Value; }
}
@@ -125,7 +154,7 @@ namespace Umbraco.Core.Services
///
public IContentTypeService ContentTypeService
{
- get { return _contentTypeService.Value; }
+ get { return _contentTypeService.Value; }
}
///
@@ -133,7 +162,7 @@ namespace Umbraco.Core.Services
///
public IDataTypeService DataTypeService
{
- get { return _dataTypeService.Value; }
+ get { return _dataTypeService.Value; }
}
///
@@ -141,7 +170,7 @@ namespace Umbraco.Core.Services
///
public IFileService FileService
{
- get { return _fileService.Value; }
+ get { return _fileService.Value; }
}
///
@@ -149,7 +178,7 @@ namespace Umbraco.Core.Services
///
public ILocalizationService LocalizationService
{
- get { return _localizationService.Value; }
+ get { return _localizationService.Value; }
}
///
@@ -157,7 +186,7 @@ namespace Umbraco.Core.Services
///
public IMediaService MediaService
{
- get { return _mediaService.Value; }
+ get { return _mediaService.Value; }
}
///
@@ -173,7 +202,7 @@ namespace Umbraco.Core.Services
///
internal IUserService UserService
{
- get { return _userService.Value; }
+ get { return _userService.Value; }
}
///
@@ -183,5 +212,14 @@ namespace Umbraco.Core.Services
{
get { return _memberService.Value; }
}
+
+ ///
+ /// Gets the MemberTypeService
+ ///
+ internal IMemberTypeService MemberTypeService
+ {
+ get { return _memberTypeService.Value; }
+ }
+
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/TypeHelper.cs b/src/Umbraco.Core/TypeHelper.cs
index adda1d3298..efb525e575 100644
--- a/src/Umbraco.Core/TypeHelper.cs
+++ b/src/Umbraco.Core/TypeHelper.cs
@@ -203,6 +203,53 @@ namespace Umbraco.Core
});
}
+ ///
+ /// Returns all public properties including inherited properties even for interfaces
+ ///
+ ///
+ ///
+ ///
+ /// taken from http://stackoverflow.com/questions/358835/getproperties-to-return-all-properties-for-an-interface-inheritance-hierarchy
+ ///
+ public static PropertyInfo[] GetPublicProperties(Type type)
+ {
+ if (type.IsInterface)
+ {
+ var propertyInfos = new List();
+
+ var considered = new List();
+ var queue = new Queue();
+ considered.Add(type);
+ queue.Enqueue(type);
+ while (queue.Count > 0)
+ {
+ var subType = queue.Dequeue();
+ foreach (var subInterface in subType.GetInterfaces())
+ {
+ if (considered.Contains(subInterface)) continue;
+
+ considered.Add(subInterface);
+ queue.Enqueue(subInterface);
+ }
+
+ var typeProperties = subType.GetProperties(
+ BindingFlags.FlattenHierarchy
+ | BindingFlags.Public
+ | BindingFlags.Instance);
+
+ var newPropertyInfos = typeProperties
+ .Where(x => !propertyInfos.Contains(x));
+
+ propertyInfos.InsertRange(0, newPropertyInfos);
+ }
+
+ return propertyInfos.ToArray();
+ }
+
+ return type.GetProperties(BindingFlags.FlattenHierarchy
+ | BindingFlags.Public | BindingFlags.Instance);
+ }
+
///
/// Gets (and caches) discoverable in the current for a given .
///
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 80b700209b..6fbe7ddd12 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -235,6 +235,7 @@
+
@@ -737,16 +738,19 @@
+
+
+
diff --git a/src/Umbraco.Tests/MockTests.cs b/src/Umbraco.Tests/MockTests.cs
new file mode 100644
index 0000000000..be31d2dbf4
--- /dev/null
+++ b/src/Umbraco.Tests/MockTests.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Web;
+using NUnit.Framework;
+using Umbraco.Core;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.UnitOfWork;
+using Umbraco.Core.Services;
+using Moq;
+using Umbraco.Web;
+
+namespace Umbraco.Tests
+{
+ [TestFixture]
+ public class MockTests
+ {
+
+ [Test]
+ public void Can_Create_Empty_App_Context()
+ {
+ var appCtx = new ApplicationContext(false);
+ Assert.Pass();
+ }
+
+ [Test]
+ public void Can_Create_Service_Context()
+ {
+ var svcCtx = 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 RepositoryFactory(true),
+ new Mock().Object),
+ new Mock().Object,
+ new RelationService(
+ new Mock().Object,
+ new RepositoryFactory(true),
+ new Mock().Object));
+ Assert.Pass();
+ }
+
+ [Test]
+ public void Can_Create_Db_Context()
+ {
+ var dbCtx = new DatabaseContext(new Mock().Object);
+ Assert.Pass();
+ }
+
+ [Test]
+ public void Can_Create_App_Context_With_Services()
+ {
+ 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 RepositoryFactory(true),
+ new Mock().Object),
+ new Mock().Object,
+ new RelationService(
+ new Mock().Object,
+ new RepositoryFactory(true),
+ new Mock().Object)),
+ false);
+ Assert.Pass();
+ }
+
+ [Test]
+ public void Can_Assign_App_Context_Singleton()
+ {
+ var appCtx = new ApplicationContext(false);
+ var result = ApplicationContext.EnsureContext(appCtx, true);
+ Assert.AreEqual(appCtx, result);
+ }
+
+ [Test]
+ public void Does_Not_Overwrite_App_Context_Singleton()
+ {
+ ApplicationContext.EnsureContext(new ApplicationContext(false), true);
+ var appCtx = new ApplicationContext(false);
+ var result = ApplicationContext.EnsureContext(appCtx, false);
+ Assert.AreNotEqual(appCtx, result);
+ }
+
+ [NUnit.Framework.Ignore("Need to fix more stuff up, this is ignore because an exception occurs because it wants to ensure we have a resolver initialized - need to make that process better for testability")]
+ [Test]
+ public void Can_Get_Umbraco_Context()
+ {
+ var appCtx = new ApplicationContext(false);
+ ApplicationContext.EnsureContext(appCtx, true);
+
+ var umbCtx = UmbracoContext.EnsureContext(
+ new Mock().Object,
+ appCtx,
+ true);
+
+ Assert.AreEqual(umbCtx, UmbracoContext.Current);
+ }
+
+ }
+}
diff --git a/src/Umbraco.Tests/Auditing/AuditTests.cs b/src/Umbraco.Tests/Persistence/Auditing/AuditTests.cs
similarity index 92%
rename from src/Umbraco.Tests/Auditing/AuditTests.cs
rename to src/Umbraco.Tests/Persistence/Auditing/AuditTests.cs
index ff5e6bb164..68e7bcb003 100644
--- a/src/Umbraco.Tests/Auditing/AuditTests.cs
+++ b/src/Umbraco.Tests/Persistence/Auditing/AuditTests.cs
@@ -1,35 +1,35 @@
-using System.Linq;
-using NUnit.Framework;
-using Umbraco.Core.Auditing;
-using Umbraco.Core.Models.Rdbms;
-using Umbraco.Tests.TestHelpers;
-
-namespace Umbraco.Tests.Auditing
-{
- [TestFixture]
- public class AuditTests : BaseDatabaseFactoryTest
- {
- [SetUp]
- public override void Initialize()
- {
- base.Initialize();
- }
-
- [Test]
- public void Can_Add_Audit_Entry()
- {
- Audit.Add(AuditTypes.System, "This is a System audit trail", 0, -1);
-
- var dtos = DatabaseContext.Database.Fetch("WHERE id > -1");
-
- Assert.That(dtos.Any(), Is.True);
- Assert.That(dtos.First().Comment, Is.EqualTo("This is a System audit trail"));
- }
-
- [TearDown]
- public override void TearDown()
- {
- base.TearDown();
- }
- }
+using System.Linq;
+using NUnit.Framework;
+using Umbraco.Core.Auditing;
+using Umbraco.Core.Models.Rdbms;
+using Umbraco.Tests.TestHelpers;
+
+namespace Umbraco.Tests.Persistence.Auditing
+{
+ [TestFixture]
+ public class AuditTests : BaseDatabaseFactoryTest
+ {
+ [SetUp]
+ public override void Initialize()
+ {
+ base.Initialize();
+ }
+
+ [Test]
+ public void Can_Add_Audit_Entry()
+ {
+ Audit.Add(AuditTypes.System, "This is a System audit trail", 0, -1);
+
+ var dtos = DatabaseContext.Database.Fetch("WHERE id > -1");
+
+ Assert.That(dtos.Any(), Is.True);
+ Assert.That(dtos.First().Comment, Is.EqualTo("This is a System audit trail"));
+ }
+
+ [TearDown]
+ public override void TearDown()
+ {
+ base.TearDown();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs
index e7a7285f7d..f51e50b57a 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/MemberTypeRepositoryTest.cs
@@ -45,7 +45,7 @@ namespace Umbraco.Tests.Persistence.Repositories
}
[Test]
- public void MemberRepository_Can_Persist_Member()
+ public void MemberRepository_Can_Persist_Member_Type()
{
IMemberType sut;
var provider = new PetaPocoUnitOfWorkProvider();
@@ -67,6 +67,56 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
+ [Test]
+ public void MemberRepository_Can_Get_All_Member_Types()
+ {
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ using (var repository = CreateRepository(unitOfWork))
+ {
+ var memberType1 = MockedContentTypes.CreateSimpleMemberType();
+ repository.AddOrUpdate(memberType1);
+ unitOfWork.Commit();
+
+ var memberType2 = MockedContentTypes.CreateSimpleMemberType();
+ memberType2.Name = "AnotherType";
+ memberType2.Alias = "anotherType";
+ repository.AddOrUpdate(memberType2);
+ unitOfWork.Commit();
+
+ var result = repository.GetAll();
+
+ //there are 3 because of the Member type created for init data
+ Assert.AreEqual(3, result.Count());
+ }
+ }
+
+ [Test]
+ public void MemberRepository_Can_Get_All_Member_When_No_Properties()
+ {
+ var provider = new PetaPocoUnitOfWorkProvider();
+ var unitOfWork = provider.GetUnitOfWork();
+ using (var repository = CreateRepository(unitOfWork))
+ {
+ var memberType1 = MockedContentTypes.CreateSimpleMemberType();
+ memberType1.PropertyTypeCollection.Clear();
+ repository.AddOrUpdate(memberType1);
+ unitOfWork.Commit();
+
+ var memberType2 = MockedContentTypes.CreateSimpleMemberType();
+ memberType2.PropertyTypeCollection.Clear();
+ memberType2.Name = "AnotherType";
+ memberType2.Alias = "anotherType";
+ repository.AddOrUpdate(memberType2);
+ unitOfWork.Commit();
+
+ var result = repository.GetAll();
+
+ //there are 3 because of the Member type created for init data
+ Assert.AreEqual(3, result.Count());
+ }
+ }
+
[Test, NUnit.Framework.Ignore]
public void MemberTypeRepository_Can_Get_MemberType_By_Id()
{
diff --git a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
index 2b00ea75cf..4b13acf7ee 100644
--- a/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
+++ b/src/Umbraco.Tests/Routing/RenderRouteHandlerTests.cs
@@ -3,8 +3,8 @@ using System.Web.Routing;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
-using Umbraco.Tests.Stubs;
using Umbraco.Tests.TestHelpers;
+using Umbraco.Tests.TestHelpers.Stubs;
using Umbraco.Web;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
diff --git a/src/Umbraco.Tests/Routing/uQueryGetNodeIdByUrlTests.cs b/src/Umbraco.Tests/Routing/uQueryGetNodeIdByUrlTests.cs
index 24bc912f91..53d5301246 100644
--- a/src/Umbraco.Tests/Routing/uQueryGetNodeIdByUrlTests.cs
+++ b/src/Umbraco.Tests/Routing/uQueryGetNodeIdByUrlTests.cs
@@ -3,9 +3,9 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
-using Umbraco.Tests.Stubs;
using Umbraco.Tests.TestHelpers;
using System.Configuration;
+using Umbraco.Tests.TestHelpers.Stubs;
using Umbraco.Web;
using Umbraco.Web.PublishedCache.XmlPublishedCache;
using Umbraco.Web.Routing;
diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
index 82a332bc4c..755c6e5714 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs
@@ -21,7 +21,6 @@ using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
-using Umbraco.Tests.Stubs;
using Umbraco.Web;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.PublishedCache.XmlPublishedCache;
diff --git a/src/Umbraco.Tests/TestHelpers/BaseRoutingTest.cs b/src/Umbraco.Tests/TestHelpers/BaseRoutingTest.cs
index ab787bf105..d55a437976 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseRoutingTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseRoutingTest.cs
@@ -4,7 +4,7 @@ using System.Web.Routing;
using NUnit.Framework;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
-using Umbraco.Tests.Stubs;
+using Umbraco.Tests.TestHelpers.Stubs;
using Umbraco.Web;
using Umbraco.Web.PublishedCache.XmlPublishedCache;
using Umbraco.Web.Routing;
diff --git a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs
index 064e48dd7f..26c77d66e4 100644
--- a/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs
+++ b/src/Umbraco.Tests/TestHelpers/BaseWebTest.cs
@@ -14,7 +14,6 @@ using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
using Umbraco.Tests.PublishedContent;
-using Umbraco.Tests.Stubs;
using Umbraco.Web;
using Umbraco.Web.Routing;
using umbraco.BusinessLogic;
diff --git a/src/Umbraco.Tests/Stubs/FakeLastChanceFinder.cs b/src/Umbraco.Tests/TestHelpers/Stubs/FakeLastChanceFinder.cs
similarity index 81%
rename from src/Umbraco.Tests/Stubs/FakeLastChanceFinder.cs
rename to src/Umbraco.Tests/TestHelpers/Stubs/FakeLastChanceFinder.cs
index 9090909baa..c9f5dbe024 100644
--- a/src/Umbraco.Tests/Stubs/FakeLastChanceFinder.cs
+++ b/src/Umbraco.Tests/TestHelpers/Stubs/FakeLastChanceFinder.cs
@@ -1,12 +1,12 @@
-using Umbraco.Web.Routing;
-
-namespace Umbraco.Tests.Stubs
-{
- internal class FakeLastChanceFinder : IContentFinder
- {
- public bool TryFindContent(PublishedContentRequest docRequest)
- {
- return false;
- }
- }
+using Umbraco.Web.Routing;
+
+namespace Umbraco.Tests.TestHelpers.Stubs
+{
+ internal class FakeLastChanceFinder : IContentFinder
+ {
+ public bool TryFindContent(PublishedContentRequest docRequest)
+ {
+ return false;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Stubs/TestControllerFactory.cs b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
similarity index 94%
rename from src/Umbraco.Tests/Stubs/TestControllerFactory.cs
rename to src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
index 872093f896..5796ee5bc3 100644
--- a/src/Umbraco.Tests/Stubs/TestControllerFactory.cs
+++ b/src/Umbraco.Tests/TestHelpers/Stubs/TestControllerFactory.cs
@@ -1,40 +1,40 @@
-using System;
-using System.Linq;
-using System.Reflection;
-using System.Web.Mvc;
-using System.Web.Routing;
-using System.Web.SessionState;
-using Umbraco.Core;
-
-namespace Umbraco.Tests.Stubs
-{
- ///
- /// Used in place of the UmbracoControllerFactory which relies on BuildManager which throws exceptions in a unit test context
- ///
- internal class TestControllerFactory : IControllerFactory
- {
-
- public IController CreateController(RequestContext requestContext, string controllerName)
- {
- var types = TypeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() });
-
- var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase));
- var t = controllerTypes.SingleOrDefault();
-
- if (t == null)
- return null;
-
- return Activator.CreateInstance(t) as IController;
- }
-
- public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
- {
- return SessionStateBehavior.Disabled;
- }
-
- public void ReleaseController(IController controller)
- {
- controller.DisposeIfDisposable();
- }
- }
+using System;
+using System.Linq;
+using System.Reflection;
+using System.Web.Mvc;
+using System.Web.Routing;
+using System.Web.SessionState;
+using Umbraco.Core;
+
+namespace Umbraco.Tests.TestHelpers.Stubs
+{
+ ///
+ /// Used in place of the UmbracoControllerFactory which relies on BuildManager which throws exceptions in a unit test context
+ ///
+ internal class TestControllerFactory : IControllerFactory
+ {
+
+ public IController CreateController(RequestContext requestContext, string controllerName)
+ {
+ var types = TypeFinder.FindClassesOfType(new[] { Assembly.GetExecutingAssembly() });
+
+ var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase));
+ var t = controllerTypes.SingleOrDefault();
+
+ if (t == null)
+ return null;
+
+ return Activator.CreateInstance(t) as IController;
+ }
+
+ public System.Web.SessionState.SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
+ {
+ return SessionStateBehavior.Disabled;
+ }
+
+ public void ReleaseController(IController controller)
+ {
+ controller.DisposeIfDisposable();
+ }
+ }
}
\ No newline at end of file
diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj
index a11556edba..1e344fc47d 100644
--- a/src/Umbraco.Tests/Umbraco.Tests.csproj
+++ b/src/Umbraco.Tests/Umbraco.Tests.csproj
@@ -144,7 +144,8 @@
-
+
+
@@ -359,7 +360,7 @@
-
+
@@ -395,7 +396,7 @@
-
+
diff --git a/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs b/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs
index b02ed4ecf2..811fc6be52 100644
--- a/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs
+++ b/src/Umbraco.Web/Security/Providers/MembersMembershipProvider.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Specialized;
+using System.ComponentModel.DataAnnotations;
using System.Configuration.Provider;
+using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
@@ -8,6 +10,7 @@ using System.Web.Hosting;
using System.Web.Security;
using Umbraco.Core;
using Umbraco.Core.Logging;
+using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Models.Membership;
@@ -254,8 +257,9 @@ namespace Umbraco.Web.Security.Providers
}
///
- /// Adds a new membership user to the data source.
+ /// Adds a new membership user to the data source with the specified member type
///
+ /// A specific member type to create the member for
/// The user name for the new user.
/// The password for the new user.
/// The e-mail address for the new user.
@@ -267,16 +271,16 @@ namespace Umbraco.Web.Security.Providers
///
/// A object populated with the information for the newly created user.
///
- public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer,
+ public MembershipUser CreateUser(string memberType, string username, string password, string email, string passwordQuestion, string passwordAnswer,
bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
- LogHelper.Debug("Member signup requested: username -> " + username + ". email -> " +email);
+ LogHelper.Debug("Member signup requested: username -> " + username + ". email -> " + email);
// Validate password
if (IsPasswordValid(password) == false)
{
- status = MembershipCreateStatus.InvalidPassword;
- return null;
+ status = MembershipCreateStatus.InvalidPassword;
+ return null;
}
// Validate email
@@ -324,18 +328,41 @@ namespace Umbraco.Web.Security.Providers
return null;
}
- var member = MemberService.CreateMember(email, username, password, DefaultMemberTypeAlias);
+ var member = MemberService.CreateMember(email, username, password, memberType);
member.IsApproved = isApproved;
member.PasswordQuestion = passwordQuestion;
member.PasswordAnswer = passwordAnswer;
-
+
+ //encrypts/hashes the password depending on the settings
+ member.Password = EncryptOrHashPassword(member.Password);
+
MemberService.Save(member);
-
+
status = MembershipCreateStatus.Success;
return member.AsConcreteMembershipUser();
}
+ ///
+ /// Adds a new membership user to the data source.
+ ///
+ /// The user name for the new user.
+ /// The password for the new user.
+ /// The e-mail address for the new user.
+ /// The password question for the new user.
+ /// The password answer for the new user
+ /// Whether or not the new user is approved to be validated.
+ /// The unique identifier from the membership data source for the user.
+ /// A enumeration value indicating whether the user was created successfully.
+ ///
+ /// A object populated with the information for the newly created user.
+ ///
+ public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer,
+ bool isApproved, object providerUserKey, out MembershipCreateStatus status)
+ {
+ return CreateUser(DefaultMemberTypeAlias, username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
+ }
+
///
/// Processes a request to update the password question and answer for a membership user.
///
@@ -360,7 +387,7 @@ namespace Umbraco.Web.Security.Providers
}
var member = MemberService.GetByUsername(username);
- var encodedPassword = EncodePassword(password);
+ var encodedPassword = EncryptOrHashPassword(password);
if (member.Password == encodedPassword)
{
@@ -427,12 +454,12 @@ namespace Umbraco.Web.Security.Providers
var member = MemberService.GetByUsername(username);
if (member == null) return false;
- var encodedPassword = EncodePassword(oldPassword);
+ var encodedPassword = EncryptOrHashPassword(oldPassword);
if (member.Password == encodedPassword)
{
- member.Password = EncodePassword(newPassword);
+ member.Password = EncryptOrHashPassword(newPassword);
MemberService.Save(member);
return true;
@@ -464,7 +491,7 @@ namespace Umbraco.Web.Security.Providers
if (_requiresQuestionAndAnswer == false || (_requiresQuestionAndAnswer && answer == member.PasswordAnswer))
{
member.Password =
- EncodePassword(Membership.GeneratePassword(_minRequiredPasswordLength,
+ EncryptOrHashPassword(Membership.GeneratePassword(_minRequiredPasswordLength,
_minRequiredNonAlphanumericCharacters));
MemberService.Save(member);
}
@@ -505,7 +532,7 @@ namespace Umbraco.Web.Security.Providers
if (member.IsLockedOut)
throw new ProviderException("The member is locked out.");
- var encodedPassword = EncodePassword(password);
+ var encodedPassword = EncryptOrHashPassword(password);
var authenticated = (encodedPassword == member.Password);
@@ -687,7 +714,16 @@ namespace Umbraco.Web.Security.Providers
///
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
- throw new System.NotImplementedException();
+ var byEmail = MemberService.FindMembersByEmail(emailToMatch).ToArray();
+ totalRecords = byEmail.Length;
+ var pagedResult = new PagedResult(totalRecords, pageIndex, pageSize);
+
+ var collection = new MembershipUserCollection();
+ foreach (var m in byEmail.Skip(pagedResult.SkipSize).Take(pageSize))
+ {
+ collection.Add(m.AsConcreteMembershipUser());
+ }
+ return collection;
}
#region Private methods
@@ -714,11 +750,9 @@ namespace Umbraco.Web.Security.Providers
private bool IsEmaiValid(string email)
{
- const string pattern = @"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
- + @"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?
@@ -726,7 +760,7 @@ namespace Umbraco.Web.Security.Providers
///
/// The password.
/// The encoded password.
- private string EncodePassword(string password)
+ private string EncryptOrHashPassword(string password)
{
var encodedPassword = password;
switch (PasswordFormat)
diff --git a/src/umbraco.cms/businesslogic/Dictionary.cs b/src/umbraco.cms/businesslogic/Dictionary.cs
index 7a655f8373..e524f90429 100644
--- a/src/umbraco.cms/businesslogic/Dictionary.cs
+++ b/src/umbraco.cms/businesslogic/Dictionary.cs
@@ -2,8 +2,10 @@ using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Data;
+using System.Threading;
using System.Xml;
using System.Linq;
+using Umbraco.Core;
using umbraco.cms.businesslogic.language;
using umbraco.DataLayer;
using umbraco.BusinessLogic;
@@ -19,7 +21,7 @@ namespace umbraco.cms.businesslogic
public class Dictionary
{
private static volatile bool _cacheIsEnsured = false;
- private static readonly object Locker = new object();
+ private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
private static readonly ConcurrentDictionary DictionaryItems = new ConcurrentDictionary();
private static readonly Guid TopLevelParent = new Guid("41c7638d-f529-4bff-853e-59a0c2fb1bde");
@@ -33,30 +35,28 @@ namespace umbraco.cms.businesslogic
///
private static void EnsureCache()
{
- if (!_cacheIsEnsured)
+ using (var lck = new UpgradeableReadLock(Locker))
{
- lock (Locker)
+ if (_cacheIsEnsured) return;
+
+ lck.UpgradeToWriteLock();
+
+ using (var dr = SqlHelper.ExecuteReader("Select pk, id, [key], parent from cmsDictionary"))
{
- if (!_cacheIsEnsured)
+ while (dr.Read())
{
- using (IRecordsReader dr = SqlHelper.ExecuteReader("Select pk, id, [key], parent from cmsDictionary"))
- {
- while (dr.Read())
- {
- //create new dictionaryitem object and put in cache
- var item = new DictionaryItem(dr.GetInt("pk"),
- dr.GetString("key"),
- dr.GetGuid("id"),
- dr.GetGuid("parent"));
+ //create new dictionaryitem object and put in cache
+ var item = new DictionaryItem(dr.GetInt("pk"),
+ dr.GetString("key"),
+ dr.GetGuid("id"),
+ dr.GetGuid("parent"));
- DictionaryItems.TryAdd(item.key, item);
- }
- }
-
- _cacheIsEnsured = true;
+ DictionaryItems.TryAdd(item.key, item);
}
}
- }
+
+ _cacheIsEnsured = true;
+ }
}
///
@@ -64,9 +64,12 @@ namespace umbraco.cms.businesslogic
///
internal static void ClearCache()
{
- DictionaryItems.Clear();
- //ensure the flag is reset so that EnsureCache will re-cache everything
- _cacheIsEnsured = false;
+ using (new WriteLock(Locker))
+ {
+ DictionaryItems.Clear();
+ //ensure the flag is reset so that EnsureCache will re-cache everything
+ _cacheIsEnsured = false;
+ }
}
///
diff --git a/src/umbraco.cms/businesslogic/member/Member.cs b/src/umbraco.cms/businesslogic/member/Member.cs
index 947330b292..3a2389d35b 100644
--- a/src/umbraco.cms/businesslogic/member/Member.cs
+++ b/src/umbraco.cms/businesslogic/member/Member.cs
@@ -30,8 +30,8 @@ namespace umbraco.cms.businesslogic.member
public class Member : Content
{
#region Constants and static members
- public static readonly string UmbracoMemberProviderName = "UmbracoMembershipProvider";
- public static readonly string UmbracoRoleProviderName = "UmbracoRoleProvider";
+ public static readonly string UmbracoMemberProviderName = Constants.Conventions.Member.UmbracoMemberProviderName;
+ public static readonly string UmbracoRoleProviderName = Constants.Conventions.Member.UmbracoRoleProviderName;
public static readonly Guid _objectType = new Guid(Constants.ObjectTypes.Member);
private static readonly object m_Locker = new object();
@@ -211,6 +211,8 @@ namespace umbraco.cms.businesslogic.member
/// The new member
public static Member MakeNew(string Name, string LoginName, string Email, MemberType mbt, User u)
{
+ if (mbt == null) throw new ArgumentNullException("mbt");
+
var loginName = (!String.IsNullOrEmpty(LoginName)) ? LoginName : Name;
if (String.IsNullOrEmpty(loginName))
diff --git a/src/umbraco.providers/members/MembersMembershipProvider.cs b/src/umbraco.providers/members/MembersMembershipProvider.cs
index 0572613d78..b9dc4872a7 100644
--- a/src/umbraco.providers/members/MembersMembershipProvider.cs
+++ b/src/umbraco.providers/members/MembersMembershipProvider.cs
@@ -1,20 +1,26 @@
#region namespace
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
using System.Web.Security;
using System.Configuration;
+using Umbraco.Core;
+using Umbraco.Core.Models;
using umbraco.BusinessLogic;
using System.Security.Cryptography;
using System.Web.Util;
using System.Collections.Specialized;
using System.Configuration.Provider;
using umbraco.cms.businesslogic;
-using umbraco.cms.businesslogic.member;
-
using System.Security;
using System.Security.Permissions;
using System.Runtime.CompilerServices;
+using Member = umbraco.cms.businesslogic.member.Member;
+using MemberType = umbraco.cms.businesslogic.member.MemberType;
+using Umbraco.Core.Models.Membership;
+using User = umbraco.BusinessLogic.User;
+
#endregion
namespace umbraco.providers.members
@@ -354,6 +360,68 @@ namespace umbraco.providers.members
}
}
+ ///
+ /// Adds a new membership user to the data source.
+ ///
+ ///
+ /// The user name for the new user.
+ /// The password for the new user.
+ /// The e-mail address for the new user.
+ /// The password question for the new user.
+ /// The password answer for the new user
+ /// Whether or not the new user is approved to be validated.
+ /// The unique identifier from the membership data source for the user.
+ /// A enumeration value indicating whether the user was created successfully.
+ ///
+ /// A object populated with the information for the newly created user.
+ ///
+ public MembershipUser CreateUser(string memberTypeAlias, string username, string password, string email, string passwordQuestion,
+ string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
+ {
+ if (Member.GetMemberFromLoginName(username) != null)
+ status = MembershipCreateStatus.DuplicateUserName;
+ else if (Member.GetMemberFromEmail(email) != null && RequiresUniqueEmail)
+ status = MembershipCreateStatus.DuplicateEmail;
+ else
+ {
+ var memberType = MemberType.GetByAlias(memberTypeAlias);
+ if (memberType == null)
+ {
+ throw new InvalidOperationException("Could not find a member type with alias " + memberTypeAlias + ". Ensure your membership provider configuration is up to date and that the default member type exists.");
+ }
+
+ Member m = Member.MakeNew(username, email, memberType, User.GetUser(0));
+ m.Password = password;
+
+ MembershipUser mUser =
+ ConvertToMembershipUser(m);
+
+ // custom fields
+ if (!String.IsNullOrEmpty(m_PasswordRetrievalQuestionPropertyTypeAlias))
+ UpdateMemberProperty(m, m_PasswordRetrievalQuestionPropertyTypeAlias, passwordQuestion);
+
+ if (!String.IsNullOrEmpty(m_PasswordRetrievalAnswerPropertyTypeAlias))
+ UpdateMemberProperty(m, m_PasswordRetrievalAnswerPropertyTypeAlias, passwordAnswer);
+
+ if (!String.IsNullOrEmpty(m_ApprovedPropertyTypeAlias))
+ UpdateMemberProperty(m, m_ApprovedPropertyTypeAlias, isApproved);
+
+ if (!String.IsNullOrEmpty(m_LastLoginPropertyTypeAlias))
+ {
+ mUser.LastActivityDate = DateTime.Now;
+ UpdateMemberProperty(m, m_LastLoginPropertyTypeAlias, mUser.LastActivityDate);
+ }
+
+ // save
+ m.Save();
+
+ status = MembershipCreateStatus.Success;
+
+ return mUser;
+ }
+ return null;
+ }
+
///
/// Adds a new membership user to the data source.
///
@@ -371,41 +439,7 @@ namespace umbraco.providers.members
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion,
string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
- if (Member.GetMemberFromLoginName(username) != null)
- status = MembershipCreateStatus.DuplicateUserName;
- else if (Member.GetMemberFromEmail(email) != null && RequiresUniqueEmail)
- status = MembershipCreateStatus.DuplicateEmail;
- else
- {
- Member m = Member.MakeNew(username, email, MemberType.GetByAlias(m_DefaultMemberTypeAlias), User.GetUser(0));
- m.Password = password;
-
- MembershipUser mUser =
- ConvertToMembershipUser(m);
-
- // custom fields
- if (!String.IsNullOrEmpty(m_PasswordRetrievalQuestionPropertyTypeAlias))
- UpdateMemberProperty(m, m_PasswordRetrievalQuestionPropertyTypeAlias, passwordQuestion);
-
- if (!String.IsNullOrEmpty(m_PasswordRetrievalAnswerPropertyTypeAlias))
- UpdateMemberProperty(m, m_PasswordRetrievalAnswerPropertyTypeAlias, passwordAnswer);
-
- if (!String.IsNullOrEmpty(m_ApprovedPropertyTypeAlias))
- UpdateMemberProperty(m, m_ApprovedPropertyTypeAlias, isApproved);
-
- if (!String.IsNullOrEmpty(m_LastLoginPropertyTypeAlias)) {
- mUser.LastActivityDate = DateTime.Now;
- UpdateMemberProperty(m, m_LastLoginPropertyTypeAlias, mUser.LastActivityDate);
- }
-
- // save
- m.Save();
-
- status = MembershipCreateStatus.Success;
-
- return mUser;
- }
- return null;
+ return CreateUser(m_DefaultMemberTypeAlias, username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);
}
///
@@ -439,7 +473,16 @@ namespace umbraco.providers.members
///
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
- throw new Exception("The method or operation is not implemented.");
+ var byEmail = ApplicationContext.Current.Services.MemberService.FindMembersByEmail(emailToMatch).ToArray();
+ totalRecords = byEmail.Length;
+ var pagedResult = new PagedResult(totalRecords, pageIndex, pageSize);
+
+ var collection = new MembershipUserCollection();
+ foreach (var m in byEmail.Skip(pagedResult.SkipSize).Take(pageSize))
+ {
+ collection.Add(m.AsConcreteMembershipUser());
+ }
+ return collection;
}
///
@@ -751,7 +794,7 @@ namespace umbraco.providers.members
return null;
}
-
+
///
/// Verifies that the specified user name and password exist in the data source.
///
@@ -973,6 +1016,7 @@ namespace umbraco.providers.members
DateTime.Now, DateTime.Now, DateTime.Now);
}
}
+
#endregion
}
}
diff --git a/src/umbraco.providers/umbraco.providers.csproj b/src/umbraco.providers/umbraco.providers.csproj
index 29e8df7ccc..7c6f3892eb 100644
--- a/src/umbraco.providers/umbraco.providers.csproj
+++ b/src/umbraco.providers/umbraco.providers.csproj
@@ -97,6 +97,10 @@
{ccd75ec3-63db-4184-b49d-51c1dd337230}
umbraco.cms
+
+ {31785bc3-256c-4613-b2f5-a1b0bdded8c1}
+ Umbraco.Core
+
{C7CB79F0-1C97-4B33-BFA7-00731B579AE2}
umbraco.datalayer
diff --git a/src/umbraco.sln b/src/umbraco.sln
index 2e6c017bee..0b7902d964 100644
--- a/src/umbraco.sln
+++ b/src/umbraco.sln
@@ -1,7 +1,5 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.20827.3
-MinimumVisualStudioVersion = 10.0.40219.1
+# Visual Studio 2012
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4-3B4E-40A3-A309-F3CB4F0E125F}"
ProjectSection(SolutionItems) = preProject
..\build\Build.bat = ..\build\Build.bat
@@ -159,4 +157,7 @@ Global
{73529637-28F5-419C-A6BB-D094E39DE614} = {DD32977B-EF54-475B-9A1B-B97A502C6E58}
{B555AAE6-0F56-442F-AC9F-EF497DB38DE7} = {DD32977B-EF54-475B-9A1B-B97A502C6E58}
EndGlobalSection
+ GlobalSection(Performance) = preSolution
+ HasPerformanceSessions = true
+ EndGlobalSection
EndGlobal