Merge branch '6.2.0' of https://github.com/umbraco/Umbraco-CMS into 6.2.0
This commit is contained in:
@@ -166,140 +166,84 @@ namespace Umbraco.Core
|
||||
|
||||
public const string FailedPasswordAttemptsLabel = "Failed Password Attempts";
|
||||
|
||||
internal static Dictionary<string, PropertyType>
|
||||
StandardPropertyTypeStubs = new Dictionary<string, PropertyType>
|
||||
{
|
||||
{
|
||||
Comments,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors
|
||||
.TextboxMultiple),
|
||||
DataTypeDatabaseType
|
||||
.Ntext)
|
||||
{
|
||||
Alias = Comments,
|
||||
Name =
|
||||
CommentsLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
FailedPasswordAttempts,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors
|
||||
.Integer),
|
||||
DataTypeDatabaseType
|
||||
.Integer)
|
||||
{
|
||||
Alias =
|
||||
FailedPasswordAttempts,
|
||||
Name =
|
||||
FailedPasswordAttemptsLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
IsApproved,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors
|
||||
.TrueFalse),
|
||||
DataTypeDatabaseType
|
||||
.Integer)
|
||||
{
|
||||
Alias = IsApproved,
|
||||
Name =
|
||||
IsApprovedLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
IsLockedOut,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors
|
||||
.TrueFalse),
|
||||
DataTypeDatabaseType
|
||||
.Integer)
|
||||
{
|
||||
Alias =
|
||||
IsLockedOut,
|
||||
Name =
|
||||
IsLockedOutLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
LastLockoutDate,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors.Date),
|
||||
DataTypeDatabaseType
|
||||
.Date)
|
||||
{
|
||||
Alias =
|
||||
LastLockoutDate,
|
||||
Name =
|
||||
LastLockoutDateLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
LastLoginDate,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors.Date),
|
||||
DataTypeDatabaseType
|
||||
.Date)
|
||||
{
|
||||
Alias =
|
||||
LastLoginDate,
|
||||
Name =
|
||||
LastLoginDateLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
LastPasswordChangeDate,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors.Date),
|
||||
DataTypeDatabaseType
|
||||
.Date)
|
||||
{
|
||||
Alias =
|
||||
LastPasswordChangeDate,
|
||||
Name =
|
||||
LastPasswordChangeDateLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordAnswer,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors
|
||||
.Textbox),
|
||||
DataTypeDatabaseType
|
||||
.Nvarchar)
|
||||
{
|
||||
Alias =
|
||||
PasswordAnswer,
|
||||
Name =
|
||||
PasswordAnswerLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordQuestion,
|
||||
new PropertyType(
|
||||
new Guid(
|
||||
PropertyEditors
|
||||
.Textbox),
|
||||
DataTypeDatabaseType
|
||||
.Nvarchar)
|
||||
{
|
||||
Alias =
|
||||
PasswordQuestion,
|
||||
Name =
|
||||
PasswordQuestionLabel
|
||||
}
|
||||
}
|
||||
};
|
||||
internal static Dictionary<string, PropertyType> GetStandardPropertyTypeStubs()
|
||||
{
|
||||
return new Dictionary<string, PropertyType>
|
||||
{
|
||||
{
|
||||
Comments,
|
||||
new PropertyType(new Guid(PropertyEditors.TextboxMultiple), DataTypeDatabaseType.Ntext)
|
||||
{
|
||||
Alias = Comments,
|
||||
Name = CommentsLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
FailedPasswordAttempts,
|
||||
new PropertyType(new Guid(PropertyEditors.Integer), DataTypeDatabaseType.Integer)
|
||||
{
|
||||
Alias = FailedPasswordAttempts,
|
||||
Name = FailedPasswordAttemptsLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
IsApproved,
|
||||
new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer)
|
||||
{
|
||||
Alias = IsApproved,
|
||||
Name = IsApprovedLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
IsLockedOut,
|
||||
new PropertyType(new Guid(PropertyEditors.TrueFalse), DataTypeDatabaseType.Integer)
|
||||
{
|
||||
Alias = IsLockedOut,
|
||||
Name = IsLockedOutLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
LastLockoutDate,
|
||||
new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date)
|
||||
{
|
||||
Alias = LastLockoutDate,
|
||||
Name = LastLockoutDateLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
LastLoginDate,
|
||||
new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date)
|
||||
{
|
||||
Alias = LastLoginDate,
|
||||
Name = LastLoginDateLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
LastPasswordChangeDate,
|
||||
new PropertyType(new Guid(PropertyEditors.Date), DataTypeDatabaseType.Date)
|
||||
{
|
||||
Alias = LastPasswordChangeDate,
|
||||
Name = LastPasswordChangeDateLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordAnswer,
|
||||
new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType.Nvarchar)
|
||||
{
|
||||
Alias = PasswordAnswer,
|
||||
Name = PasswordAnswerLabel
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordQuestion,
|
||||
new PropertyType(new Guid(PropertyEditors.Textbox), DataTypeDatabaseType.Nvarchar)
|
||||
{
|
||||
Alias = PasswordQuestion,
|
||||
Name = PasswordQuestionLabel
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -613,11 +613,16 @@ namespace Umbraco.Core.Models
|
||||
return ApplicationContext.Current.Services.PackagingService.Export(media);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the full xml representation for the <see cref="IMedia"/> object and all of it's descendants
|
||||
/// </summary>
|
||||
/// <param name="media"><see cref="IMedia"/> to generate xml for</param>
|
||||
/// <returns>Xml representation of the passed in <see cref="IMedia"/></returns>
|
||||
internal static XElement ToDeepXml(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.PackagingService.Export(media, true);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
@@ -630,5 +635,15 @@ namespace Umbraco.Core.Models
|
||||
//If current IContent is published we should get latest unpublished version
|
||||
return content.ToXml();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IMember"/> object
|
||||
/// </summary>
|
||||
/// <param name="member"><see cref="IMember"/> to generate xml for</param>
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
public static XElement ToXml(this IMember member)
|
||||
{
|
||||
return ApplicationContext.Current.Services.PackagingService.Export(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ namespace Umbraco.Core.Models
|
||||
_allowedContentTypes = new List<ContentTypeSort>();
|
||||
_propertyGroups = new PropertyGroupCollection();
|
||||
_propertyTypes = new PropertyTypeCollection();
|
||||
_propertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
@@ -54,6 +55,7 @@ namespace Umbraco.Core.Models
|
||||
_allowedContentTypes = new List<ContentTypeSort>();
|
||||
_propertyGroups = new PropertyGroupCollection();
|
||||
_propertyTypes = new PropertyTypeCollection();
|
||||
_propertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
_additionalData = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
@@ -428,8 +430,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (PropertyTypeExists(propertyType.Alias) == false)
|
||||
{
|
||||
_propertyTypes.Add(propertyType);
|
||||
_propertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
_propertyTypes.Add(propertyType);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,18 @@ namespace Umbraco.Core.Models
|
||||
private object _providerUserKey;
|
||||
private Type _userTypeKey;
|
||||
|
||||
public Member(string name, string email, string username, string password, int parentId, IMemberType contentType)
|
||||
/// <summary>
|
||||
/// Constructor for creating a Member object
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the content</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Member(string name, IMemberType contentType)
|
||||
: base(name, -1, contentType, new PropertyCollection())
|
||||
{
|
||||
_contentType = contentType;
|
||||
}
|
||||
|
||||
internal Member(string name, string email, string username, string password, int parentId, IMemberType contentType)
|
||||
: base(name, parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
@@ -31,8 +42,8 @@ namespace Umbraco.Core.Models
|
||||
_password = password;
|
||||
}
|
||||
|
||||
public Member(string name, string email, string username, string password, IContentBase parent, IMemberType contentType)
|
||||
: base(name, parent, contentType, new PropertyCollection())
|
||||
public Member(string name, string email, string username, string password, IMemberType contentType)
|
||||
: this(name, email, username, password, -1, contentType)
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
@@ -42,6 +53,17 @@ namespace Umbraco.Core.Models
|
||||
_password = password;
|
||||
}
|
||||
|
||||
//public Member(string name, string email, string username, string password, IContentBase parent, IMemberType contentType)
|
||||
// : base(name, parent, contentType, new PropertyCollection())
|
||||
//{
|
||||
// Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
// _contentType = contentType;
|
||||
// _email = email;
|
||||
// _username = username;
|
||||
// _password = password;
|
||||
//}
|
||||
|
||||
private static readonly PropertyInfo DefaultContentTypeAliasSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.ContentTypeAlias);
|
||||
private static readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Username);
|
||||
private static readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<Member, string>(x => x.Email);
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public DateTime DateRegistered { get; set; }
|
||||
|
||||
[Column("lastNotifiedDate")]
|
||||
[Constraint(Default = "getdate()")]
|
||||
public DateTime LastNotified { get; set; }
|
||||
|
||||
[Column("isActive")]
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
var propertyTypes = GetPropertyTypes(dto, memberType);
|
||||
//By Convention we add 9 stnd PropertyTypes - This is only here to support loading of types that didn't have these conventions before.
|
||||
var standardPropertyTypes = Constants.Conventions.Member.StandardPropertyTypeStubs;
|
||||
var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
|
||||
foreach (var standardPropertyType in standardPropertyTypes)
|
||||
{
|
||||
if(dto.PropertyTypes.Any(x => x.Alias.Equals(standardPropertyType.Key))) continue;
|
||||
|
||||
@@ -21,14 +21,18 @@ namespace Umbraco.Core.Persistence
|
||||
/// <summary>
|
||||
/// This will escape single @ symbols for peta poco values so it doesn't think it's a parameter
|
||||
/// </summary>
|
||||
/// <param name="db"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string EscapeAtSymbols(this Database db, string value)
|
||||
public static string EscapeAtSymbols(string value)
|
||||
{
|
||||
//this fancy regex will only match a single @ not a double, etc...
|
||||
var regex = new Regex("(?<!@)@(?!@)");
|
||||
return regex.Replace(value, "@@");
|
||||
if (value.Contains("@"))
|
||||
{
|
||||
//this fancy regex will only match a single @ not a double, etc...
|
||||
var regex = new Regex("(?<!@)@(?!@)");
|
||||
return regex.Replace(value, "@@");
|
||||
}
|
||||
return value;
|
||||
|
||||
}
|
||||
|
||||
public static void CreateTable<T>(this Database db)
|
||||
|
||||
@@ -64,13 +64,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
|
||||
public virtual string EscapeAtArgument(string exp)
|
||||
{
|
||||
/*if (exp.StartsWith("@"))
|
||||
return string.Concat("@", exp);*/
|
||||
|
||||
if (exp.Contains("@"))
|
||||
return exp.Replace("@", "@@");
|
||||
|
||||
return exp;
|
||||
return PetaPocoExtensions.EscapeAtSymbols(exp);
|
||||
}
|
||||
|
||||
public virtual bool ShouldQuoteValue(Type fieldType)
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
@@ -226,6 +228,39 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
|
||||
}
|
||||
|
||||
private string HandleStringComparison(string col, string val, string verb, TextColumnType columnType)
|
||||
{
|
||||
switch (verb)
|
||||
{
|
||||
case "Equals":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEqualComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "StartsWith":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnStartsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "EndsWith":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnEndsWithComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "Contains":
|
||||
return SqlSyntaxContext.SqlSyntaxProvider.GetStringColumnContainsComparison(col, EscapeAtArgument(RemoveQuote(val)), columnType);
|
||||
case "InvariantEquals":
|
||||
case "SqlEquals":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "Equals", columnType);
|
||||
case "InvariantStartsWith":
|
||||
case "SqlStartsWith":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "StartsWith", columnType);
|
||||
case "InvariantEndsWith":
|
||||
case "SqlEndsWith":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "EndsWith", columnType);
|
||||
case "InvariantContains":
|
||||
case "SqlContains":
|
||||
//recurse
|
||||
return HandleStringComparison(col, val, "Contains", columnType);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("verb");
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
List<Object> args = this.VisitExpressionList(m.Arguments);
|
||||
@@ -245,12 +280,31 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
return string.Format("upper({0})", r);
|
||||
case "ToLower":
|
||||
return string.Format("lower({0})", r);
|
||||
|
||||
case "StartsWith":
|
||||
return string.Format("upper({0}) like '{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString().ToUpper())));
|
||||
case "EndsWith":
|
||||
return string.Format("upper({0}) like '%{1}'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper()));
|
||||
case "Contains":
|
||||
return string.Format("{0} like '%{1}%'", r, EscapeAtArgument(RemoveQuote(args[0].ToString()).ToUpper()));
|
||||
case "Equals":
|
||||
case "SqlStartsWith":
|
||||
case "SqlEndsWith":
|
||||
case "SqlContains":
|
||||
case "SqlEquals":
|
||||
case "InvariantStartsWith":
|
||||
case "InvariantEndsWith":
|
||||
case "InvariantContains":
|
||||
case "InvariantEquals":
|
||||
//default
|
||||
var colType = TextColumnType.NVarchar;
|
||||
//then check if this arg has been passed in
|
||||
if (m.Arguments.Count > 1)
|
||||
{
|
||||
var colTypeArg = m.Arguments.FirstOrDefault(x => x is ConstantExpression && x.Type == typeof(TextColumnType));
|
||||
if (colTypeArg != null)
|
||||
{
|
||||
colType = (TextColumnType) ((ConstantExpression) colTypeArg).Value;
|
||||
}
|
||||
}
|
||||
return HandleStringComparison(r.ToString(), args[0].ToString(), m.Method.Name, colType);
|
||||
case "Substring":
|
||||
var startIndex = Int32.Parse(args[0].ToString()) + 1;
|
||||
if (args.Count == 2)
|
||||
|
||||
30
src/Umbraco.Core/Persistence/Querying/SqlStringExtensions.cs
Normal file
30
src/Umbraco.Core/Persistence/Querying/SqlStringExtensions.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
/// <summary>
|
||||
/// String extension methods used specifically to translate into SQL
|
||||
/// </summary>
|
||||
internal static class SqlStringExtensions
|
||||
{
|
||||
public static bool SqlContains(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantContains(txt);
|
||||
}
|
||||
|
||||
public static bool SqlEquals(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantEquals(txt);
|
||||
}
|
||||
|
||||
public static bool SqlStartsWith(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantStartsWith(txt);
|
||||
}
|
||||
|
||||
public static bool SqlEndsWith(this string str, string txt, TextColumnType columnType)
|
||||
{
|
||||
return str.InvariantEndsWith(txt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines how to match a string property value
|
||||
/// </summary>
|
||||
public enum StringPropertyMatchType
|
||||
{
|
||||
Exact,
|
||||
Contains,
|
||||
StartsWith,
|
||||
EndsWith
|
||||
}
|
||||
}
|
||||
8
src/Umbraco.Core/Persistence/Querying/TextColumnType.cs
Normal file
8
src/Umbraco.Core/Persistence/Querying/TextColumnType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Core.Persistence.Querying
|
||||
{
|
||||
public enum TextColumnType
|
||||
{
|
||||
NVarchar,
|
||||
NText
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Relators
|
||||
@@ -20,8 +21,12 @@ namespace Umbraco.Core.Persistence.Relators
|
||||
// Is this the same MemberReadOnlyDto as the current one we're processing
|
||||
if (Current != null && Current.UniqueId == a.UniqueId)
|
||||
{
|
||||
// Yes, just add this PropertyDataReadOnlyDto to the current MemberReadOnlyDto's collection
|
||||
Current.Properties.Add(p);
|
||||
//This property may already be added so we need to check for that
|
||||
if (Current.Properties.Any(x => x.Id == p.Id) == false)
|
||||
{
|
||||
// Yes, just add this PropertyDataReadOnlyDto to the current MemberReadOnlyDto's collection
|
||||
Current.Properties.Add(p);
|
||||
}
|
||||
|
||||
// Return null to indicate we're not done with this MemberReadOnlyDto yet
|
||||
return null;
|
||||
|
||||
@@ -22,14 +22,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private readonly IMemberTypeRepository _memberTypeRepository;
|
||||
|
||||
public MemberRepository(IDatabaseUnitOfWork work, IMemberTypeRepository memberTypeRepository) : base(work)
|
||||
public MemberRepository(IDatabaseUnitOfWork work, IMemberTypeRepository memberTypeRepository)
|
||||
: base(work)
|
||||
{
|
||||
if (memberTypeRepository == null) throw new ArgumentNullException("memberTypeRepository");
|
||||
_memberTypeRepository = memberTypeRepository;
|
||||
}
|
||||
|
||||
public MemberRepository(IDatabaseUnitOfWork work, IRepositoryCacheProvider cache, IMemberTypeRepository memberTypeRepository)
|
||||
: base(work, cache)
|
||||
{
|
||||
if (memberTypeRepository == null) throw new ArgumentNullException("memberTypeRepository");
|
||||
_memberTypeRepository = memberTypeRepository;
|
||||
}
|
||||
|
||||
@@ -104,11 +107,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
sql.Select("umbracoNode.*", "cmsContent.contentType", "cmsContentType.alias AS ContentTypeAlias", "cmsContentVersion.VersionId",
|
||||
"cmsContentVersion.VersionDate", "cmsContentVersion.LanguageLocale", "cmsMember.Email",
|
||||
"cmsMember.LoginName", "cmsMember.Password", "cmsPropertyData.id AS PropertyDataId", "cmsPropertyData.propertytypeid",
|
||||
"cmsMember.LoginName", "cmsMember.Password", "cmsPropertyData.id AS PropertyDataId", "cmsPropertyData.propertytypeid",
|
||||
"cmsPropertyData.dataDate", "cmsPropertyData.dataInt", "cmsPropertyData.dataNtext", "cmsPropertyData.dataNvarchar",
|
||||
"cmsPropertyType.id", "cmsPropertyType.Alias", "cmsPropertyType.Description",
|
||||
"cmsPropertyType.Name", "cmsPropertyType.mandatory", "cmsPropertyType.validationRegExp",
|
||||
"cmsPropertyType.helpText", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", "cmsPropertyType.propertyTypeGroupId",
|
||||
"cmsPropertyType.helpText", "cmsPropertyType.sortOrder AS PropertyTypeSortOrder", "cmsPropertyType.propertyTypeGroupId",
|
||||
"cmsPropertyType.dataTypeId", "cmsDataType.controlId", "cmsDataType.dbType")
|
||||
.From<NodeDto>()
|
||||
.InnerJoin<ContentDto>().On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
@@ -247,7 +250,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
property.Id = keyDictionary[property.PropertyTypeId];
|
||||
}
|
||||
|
||||
|
||||
((Member)entity).ResetDirtyProperties();
|
||||
}
|
||||
|
||||
@@ -256,8 +259,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Updates Modified date
|
||||
((Member)entity).UpdatingEntity();
|
||||
|
||||
var dirtyEntity = (ICanBeDirty)entity;
|
||||
|
||||
//Look up parent to get and set the correct Path and update SortOrder if ParentId has changed
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("ParentId"))
|
||||
if (dirtyEntity.IsPropertyDirty("ParentId"))
|
||||
{
|
||||
var parent = Database.First<NodeDto>("WHERE id = @ParentId", new { ParentId = ((IUmbracoEntity)entity).ParentId });
|
||||
((IUmbracoEntity)entity).Path = string.Concat(parent.Path, ",", entity.Id);
|
||||
@@ -293,13 +298,32 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//Updates the current version - cmsContentVersion
|
||||
//Assumes a Version guid exists and Version date (modified date) has been set/updated
|
||||
Database.Update(dto.ContentVersionDto);
|
||||
//Updates the cmsMember entry
|
||||
Database.Update(dto);
|
||||
|
||||
//Updates the cmsMember entry if it has changed
|
||||
var changedCols = new List<string>();
|
||||
if (dirtyEntity.IsPropertyDirty("Email"))
|
||||
{
|
||||
changedCols.Add("Email");
|
||||
}
|
||||
if (dirtyEntity.IsPropertyDirty("Username"))
|
||||
{
|
||||
changedCols.Add("LoginName");
|
||||
}
|
||||
// DO NOT update the password if it is null or empty
|
||||
if (dirtyEntity.IsPropertyDirty("Password") && entity.Password.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
changedCols.Add("Password");
|
||||
}
|
||||
//only update the changed cols
|
||||
if (changedCols.Count > 0)
|
||||
{
|
||||
Database.Update(dto, changedCols);
|
||||
}
|
||||
|
||||
//TODO ContentType for the Member entity
|
||||
|
||||
//Create the PropertyData for this version - cmsPropertyData
|
||||
var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
|
||||
var propertyFactory = new PropertyFactory(entity.ContentType, entity.Version, entity.Id);
|
||||
var keyDictionary = new Dictionary<int, int>();
|
||||
|
||||
//Add Properties
|
||||
@@ -333,8 +357,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
property.Id = keyDictionary[property.PropertyTypeId];
|
||||
}
|
||||
}
|
||||
|
||||
((ICanBeDirty)entity).ResetDirtyProperties();
|
||||
|
||||
dirtyEntity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
protected override void PersistDeletedItem(IMember entity)
|
||||
@@ -416,9 +440,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public bool Exists(string username)
|
||||
{
|
||||
var sql = new Sql();
|
||||
var escapedUserName = PetaPocoExtensions.EscapeAtSymbols(username);
|
||||
sql.Select("COUNT(*)")
|
||||
.From<MemberDto>()
|
||||
.Where<MemberDto>(x => x.LoginName == username);
|
||||
.Where<MemberDto>(x => x.LoginName == escapedUserName);
|
||||
|
||||
return Database.ExecuteScalar<int>(sql) > 0;
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
((MemberType)entity).AddingEntity();
|
||||
|
||||
//By Convention we add 9 stnd PropertyTypes to an Umbraco MemberType
|
||||
var standardPropertyTypes = Constants.Conventions.Member.StandardPropertyTypeStubs;
|
||||
var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
|
||||
foreach (var standardPropertyType in standardPropertyTypes)
|
||||
{
|
||||
entity.AddPropertyType(standardPropertyType.Value);
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
@@ -10,6 +11,11 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// </summary>
|
||||
public interface ISqlSyntaxProvider
|
||||
{
|
||||
string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType);
|
||||
string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType);
|
||||
string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType);
|
||||
string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType);
|
||||
|
||||
string GetQuotedTableName(string tableName);
|
||||
string GetQuotedColumnName(string columnName);
|
||||
string GetQuotedName(string name);
|
||||
|
||||
10
src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntax.cs
Normal file
10
src/Umbraco.Core/Persistence/SqlSyntax/MySqlSyntax.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the MySql SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class MySqlSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new MySqlSyntaxProvider(); } }
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,6 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the MySql SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class MySqlSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new MySqlSyntaxProvider(); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for MySql
|
||||
/// </summary>
|
||||
|
||||
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntax.cs
Normal file
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlCeSyntax.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql CE SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlCeSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlCeSyntaxProvider(); } }
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,10 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql CE SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlCeSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlCeSyntaxProvider(); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Ce
|
||||
/// </summary>
|
||||
@@ -67,6 +60,62 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
return indexType;
|
||||
}
|
||||
|
||||
public override string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEqualComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for = comparison with NText columns but allows this syntax
|
||||
return string.Format("{0} LIKE '{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnStartsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEndsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnContainsComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("[{0}]", tableName);
|
||||
|
||||
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntax.cs
Normal file
10
src/Umbraco.Core/Persistence/SqlSyntax/SqlServerSyntax.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql Server SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlServerSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlServerSyntaxProvider(); } }
|
||||
}
|
||||
}
|
||||
@@ -2,31 +2,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Static class that provides simple access to the Sql Server SqlSyntax Provider
|
||||
/// </summary>
|
||||
internal static class SqlServerSyntax
|
||||
{
|
||||
public static ISqlSyntaxProvider Provider { get { return new SqlServerSyntaxProvider(); } }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the version name of SQL server (i.e. the year 2008, 2005, etc...)
|
||||
/// </summary>
|
||||
internal enum SqlServerVersionName
|
||||
{
|
||||
Invalid = -1,
|
||||
V7 = 0,
|
||||
V2000 = 1,
|
||||
V2005 = 2,
|
||||
V2008 = 3,
|
||||
V2012 = 4,
|
||||
Other = 5
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents an SqlSyntaxProvider for Sql Server
|
||||
/// </summary>
|
||||
@@ -55,6 +34,62 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
/// </summary>
|
||||
internal Lazy<SqlServerVersionName> VersionName { get; set; }
|
||||
|
||||
public override string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEqualComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for = comparison with NText columns but allows this syntax
|
||||
return string.Format("{0} LIKE '{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnStartsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnEndsWithComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
switch (columnType)
|
||||
{
|
||||
case TextColumnType.NVarchar:
|
||||
return base.GetStringColumnContainsComparison(column, value, columnType);
|
||||
case TextColumnType.NText:
|
||||
//MSSQL doesn't allow for upper methods with NText columns
|
||||
return string.Format("{0} LIKE '%{1}%'", column, value);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("columnType");
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("[{0}]", tableName);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the version name of SQL server (i.e. the year 2008, 2005, etc...)
|
||||
/// </summary>
|
||||
internal enum SqlServerVersionName
|
||||
{
|
||||
Invalid = -1,
|
||||
V7 = 0,
|
||||
V2000 = 1,
|
||||
V2005 = 2,
|
||||
V2008 = 3,
|
||||
V2012 = 4,
|
||||
Other = 5
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
{
|
||||
@@ -102,6 +103,30 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
DbTypeMap.Set<byte[]>(DbType.Binary, BlobColumnDefinition);
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnEqualComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) = '{1}'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnStartsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) like '{1}%'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnEndsWithComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) like '%{1}'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetStringColumnContainsComparison(string column, string value, TextColumnType columnType)
|
||||
{
|
||||
//use the 'upper' method to always ensure strings are matched without case sensitivity no matter what the db setting.
|
||||
return string.Format("upper({0}) like '%{1}%'", column, value.ToUpper());
|
||||
}
|
||||
|
||||
public virtual string GetQuotedTableName(string tableName)
|
||||
{
|
||||
return string.Format("\"{0}\"", tableName);
|
||||
|
||||
@@ -10,7 +10,6 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -21,7 +20,7 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Represents the ContentType Service, which is an easy access to operations involving <see cref="IContentType"/>
|
||||
/// </summary>
|
||||
public class ContentTypeService : IContentTypeService
|
||||
public class ContentTypeService : ContentTypeServiceBase, IContentTypeService
|
||||
{
|
||||
private readonly RepositoryFactory _repositoryFactory;
|
||||
private readonly IContentService _contentService;
|
||||
@@ -147,48 +146,7 @@ namespace Umbraco.Core.Services
|
||||
private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes)
|
||||
{
|
||||
|
||||
var toUpdate = new List<IContentTypeBase>();
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
//we need to determine if we need to refresh the xml content in the database. This is to be done when:
|
||||
// - the item is not new (already existed in the db) AND
|
||||
// - a content type changes it's alias OR
|
||||
// - if a content type has it's property removed OR
|
||||
// - if a content type has a property whose alias has changed
|
||||
//here we need to check if the alias of the content type changed or if one of the properties was removed.
|
||||
var dirty = contentType as IRememberBeingDirty;
|
||||
if (dirty == null) continue;
|
||||
|
||||
//check if any property types have changed their aliases (and not new property types)
|
||||
var hasAnyPropertiesChangedAlias = contentType.PropertyTypes.Any(propType =>
|
||||
{
|
||||
var dirtyProperty = propType as IRememberBeingDirty;
|
||||
if (dirtyProperty == null) return false;
|
||||
return dirtyProperty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new'
|
||||
&& dirtyProperty.WasPropertyDirty("Alias"); //alias has changed
|
||||
});
|
||||
|
||||
if (dirty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new'
|
||||
&& (dirty.WasPropertyDirty("Alias") || dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") || hasAnyPropertiesChangedAlias))
|
||||
{
|
||||
//If the alias was changed then we only need to update the xml structures for content of the current content type.
|
||||
//If a property was deleted or a property alias was changed then we need to update the xml structures for any
|
||||
// content of the current content type and any of the content type's child content types.
|
||||
if (dirty.WasPropertyDirty("Alias")
|
||||
&& dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") == false && hasAnyPropertiesChangedAlias == false)
|
||||
{
|
||||
//if only the alias changed then only update the current content type
|
||||
toUpdate.Add(contentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if a property was deleted or alias changed, then update all content of the current content type
|
||||
// and all of it's desscendant doc types.
|
||||
toUpdate.AddRange(contentType.DescendantsAndSelf());
|
||||
}
|
||||
}
|
||||
}
|
||||
var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray();
|
||||
|
||||
if (toUpdate.Any())
|
||||
{
|
||||
|
||||
65
src/Umbraco.Core/Services/ContentTypeServiceBase.cs
Normal file
65
src/Umbraco.Core/Services/ContentTypeServiceBase.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
public class ContentTypeServiceBase
|
||||
{
|
||||
/// <summary>
|
||||
/// This is called after an content type is saved and is used to update the content xml structures in the database
|
||||
/// if they are required to be updated.
|
||||
/// </summary>
|
||||
/// <param name="contentTypes"></param>
|
||||
internal IEnumerable<IContentTypeBase> GetContentTypesForXmlUpdates(params IContentTypeBase[] contentTypes)
|
||||
{
|
||||
|
||||
var toUpdate = new List<IContentTypeBase>();
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
//we need to determine if we need to refresh the xml content in the database. This is to be done when:
|
||||
// - the item is not new (already existed in the db) AND
|
||||
// - a content type changes it's alias OR
|
||||
// - if a content type has it's property removed OR
|
||||
// - if a content type has a property whose alias has changed
|
||||
//here we need to check if the alias of the content type changed or if one of the properties was removed.
|
||||
var dirty = contentType as IRememberBeingDirty;
|
||||
if (dirty == null) continue;
|
||||
|
||||
//check if any property types have changed their aliases (and not new property types)
|
||||
var hasAnyPropertiesChangedAlias = contentType.PropertyTypes.Any(propType =>
|
||||
{
|
||||
var dirtyProperty = propType as IRememberBeingDirty;
|
||||
if (dirtyProperty == null) return false;
|
||||
return dirtyProperty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new'
|
||||
&& dirtyProperty.WasPropertyDirty("Alias"); //alias has changed
|
||||
});
|
||||
|
||||
if (dirty.WasPropertyDirty("HasIdentity") == false //ensure it's not 'new'
|
||||
&& (dirty.WasPropertyDirty("Alias") || dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") || hasAnyPropertiesChangedAlias))
|
||||
{
|
||||
//If the alias was changed then we only need to update the xml structures for content of the current content type.
|
||||
//If a property was deleted or a property alias was changed then we need to update the xml structures for any
|
||||
// content of the current content type and any of the content type's child content types.
|
||||
if (dirty.WasPropertyDirty("Alias")
|
||||
&& dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") == false && hasAnyPropertiesChangedAlias == false)
|
||||
{
|
||||
//if only the alias changed then only update the current content type
|
||||
toUpdate.Add(contentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
//if a property was deleted or alias changed, then update all content of the current content type
|
||||
// and all of it's desscendant doc types.
|
||||
toUpdate.AddRange(contentType.DescendantsAndSelf());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return toUpdate;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
@@ -19,37 +20,15 @@ namespace Umbraco.Core.Services
|
||||
IMember GetById(int id);
|
||||
IMember GetByKey(Guid id);
|
||||
IEnumerable<IMember> GetMembersByMemberType(string memberTypeAlias);
|
||||
IEnumerable<IMember> GetMembersByMemberType(int memberTypeId);
|
||||
IEnumerable<IMember> GetMembersByGroup(string memberGroupName);
|
||||
IEnumerable<IMember> GetAllMembers(params int[] ids);
|
||||
}
|
||||
|
||||
void DeleteMembersOfType(int memberTypeId);
|
||||
|
||||
/// <summary>
|
||||
/// Defines part of the MemberService, which is specific to methods used by the membership provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl.
|
||||
/// </remarks>
|
||||
internal interface IMembershipMemberService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a member with the username exists
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
bool Exists(string username);
|
||||
|
||||
IMember CreateMember(string username, string email, string password, string memberTypeAlias, int userId = 0);
|
||||
|
||||
IMember GetById(object id);
|
||||
|
||||
IMember GetByEmail(string email);
|
||||
|
||||
IMember GetByUsername(string login);
|
||||
|
||||
void Delete(IMember membershipUser);
|
||||
|
||||
void Save(IMember membershipUser);
|
||||
|
||||
IEnumerable<IMember> FindMembersByEmail(string emailStringToMatch);
|
||||
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, string value, StringPropertyMatchType matchType = StringPropertyMatchType.Exact);
|
||||
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, int value);
|
||||
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, bool value);
|
||||
IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, DateTime value);
|
||||
}
|
||||
}
|
||||
@@ -25,5 +25,35 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="alias">Alias of the <see cref="IMediaType"/> to retrieve</param>
|
||||
/// <returns><see cref="IMediaType"/></returns>
|
||||
IMemberType GetMemberType(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMemberType"/> object
|
||||
/// </summary>
|
||||
/// <param name="memberType"><see cref="IMemberType"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the ContentType</param>
|
||||
void Save(IMemberType memberType, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a collection of <see cref="IMemberType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="memberTypes">Collection of <see cref="IMemberType"/> to save</param>
|
||||
/// <param name="userId">Optional Id of the User saving the ContentTypes</param>
|
||||
void Save(IEnumerable<IMemberType> memberTypes, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a single <see cref="IMemberType"/> object
|
||||
/// </summary>
|
||||
/// <param name="memberType"><see cref="IMemberType"/> to delete</param>
|
||||
/// <remarks>Deleting a <see cref="IMemberType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IMemberType"/></remarks>
|
||||
/// <param name="userId">Optional Id of the User deleting the ContentType</param>
|
||||
void Delete(IMemberType memberType, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a collection of <see cref="IMemberType"/> objects
|
||||
/// </summary>
|
||||
/// <param name="memberTypes">Collection of <see cref="IMemberType"/> to delete</param>
|
||||
/// <remarks>Deleting a <see cref="IMemberType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IMemberType"/></remarks>
|
||||
/// <param name="userId">Optional Id of the User deleting the ContentTypes</param>
|
||||
void Delete(IEnumerable<IMemberType> memberTypes, int userId = 0);
|
||||
}
|
||||
}
|
||||
48
src/Umbraco.Core/Services/IMembershipMemberService.cs
Normal file
48
src/Umbraco.Core/Services/IMembershipMemberService.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines part of the MemberService, which is specific to methods used by the membership provider.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Idea is to have this is an isolated interface so that it can be easily 'replaced' in the membership provider impl.
|
||||
/// </remarks>
|
||||
internal interface IMembershipMemberService : IService
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if a member with the username exists
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <returns></returns>
|
||||
bool Exists(string username);
|
||||
|
||||
/// <summary>
|
||||
/// Creates and persists a new member
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="memberTypeAlias"></param>
|
||||
/// <returns></returns>
|
||||
IMember CreateMember(string username, string email, string password, string memberTypeAlias);
|
||||
|
||||
IMember GetById(object id);
|
||||
|
||||
IMember GetByEmail(string email);
|
||||
|
||||
IMember GetByUsername(string login);
|
||||
|
||||
void Delete(IMember membershipUser);
|
||||
|
||||
void Save(IMember membershipUser, bool raiseEvents = true);
|
||||
|
||||
void Save(IEnumerable<IMember> members, bool raiseEvents = true);
|
||||
|
||||
IEnumerable<IMember> FindMembersByEmail(string emailStringToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
|
||||
|
||||
IEnumerable<IMember> FindMembersByUsername(string login, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith);
|
||||
}
|
||||
}
|
||||
@@ -598,7 +598,7 @@ namespace Umbraco.Core.Services
|
||||
//The ContentType has to be removed from the composition somehow as it would otherwise break
|
||||
//Dbl.check+test that the ContentType's Id is removed from the ContentType2ContentType table
|
||||
var query = Query<IMedia>.Builder.Where(x => x.ContentTypeId == mediaTypeId);
|
||||
var contents = repository.GetByQuery(query);
|
||||
var contents = repository.GetByQuery(query).ToArray();
|
||||
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMedia>(contents), this))
|
||||
return;
|
||||
@@ -760,30 +760,31 @@ namespace Umbraco.Core.Services
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMedia>(medias), this))
|
||||
return;
|
||||
}
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
foreach (var media in medias)
|
||||
{
|
||||
media.CreatorId = userId;
|
||||
repository.AddOrUpdate(media);
|
||||
}
|
||||
|
||||
var mediaXml = new Dictionary<int, Lazy<XElement>>();
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMediaRepository(uow))
|
||||
{
|
||||
foreach (var media in medias)
|
||||
{
|
||||
media.CreatorId = userId;
|
||||
repository.AddOrUpdate(media);
|
||||
}
|
||||
//commit the whole lot in one go
|
||||
uow.Commit();
|
||||
|
||||
//commit the whole lot in one go
|
||||
uow.Commit();
|
||||
foreach (var media in medias)
|
||||
{
|
||||
CreateAndSaveMediaXml(media.ToXml(), media.Id, uow.Database);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var media in medias)
|
||||
{
|
||||
CreateAndSaveMediaXml(media.ToXml(), media.Id, uow.Database);
|
||||
}
|
||||
}
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMedia>(medias, false), this);
|
||||
|
||||
if(raiseEvents)
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMedia>(medias, false), this);
|
||||
|
||||
Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1);
|
||||
Audit.Add(AuditTypes.Save, "Save Media items performed by user", userId, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
@@ -17,6 +21,8 @@ namespace Umbraco.Core.Services
|
||||
private readonly RepositoryFactory _repositoryFactory;
|
||||
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
|
||||
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
public MemberService(RepositoryFactory repositoryFactory)
|
||||
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
|
||||
{
|
||||
@@ -108,6 +114,22 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of Members by their MemberType
|
||||
/// </summary>
|
||||
/// <param name="memberTypeId"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IMember> GetMembersByMemberType(int memberTypeId)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
repository.Get(memberTypeId);
|
||||
var query = Query<IMember>.Builder.Where(x => x.ContentTypeId == memberTypeId);
|
||||
var members = repository.GetByQuery(query);
|
||||
return members;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of Members by the MemberGroup they are part of
|
||||
/// </summary>
|
||||
@@ -134,20 +156,88 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteMembersOfType(int memberTypeId)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var uow = _uowProvider.GetUnitOfWork())
|
||||
{
|
||||
var repository = _repositoryFactory.CreateMemberRepository(uow);
|
||||
//NOTE What about content that has the contenttype as part of its composition?
|
||||
var query = Query<IMember>.Builder.Where(x => x.ContentTypeId == memberTypeId);
|
||||
var members = repository.GetByQuery(query).ToArray();
|
||||
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMember>(members), this))
|
||||
return;
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
//Permantly delete the member
|
||||
Delete(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does a search for members that contain the specified string in their email address
|
||||
/// </summary>
|
||||
/// <param name="emailStringToMatch"></param>
|
||||
/// <param name="matchType"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IMember> FindMembersByEmail(string emailStringToMatch)
|
||||
public IEnumerable<IMember> FindMembersByEmail(string emailStringToMatch, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
|
||||
{
|
||||
var query = new Query<IMember>();
|
||||
|
||||
switch (matchType)
|
||||
{
|
||||
case StringPropertyMatchType.Exact:
|
||||
query.Where(member => member.Email.Equals(emailStringToMatch));
|
||||
break;
|
||||
case StringPropertyMatchType.Contains:
|
||||
query.Where(member => member.Email.Contains(emailStringToMatch));
|
||||
break;
|
||||
case StringPropertyMatchType.StartsWith:
|
||||
query.Where(member => member.Email.StartsWith(emailStringToMatch));
|
||||
break;
|
||||
case StringPropertyMatchType.EndsWith:
|
||||
query.Where(member => member.Email.EndsWith(emailStringToMatch));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
}
|
||||
|
||||
query.Where(member => member.Email.Contains(emailStringToMatch));
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IMember> FindMembersByUsername(string login, StringPropertyMatchType matchType = StringPropertyMatchType.StartsWith)
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
|
||||
{
|
||||
var query = new Query<IMember>();
|
||||
|
||||
switch (matchType)
|
||||
{
|
||||
case StringPropertyMatchType.Exact:
|
||||
query.Where(member => member.Username.Equals(login));
|
||||
break;
|
||||
case StringPropertyMatchType.Contains:
|
||||
query.Where(member => member.Username.Contains(login));
|
||||
break;
|
||||
case StringPropertyMatchType.StartsWith:
|
||||
query.Where(member => member.Username.StartsWith(login));
|
||||
break;
|
||||
case StringPropertyMatchType.EndsWith:
|
||||
query.Where(member => member.Username.EndsWith(login));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
}
|
||||
|
||||
return repository.GetByQuery(query);
|
||||
}
|
||||
@@ -158,17 +248,51 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="matchType"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, string value)
|
||||
public IEnumerable<IMember> GetMembersByPropertyValue(string propertyTypeAlias, string value, StringPropertyMatchType matchType = StringPropertyMatchType.Exact)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query =
|
||||
Query<IMember>.Builder.Where(
|
||||
x =>
|
||||
((Member)x).PropertyTypeAlias == propertyTypeAlias &&
|
||||
(((Member)x).LongStringPropertyValue.Contains(value) ||
|
||||
((Member)x).ShortStringPropertyValue.Contains(value)));
|
||||
IQuery<IMember> query;
|
||||
|
||||
switch (matchType)
|
||||
{
|
||||
case StringPropertyMatchType.Exact:
|
||||
query =
|
||||
Query<IMember>.Builder.Where(
|
||||
x =>
|
||||
((Member) x).PropertyTypeAlias == propertyTypeAlias &&
|
||||
(((Member)x).LongStringPropertyValue.SqlEquals(value, TextColumnType.NText) ||
|
||||
((Member)x).ShortStringPropertyValue.SqlEquals(value, TextColumnType.NVarchar)));
|
||||
break;
|
||||
case StringPropertyMatchType.Contains:
|
||||
query =
|
||||
Query<IMember>.Builder.Where(
|
||||
x =>
|
||||
((Member) x).PropertyTypeAlias == propertyTypeAlias &&
|
||||
(((Member)x).LongStringPropertyValue.SqlContains(value, TextColumnType.NText) ||
|
||||
((Member)x).ShortStringPropertyValue.SqlContains(value, TextColumnType.NVarchar)));
|
||||
break;
|
||||
case StringPropertyMatchType.StartsWith:
|
||||
query =
|
||||
Query<IMember>.Builder.Where(
|
||||
x =>
|
||||
((Member) x).PropertyTypeAlias == propertyTypeAlias &&
|
||||
(((Member)x).LongStringPropertyValue.SqlStartsWith(value, TextColumnType.NText) ||
|
||||
((Member)x).ShortStringPropertyValue.SqlStartsWith(value, TextColumnType.NVarchar)));
|
||||
break;
|
||||
case StringPropertyMatchType.EndsWith:
|
||||
query =
|
||||
Query<IMember>.Builder.Where(
|
||||
x =>
|
||||
((Member) x).PropertyTypeAlias == propertyTypeAlias &&
|
||||
(((Member)x).LongStringPropertyValue.SqlEndsWith(value, TextColumnType.NText) ||
|
||||
((Member)x).ShortStringPropertyValue.SqlEndsWith(value, TextColumnType.NVarchar)));
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("matchType");
|
||||
}
|
||||
|
||||
var members = repository.GetByQuery(query);
|
||||
return members;
|
||||
@@ -243,15 +367,14 @@ namespace Umbraco.Core.Services
|
||||
#region IMembershipMemberService Implementation
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Member
|
||||
/// Creates and persists a new Member
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="password"></param>
|
||||
/// <param name="memberTypeAlias"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public IMember CreateMember(string email, string username, string password, string memberTypeAlias, int userId = 0)
|
||||
public IMember CreateMember(string email, string username, string password, string memberTypeAlias)
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
IMemberType memberType;
|
||||
@@ -308,7 +431,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(_uowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IMember>.Builder.Where(x => x.Email == email);
|
||||
var query = Query<IMember>.Builder.Where(x => x.Email.Equals(email));
|
||||
var member = repository.GetByQuery(query).FirstOrDefault();
|
||||
|
||||
return member;
|
||||
@@ -337,28 +460,239 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="member"></param>
|
||||
public void Delete(IMember member)
|
||||
{
|
||||
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs<IMember>(member), this))
|
||||
return;
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
|
||||
{
|
||||
repository.Delete(member);
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
Deleted.RaiseEvent(new DeleteEventArgs<IMember>(member, false), this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves an updated Member
|
||||
/// </summary>
|
||||
/// <param name="member"></param>
|
||||
public void Save(IMember member)
|
||||
/// <param name="raiseEvents"></param>
|
||||
public void Save(IMember member, bool raiseEvents = true)
|
||||
{
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(member), this))
|
||||
return;
|
||||
}
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(member);
|
||||
uow.Commit();
|
||||
|
||||
var xml = member.ToXml();
|
||||
CreateAndSaveMemberXml(xml, member.Id, uow.Database);
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMember>(member, false), this);
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<IMember> members, bool raiseEvents = true)
|
||||
{
|
||||
if (raiseEvents)
|
||||
{
|
||||
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMember>(members), this))
|
||||
return;
|
||||
}
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberRepository(uow))
|
||||
{
|
||||
foreach (var member in members)
|
||||
{
|
||||
repository.AddOrUpdate(member);
|
||||
}
|
||||
|
||||
//commit the whole lot in one go
|
||||
uow.Commit();
|
||||
|
||||
foreach (var member in members)
|
||||
{
|
||||
CreateAndSaveMemberXml(member.ToXml(), member.Id, uow.Database);
|
||||
}
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
Saved.RaiseEvent(new SaveEventArgs<IMember>(members, false), this);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds all xml content in the cmsContentXml table for all media
|
||||
/// </summary>
|
||||
/// <param name="memberTypeIds">
|
||||
/// Only rebuild the xml structures for the content type ids passed in, if none then rebuilds the structures
|
||||
/// for all members = USE WITH CARE!
|
||||
/// </param>
|
||||
/// <returns>True if publishing succeeded, otherwise False</returns>
|
||||
internal void RebuildXmlStructures(params int[] memberTypeIds)
|
||||
{
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var list = new List<IMember>();
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
|
||||
//First we're going to get the data that needs to be inserted before clearing anything, this
|
||||
//ensures that we don't accidentally leave the content xml table empty if something happens
|
||||
//during the lookup process.
|
||||
|
||||
if (memberTypeIds.Any() == false)
|
||||
{
|
||||
list.AddRange(GetAllMembers());
|
||||
}
|
||||
else
|
||||
{
|
||||
list.AddRange(memberTypeIds.SelectMany(GetMembersByMemberType));
|
||||
}
|
||||
|
||||
var xmlItems = new List<ContentXmlDto>();
|
||||
foreach (var c in list)
|
||||
{
|
||||
var xml = c.ToXml();
|
||||
xmlItems.Add(new ContentXmlDto { NodeId = c.Id, Xml = xml.ToString(SaveOptions.None) });
|
||||
}
|
||||
|
||||
//Ok, now we need to remove the data and re-insert it, we'll do this all in one transaction too.
|
||||
using (var tr = uow.Database.GetTransaction())
|
||||
{
|
||||
if (memberTypeIds.Any() == false)
|
||||
{
|
||||
//Remove all media records from the cmsContentXml table (DO NOT REMOVE Content/Members!)
|
||||
uow.Database.Execute(@"DELETE FROM cmsContentXml WHERE nodeId IN
|
||||
(SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml
|
||||
INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id
|
||||
WHERE nodeObjectType = @nodeObjectType)",
|
||||
new { nodeObjectType = Constants.ObjectTypes.Member });
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var id in memberTypeIds)
|
||||
{
|
||||
//first we'll clear out the data from the cmsContentXml table for this type
|
||||
uow.Database.Execute(@"delete from cmsContentXml where nodeId in
|
||||
(SELECT DISTINCT cmsContentXml.nodeId FROM cmsContentXml
|
||||
INNER JOIN umbracoNode ON cmsContentXml.nodeId = umbracoNode.id
|
||||
INNER JOIN cmsContent ON cmsContent.nodeId = umbracoNode.id
|
||||
WHERE nodeObjectType = @nodeObjectType AND cmsContent.contentType = @contentTypeId)",
|
||||
new { contentTypeId = id, nodeObjectType = Constants.ObjectTypes.Member });
|
||||
}
|
||||
}
|
||||
|
||||
//bulk insert it into the database
|
||||
uow.Database.BulkInsertRecords(xmlItems, tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateAndSaveMemberXml(XElement xml, int id, UmbracoDatabase db)
|
||||
{
|
||||
var poco = new ContentXmlDto { NodeId = id, Xml = xml.ToString(SaveOptions.None) };
|
||||
var exists = db.FirstOrDefault<ContentXmlDto>("WHERE nodeId = @Id", new { Id = id }) != null;
|
||||
int result = exists ? db.Update(poco) : Convert.ToInt32(db.Insert(poco));
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, DeleteEventArgs<IMember>> Deleting;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, DeleteEventArgs<IMember>> Deleted;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saving;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberService, SaveEventArgs<IMember>> Saved;
|
||||
|
||||
#endregion
|
||||
|
||||
///// <summary>
|
||||
///// A helper method that will create a basic/generic member for use with a generic membership provider
|
||||
///// </summary>
|
||||
///// <returns></returns>
|
||||
//internal static IMember CreateGenericMembershipProviderMember(string name, string email, string username, string password)
|
||||
//{
|
||||
// var identity = int.MaxValue;
|
||||
|
||||
// var memType = new MemberType(-1);
|
||||
// var propGroup = new PropertyGroup
|
||||
// {
|
||||
// Name = "Membership",
|
||||
// Id = --identity
|
||||
// };
|
||||
// propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TextboxAlias, DataTypeDatabaseType.Ntext)
|
||||
// {
|
||||
// Alias = Constants.Conventions.Member.Comments,
|
||||
// Name = Constants.Conventions.Member.CommentsLabel,
|
||||
// SortOrder = 0,
|
||||
// Id = --identity
|
||||
// });
|
||||
// propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer)
|
||||
// {
|
||||
// Alias = Constants.Conventions.Member.IsApproved,
|
||||
// Name = Constants.Conventions.Member.IsApprovedLabel,
|
||||
// SortOrder = 3,
|
||||
// Id = --identity
|
||||
// });
|
||||
// propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.TrueFalseAlias, DataTypeDatabaseType.Integer)
|
||||
// {
|
||||
// Alias = Constants.Conventions.Member.IsLockedOut,
|
||||
// Name = Constants.Conventions.Member.IsLockedOutLabel,
|
||||
// SortOrder = 4,
|
||||
// Id = --identity
|
||||
// });
|
||||
// propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date)
|
||||
// {
|
||||
// Alias = Constants.Conventions.Member.LastLockoutDate,
|
||||
// Name = Constants.Conventions.Member.LastLockoutDateLabel,
|
||||
// SortOrder = 5,
|
||||
// Id = --identity
|
||||
// });
|
||||
// propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date)
|
||||
// {
|
||||
// Alias = Constants.Conventions.Member.LastLoginDate,
|
||||
// Name = Constants.Conventions.Member.LastLoginDateLabel,
|
||||
// SortOrder = 6,
|
||||
// Id = --identity
|
||||
// });
|
||||
// propGroup.PropertyTypes.Add(new PropertyType(Constants.PropertyEditors.NoEditAlias, DataTypeDatabaseType.Date)
|
||||
// {
|
||||
// Alias = Constants.Conventions.Member.LastPasswordChangeDate,
|
||||
// Name = Constants.Conventions.Member.LastPasswordChangeDateLabel,
|
||||
// SortOrder = 7,
|
||||
// Id = --identity
|
||||
// });
|
||||
|
||||
// memType.PropertyGroups.Add(propGroup);
|
||||
|
||||
// return new Member(name, email, username, password, -1, memType);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Auditing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
@@ -8,25 +11,29 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
{
|
||||
internal class MemberTypeService : IMemberTypeService
|
||||
internal class MemberTypeService : ContentTypeServiceBase, IMemberTypeService
|
||||
{
|
||||
private readonly IDatabaseUnitOfWorkProvider _uowProvider;
|
||||
private readonly RepositoryFactory _repositoryFactory;
|
||||
private readonly IMemberService _memberService;
|
||||
|
||||
public MemberTypeService()
|
||||
: this(new PetaPocoUnitOfWorkProvider(), new RepositoryFactory())
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
|
||||
|
||||
public MemberTypeService(IMemberService memberService)
|
||||
: this(new PetaPocoUnitOfWorkProvider(), new RepositoryFactory(), memberService)
|
||||
{ }
|
||||
|
||||
public MemberTypeService(RepositoryFactory repositoryFactory)
|
||||
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory)
|
||||
public MemberTypeService(RepositoryFactory repositoryFactory, IMemberService memberService)
|
||||
: this(new PetaPocoUnitOfWorkProvider(), repositoryFactory, memberService)
|
||||
{ }
|
||||
|
||||
public MemberTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory)
|
||||
public MemberTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, IMemberService memberService)
|
||||
{
|
||||
if (provider == null) throw new ArgumentNullException("provider");
|
||||
if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
|
||||
_uowProvider = provider;
|
||||
_repositoryFactory = repositoryFactory;
|
||||
_memberService = memberService;
|
||||
}
|
||||
|
||||
public IEnumerable<IMemberType> GetAllMemberTypes(params int[] ids)
|
||||
@@ -66,5 +73,143 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(IMemberType memberType, int userId = 0)
|
||||
{
|
||||
if (SavingMemberType.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(memberType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow))
|
||||
{
|
||||
memberType.CreatorId = userId;
|
||||
repository.AddOrUpdate(memberType);
|
||||
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(memberType);
|
||||
}
|
||||
SavedMemberType.RaiseEvent(new SaveEventArgs<IMemberType>(memberType, false), this);
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<IMemberType> memberTypes, int userId = 0)
|
||||
{
|
||||
var asArray = memberTypes.ToArray();
|
||||
|
||||
if (SavingMemberType.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow))
|
||||
{
|
||||
foreach (var memberType in asArray)
|
||||
{
|
||||
memberType.CreatorId = userId;
|
||||
repository.AddOrUpdate(memberType);
|
||||
}
|
||||
|
||||
//save it all in one go
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
|
||||
}
|
||||
SavedMemberType.RaiseEvent(new SaveEventArgs<IMemberType>(asArray, false), this);
|
||||
}
|
||||
|
||||
public void Delete(IMemberType memberType, int userId = 0)
|
||||
{
|
||||
if (DeletingMemberType.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(memberType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
_memberService.DeleteMembersOfType(memberType.Id);
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow))
|
||||
{
|
||||
repository.Delete(memberType);
|
||||
uow.Commit();
|
||||
|
||||
DeletedMemberType.RaiseEvent(new DeleteEventArgs<IMemberType>(memberType, false), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(IEnumerable<IMemberType> memberTypes, int userId = 0)
|
||||
{
|
||||
var asArray = memberTypes.ToArray();
|
||||
|
||||
if (DeletingMemberType.IsRaisedEventCancelled(new DeleteEventArgs<IMemberType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
foreach (var contentType in asArray)
|
||||
{
|
||||
_memberService.DeleteMembersOfType(contentType.Id);
|
||||
}
|
||||
|
||||
var uow = _uowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateMemberTypeRepository(uow))
|
||||
{
|
||||
foreach (var memberType in asArray)
|
||||
{
|
||||
repository.Delete(memberType);
|
||||
}
|
||||
|
||||
uow.Commit();
|
||||
|
||||
DeletedMemberType.RaiseEvent(new DeleteEventArgs<IMemberType>(asArray, false), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called after an IContentType is saved and is used to update the content xml structures in the database
|
||||
/// if they are required to be updated.
|
||||
/// </summary>
|
||||
/// <param name="contentTypes">A tuple of a content type and a boolean indicating if it is new (HasIdentity was false before committing)</param>
|
||||
private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes)
|
||||
{
|
||||
|
||||
var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray();
|
||||
|
||||
if (toUpdate.Any())
|
||||
{
|
||||
//if it is a media type then call the rebuilding methods for media
|
||||
var typedMemberService = _memberService as MemberService;
|
||||
if (typedMemberService != null)
|
||||
{
|
||||
typedMemberService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> SavingMemberType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Save
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, SaveEventArgs<IMemberType>> SavedMemberType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> DeletingMemberType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IMemberTypeService, DeleteEventArgs<IMemberType>> DeletedMemberType;
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ namespace Umbraco.Core.Services
|
||||
// _macroService = new Lazy<IMacroService>(() => new MacroService(provider, repositoryFactory.Value));
|
||||
|
||||
if (_memberTypeService == null)
|
||||
_memberTypeService = new Lazy<IMemberTypeService>(() => new MemberTypeService(provider, repositoryFactory.Value));
|
||||
_memberTypeService = new Lazy<IMemberTypeService>(() => new MemberTypeService(provider, repositoryFactory.Value, _memberService.Value));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -465,6 +465,11 @@ namespace Umbraco.Core
|
||||
return compare.StartsWith(compareTo, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool InvariantEndsWith(this string compare, string compareTo)
|
||||
{
|
||||
return compare.EndsWith(compareTo, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public static bool InvariantContains(this string compare, string compareTo)
|
||||
{
|
||||
return compare.IndexOf(compareTo, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
|
||||
@@ -571,7 +571,9 @@ function validateSafeAlias(id, value, immediate, callback) {{
|
||||
for (var i = 0; i < ilen; i++)
|
||||
{
|
||||
var c = input[i];
|
||||
var isTerm = config.IsTerm(c, opos == 0);
|
||||
// leading as long as StateBreak and ipos still zero
|
||||
var leading = state == StateBreak && ipos == 0;
|
||||
var isTerm = config.IsTerm(c, leading);
|
||||
|
||||
//var isDigit = char.IsDigit(c);
|
||||
var isUpper = char.IsUpper(c); // false for digits, symbols...
|
||||
@@ -583,6 +585,12 @@ function validateSafeAlias(id, value, immediate, callback) {{
|
||||
if (isPair)
|
||||
throw new NotSupportedException("Surrogate pairs are not supported.");
|
||||
|
||||
Console.WriteLine("CHAR '{0}' {1} {2} - {3} - {4}/{5} {6}",
|
||||
c,
|
||||
isTerm ? "term" : "!term", isUpper ? "upper" : "!upper",
|
||||
state,
|
||||
i, ipos, leading ? "leading" : "!leading");
|
||||
|
||||
switch (state)
|
||||
{
|
||||
// within a break
|
||||
@@ -689,10 +697,10 @@ function validateSafeAlias(id, value, immediate, callback) {{
|
||||
CleanStringType caseType, CultureInfo culture, bool isAcronym)
|
||||
{
|
||||
var term = input.Substring(ipos, len);
|
||||
//Console.WriteLine("TERM \"{0}\" {1} {2}",
|
||||
// term,
|
||||
// isAcronym ? "acronym" : "word",
|
||||
// caseType);
|
||||
Console.WriteLine("TERM \"{0}\" {1} {2}",
|
||||
term,
|
||||
isAcronym ? "acronym" : "word",
|
||||
caseType);
|
||||
|
||||
if (isAcronym)
|
||||
{
|
||||
|
||||
@@ -200,6 +200,13 @@
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModel.cs" />
|
||||
<Compile Include="Models\PublishedContent\PublishedContentModelFactoryResolver.cs" />
|
||||
<Compile Include="Models\TemplateNode.cs" />
|
||||
<Compile Include="Persistence\Querying\SqlStringExtensions.cs" />
|
||||
<Compile Include="Persistence\Querying\StringPropertyMatchType.cs" />
|
||||
<Compile Include="Persistence\Querying\TextColumnType.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\MySqlSyntax.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\SqlCeSyntax.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\SqlServerSyntax.cs" />
|
||||
<Compile Include="Persistence\SqlSyntax\SqlServerVersionName.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyCacheValue.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyValueCacheAttribute.cs" />
|
||||
<Compile Include="PropertyEditors\PropertyValueTypeAttribute.cs" />
|
||||
@@ -745,6 +752,7 @@
|
||||
<Compile Include="Serialization\StreamedResult.cs" />
|
||||
<Compile Include="Services\ContentService.cs" />
|
||||
<Compile Include="Services\ContentTypeService.cs" />
|
||||
<Compile Include="Services\ContentTypeServiceBase.cs" />
|
||||
<Compile Include="Services\DataTypeService.cs" />
|
||||
<Compile Include="Services\EntityService.cs" />
|
||||
<Compile Include="Services\FileService.cs" />
|
||||
@@ -756,6 +764,7 @@
|
||||
<Compile Include="Services\ILocalizationService.cs" />
|
||||
<Compile Include="Services\IMediaService.cs" />
|
||||
<Compile Include="Services\IMemberService.cs" />
|
||||
<Compile Include="Services\IMembershipMemberService.cs" />
|
||||
<Compile Include="Services\IMembershipUserService.cs" />
|
||||
<Compile Include="Services\IMemberTypeService.cs" />
|
||||
<Compile Include="Services\IRelationService.cs" />
|
||||
|
||||
Reference in New Issue
Block a user