Compare commits

..

3 Commits

111 changed files with 1037 additions and 2336 deletions
+3 -3
View File
@@ -32,9 +32,9 @@
<!-- AutoMapper can not be updated due to: https://github.com/AutoMapper/AutoMapper/issues/373#issuecomment-127644405 -->
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
<dependency id="Examine" version="[0.1.80, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.5.2, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.8.2, 5.0.0)" />
<dependency id="Examine" version="[0.1.70, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.5.1, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.7.2, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 2.0.0)" />
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
-1
View File
@@ -45,7 +45,6 @@
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" />
<file src="tools\processing.config.install.xdt" target="Content\Config\imageprocessor\processing.config.install.xdt" />
<file src="tools\cache.config.install.xdt" target="Content\Config\imageprocessor\cache.config.install.xdt" />
<file src="build\**" target="build" />
</files>
</package>
@@ -1,6 +0,0 @@
<?xml version="1.0"?>
<caching xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<caches>
<cache name="DiskCache" trimCache="false" xdt:Transform="SetAttributes(trimCache)" xdt:Locator="Match(name)" />
</caches>
</caching>
+1 -1
View File
@@ -1,2 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.5.9
7.5.7
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.5.9")]
[assembly: AssemblyInformationalVersion("7.5.9")]
[assembly: AssemblyFileVersion("7.5.7")]
[assembly: AssemblyInformationalVersion("7.5.7")]
+1 -2
View File
@@ -64,8 +64,7 @@ namespace Umbraco.Core.Cache
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:";
[Obsolete("No longer used and will be removed in v8")]
[EditorBrowsable(EditorBrowsableState.Never)]
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.5.9");
private static readonly Version Version = new Version("7.5.7");
/// <summary>
/// Gets the current version of Umbraco.
+1 -1
View File
@@ -415,7 +415,7 @@ namespace Umbraco.Core
if (currentTry == 5)
{
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but Umbraco cannot connect to the database.");
throw new UmbracoStartupFailedException("Umbraco cannot start. A connection string is configured but the Umbraco cannot connect to the database.");
}
}
+9 -4
View File
@@ -203,10 +203,15 @@ namespace Umbraco.Core
var path = Path.Combine(GlobalSettings.FullpathToRoot, "App_Data", "Umbraco.sdf");
if (File.Exists(path) == false)
{
using (var engine = new SqlCeEngine(connectionString))
{
engine.CreateDatabase();
}
var engine = new SqlCeEngine(connectionString);
engine.CreateDatabase();
// SD: Pretty sure this should be in a using clause but i don't want to cause unknown side-effects here
// since it's been like this for quite some time
//using (var engine = new SqlCeEngine(connectionString))
//{
// engine.CreateDatabase();
//}
}
Initialize(providerName);
+1 -1
View File
@@ -4,7 +4,7 @@ namespace Umbraco.Core.Models
{
/// <summary>
/// Defines a ContentType, which Media is based on
/// </summary>
/// </summary
public interface IMediaType : IContentTypeComposition
{
@@ -27,15 +27,15 @@ namespace Umbraco.Core.Persistence.Factories
#region Implementation of IEntityFactory<IContent,DocumentDto>
public static IContent BuildEntity(DocumentDto dto, IContentType contentType)
public IContent BuildEntity(DocumentDto dto)
{
var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, contentType);
var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType);
try
{
content.DisableChangeTracking();
content.Id = dto.NodeId;
content.Id = _id;
content.Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId;
content.Name = dto.Text;
content.NodeName = dto.ContentVersionDto.ContentDto.NodeDto.Text;
@@ -49,8 +49,8 @@ namespace Umbraco.Core.Persistence.Factories
content.Published = dto.Published;
content.CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate;
content.UpdateDate = dto.ContentVersionDto.VersionDate;
content.ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?)null;
content.ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?)null;
content.ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?) null;
content.ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?) null;
content.Version = dto.ContentVersionDto.VersionId;
content.PublishedState = dto.Published ? PublishedState.Published : PublishedState.Unpublished;
content.PublishedVersionGuid = dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId;
@@ -64,13 +64,6 @@ namespace Umbraco.Core.Persistence.Factories
{
content.EnableChangeTracking();
}
}
[Obsolete("Use the static BuildEntity instead so we don't have to allocate one of these objects everytime we want to map values")]
public IContent BuildEntity(DocumentDto dto)
{
return BuildEntity(dto, _contentType);
}
public DocumentDto BuildDto(IContent entity)
@@ -27,15 +27,15 @@ namespace Umbraco.Core.Persistence.Factories
#region Implementation of IEntityFactory<IMedia,ContentVersionDto>
public static IMedia BuildEntity(ContentVersionDto dto, IMediaType contentType)
public IMedia BuildEntity(ContentVersionDto dto)
{
var media = new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, contentType);
var media = new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, _contentType);
try
{
media.DisableChangeTracking();
media.Id = dto.NodeId;
media.Id = _id;
media.Key = dto.ContentDto.NodeDto.UniqueId;
media.Path = dto.ContentDto.NodeDto.Path;
media.CreatorId = dto.ContentDto.NodeDto.UserId.Value;
@@ -55,13 +55,6 @@ namespace Umbraco.Core.Persistence.Factories
{
media.EnableChangeTracking();
}
}
[Obsolete("Use the static BuildEntity instead so we don't have to allocate one of these objects everytime we want to map values")]
public IMedia BuildEntity(ContentVersionDto dto)
{
return BuildEntity(dto, _contentType);
}
public ContentVersionDto BuildDto(IMedia entity)
@@ -30,11 +30,11 @@ namespace Umbraco.Core.Persistence.Factories
_updateDate = updateDate;
}
public static IEnumerable<Property> BuildEntity(IReadOnlyCollection<PropertyDataDto> dtos, PropertyType[] compositionTypeProperties, DateTime createDate, DateTime updateDate)
public IEnumerable<Property> BuildEntity(PropertyDataDto[] dtos)
{
var properties = new List<Property>();
foreach (var propertyType in compositionTypeProperties)
foreach (var propertyType in _compositionTypeProperties)
{
var propertyDataDto = dtos.LastOrDefault(x => x.PropertyTypeId == propertyType.Id);
var property = propertyDataDto == null
@@ -47,8 +47,8 @@ namespace Umbraco.Core.Persistence.Factories
//on initial construction we don't want to have dirty properties tracked
property.DisableChangeTracking();
property.CreateDate = createDate;
property.UpdateDate = updateDate;
property.CreateDate = _createDate;
property.UpdateDate = _updateDate;
// http://issues.umbraco.org/issue/U4-1946
property.ResetDirtyProperties(false);
properties.Add(property);
@@ -57,18 +57,12 @@ namespace Umbraco.Core.Persistence.Factories
{
property.EnableChangeTracking();
}
}
return properties;
}
[Obsolete("Use the static method instead, there's no reason to allocate one of these classes everytime we want to map values")]
public IEnumerable<Property> BuildEntity(PropertyDataDto[] dtos)
{
return BuildEntity(dtos, _compositionTypeProperties, _createDate, _updateDate);
}
public IEnumerable<PropertyDataDto> BuildDto(IEnumerable<Property> properties)
{
var propertyDataDtos = new List<PropertyDataDto>();
@@ -20,7 +20,6 @@ namespace Umbraco.Core.Persistence.Querying
_mapper = mapper;
}
[Obsolete("Use the overload the specifies a SqlSyntaxProvider")]
public ModelToSqlExpressionVisitor()
: this(SqlSyntaxContext.SqlSyntaxProvider, MappingResolver.Current.ResolveMapperByType(typeof(T)))
{ }
@@ -18,13 +18,14 @@ namespace Umbraco.Core.Persistence.Querying
public PocoToSqlExpressionVisitor(ISqlSyntaxProvider syntaxProvider)
: base(syntaxProvider)
{
_pd = new Database.PocoData(typeof(T));
}
[Obsolete("Use the overload the specifies a SqlSyntaxProvider")]
public PocoToSqlExpressionVisitor()
: this(SqlSyntaxContext.SqlSyntaxProvider)
{
: base(SqlSyntaxContext.SqlSyntaxProvider)
{
_pd = new Database.PocoData(typeof(T));
}
protected override string VisitMemberAccess(MemberExpression m)
@@ -1,9 +0,0 @@
namespace Umbraco.Core.Persistence.Repositories
{
internal enum BaseQueryType
{
Full,
Ids,
Count
}
}
@@ -55,7 +55,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sql = GetBaseQuery(false)
.Where(GetBaseWhereClause(), new { Id = id })
.Where<DocumentDto>(x => x.Newest, SqlSyntax)
.Where<DocumentDto>(x => x.Newest)
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(SqlSyntax.SelectTop(sql, 1)).FirstOrDefault();
@@ -70,90 +70,63 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IEnumerable<IContent> PerformGetAll(params int[] ids)
{
Func<Sql, Sql> translate = s =>
var sql = GetBaseQuery(false);
if (ids.Any())
{
if (ids.Any())
{
s.Where("umbracoNode.id in (@ids)", new { ids });
}
//we only want the newest ones with this method
s.Where<DocumentDto>(x => x.Newest, SqlSyntax);
return s;
};
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
sql.Where("umbracoNode.id in (@ids)", new { ids });
}
return ProcessQuery(translate(sqlBaseFull), translate(sqlBaseIds));
//we only want the newest ones with this method
sql.Where<DocumentDto>(x => x.Newest);
return ProcessQuery(sql);
}
protected override IEnumerable<IContent> PerformGetByQuery(IQuery<IContent> query)
{
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IContent>(sqlClause, query);
var sql = translator.Translate()
.Where<DocumentDto>(x => x.Newest)
.OrderByDescending<ContentVersionDto>(x => x.VersionDate)
.OrderBy<NodeDto>(x => x.SortOrder);
Func<SqlTranslator<IContent>, Sql> translate = (translator) =>
{
return translator.Translate()
.Where<DocumentDto>(x => x.Newest, SqlSyntax)
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax)
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
};
var translatorFull = new SqlTranslator<IContent>(sqlBaseFull, query);
var translatorIds = new SqlTranslator<IContent>(sqlBaseIds, query);
return ProcessQuery(translate(translatorFull), translate(translatorIds));
return ProcessQuery(sql);
}
#endregion
#region Overrides of PetaPocoRepositoryBase<IContent>
protected override Sql GetBaseQuery(BaseQueryType queryType)
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
sql.Select(queryType == BaseQueryType.Count ? "COUNT(*)" : (queryType == BaseQueryType.Ids ? "cmsDocument.nodeId" : "*"))
.From<DocumentDto>(SqlSyntax)
.InnerJoin<ContentVersionDto>(SqlSyntax)
.On<DocumentDto, ContentVersionDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId);
if (queryType == BaseQueryType.Full)
{
//The only reason we apply this left outer join is to be able to pull back the DocumentPublishedReadOnlyDto
//information with the entire data set, so basically this will get both the latest document and also it's published
//version if it has one. When performing a count or when just retrieving Ids like in paging, this is unecessary
//and causes huge performance overhead for the SQL server, especially when sorting the result.
//To fix this perf overhead we'd need another index on :
// CREATE NON CLUSTERED INDEX ON cmsDocument.node + cmsDocument.published
var sqlx = string.Format("LEFT OUTER JOIN {0} {1} ON ({1}.{2}={0}.{2} AND {1}.{3}=1)",
var sqlx = string.Format("LEFT OUTER JOIN {0} {1} ON ({1}.{2}={0}.{2} AND {1}.{3}=1)",
SqlSyntax.GetQuotedTableName("cmsDocument"),
SqlSyntax.GetQuotedTableName("cmsDocument2"),
SqlSyntax.GetQuotedColumnName("nodeId"),
SqlSyntax.GetQuotedColumnName("published"));
var sql = new Sql();
sql.Select(isCount ? "COUNT(*)" : "*")
.From<DocumentDto>()
.InnerJoin<ContentVersionDto>()
.On<DocumentDto, ContentVersionDto>(left => left.VersionId, right => right.VersionId)
.InnerJoin<ContentDto>()
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
// cannot do this because PetaPoco does not know how to alias the table
//.LeftOuterJoin<DocumentPublishedReadOnlyDto>()
//.On<DocumentDto, DocumentPublishedReadOnlyDto>(left => left.NodeId, right => right.NodeId)
// so have to rely on writing our own SQL
sql.Append(sqlx /*, new { @published = true }*/);
}
sql.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
.Append(sqlx/*, new { @published = true }*/)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
}
protected override Sql GetBaseQuery(bool isCount)
{
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
}
protected override string GetBaseWhereClause()
{
return "umbracoNode.id = @Id";
@@ -200,32 +173,20 @@ namespace Umbraco.Core.Persistence.Repositories
// not bring much safety - so this reverts to updating each record individually,
// and it may be slower in the end, but should be more resilient.
var contentTypeIdsA = contentTypeIds == null ? new int[0] : contentTypeIds.ToArray();
Func<int, Sql, Sql> translate = (bId, sql) =>
{
if (contentTypeIdsA.Length > 0)
{
sql.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
}
sql
.Where<NodeDto>(x => x.NodeId > bId && x.Trashed == false, SqlSyntax)
.Where<DocumentDto>(x => x.Published, SqlSyntax)
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
return sql;
};
var baseId = 0;
var contentTypeIdsA = contentTypeIds == null ? new int[0] : contentTypeIds.ToArray();
while (true)
{
// get the next group of nodes
var sqlFull = translate(baseId, GetBaseQuery(BaseQueryType.Full));
var sqlIds = translate(baseId, GetBaseQuery(BaseQueryType.Ids));
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(sqlFull, groupSize), SqlSyntax.SelectTop(sqlIds, groupSize))
var query = GetBaseQuery(false);
if (contentTypeIdsA.Length > 0)
query = query
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
query = query
.Where<NodeDto>(x => x.NodeId > baseId && x.Trashed == false)
.Where<DocumentDto>(x => x.Published)
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
.ToList();
@@ -251,23 +212,17 @@ namespace Umbraco.Core.Persistence.Repositories
public override IEnumerable<IContent> GetAllVersions(int id)
{
Func<Sql, Sql> translate = s =>
{
return s.Where(GetBaseWhereClause(), new {Id = id})
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
};
var sqlFull = translate(GetBaseQuery(BaseQueryType.Full));
var sqlIds = translate(GetBaseQuery(BaseQueryType.Ids));
return ProcessQuery(sqlFull, sqlIds, true);
var sql = GetBaseQuery(false)
.Where(GetBaseWhereClause(), new { Id = id })
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
return ProcessQuery(sql, true);
}
public override IContent GetByVersion(Guid versionId)
{
var sql = GetBaseQuery(false);
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql).FirstOrDefault();
@@ -283,10 +238,10 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sql = new Sql()
.Select("*")
.From<DocumentDto>(SqlSyntax)
.InnerJoin<ContentVersionDto>(SqlSyntax).On<ContentVersionDto, DocumentDto>(SqlSyntax, left => left.VersionId, right => right.VersionId)
.Where<ContentVersionDto>(x => x.VersionId == versionId, SqlSyntax)
.Where<DocumentDto>(x => x.Newest != true, SqlSyntax);
.From<DocumentDto>()
.InnerJoin<ContentVersionDto>().On<ContentVersionDto, DocumentDto>(left => left.VersionId, right => right.VersionId)
.Where<ContentVersionDto>(x => x.VersionId == versionId)
.Where<DocumentDto>(x => x.Newest != true);
var dto = Database.Fetch<DocumentDto, ContentVersionDto>(sql).FirstOrDefault();
if (dto == null) return;
@@ -661,27 +616,21 @@ namespace Umbraco.Core.Persistence.Repositories
public IEnumerable<IContent> GetByPublishedVersion(IQuery<IContent> query)
{
Func<SqlTranslator<IContent>, Sql> translate = t =>
{
return t.Translate()
.Where<DocumentDto>(x => x.Published, SqlSyntax)
.OrderBy<NodeDto>(x => x.Level, SqlSyntax)
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
};
// we WANT to return contents in top-down order, ie parents should come before children
// ideal would be pure xml "document order" which can be achieved with:
// ORDER BY substring(path, 1, len(path) - charindex(',', reverse(path))), sortOrder
// but that's probably an overkill - sorting by level,sortOrder should be enough
var sqlFull = GetBaseQuery(BaseQueryType.Full);
var translatorFull = new SqlTranslator<IContent>(sqlFull, query);
var sqlIds = GetBaseQuery(BaseQueryType.Ids);
var translatorIds = new SqlTranslator<IContent>(sqlIds, query);
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IContent>(sqlClause, query);
var sql = translator.Translate()
.Where<DocumentDto>(x => x.Published)
.OrderBy<NodeDto>(x => x.Level, SqlSyntax)
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
return ProcessQuery(translate(translatorFull), translate(translatorIds), true);
return ProcessQuery(sql, true);
}
/// <summary>
/// This builds the Xml document used for the XML cache
/// </summary>
@@ -713,14 +662,10 @@ namespace Umbraco.Core.Persistence.Repositories
parent.Attributes.Append(pIdAtt);
xmlDoc.AppendChild(parent);
//Ensure that only nodes that have published versions are selected
var sql = string.Format(@"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.{0}, umbracoNode.{1} from umbracoNode
const string sql = @"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.xml, umbracoNode.level from umbracoNode
inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type
where umbracoNode.id in (select cmsDocument.nodeId from cmsDocument where cmsDocument.published = 1)
order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
SqlSyntax.GetQuotedColumnName("xml"),
SqlSyntax.GetQuotedColumnName("level"),
SqlSyntax.GetQuotedColumnName("level"));
order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder";
XmlElement last = null;
@@ -857,9 +802,9 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
Func<Tuple<string, object[]>> filterCallback = () => new Tuple<string, object[]>(filterSql.SQL, filterSql.Arguments);
return GetPagedResultsByQuery<DocumentDto>(query, pageIndex, pageSize, out totalRecords,
return GetPagedResultsByQuery<DocumentDto, Content>(query, pageIndex, pageSize, out totalRecords,
new Tuple<string, string>("cmsDocument", "nodeId"),
(sqlFull, sqlIds) => ProcessQuery(sqlFull, sqlIds), orderBy, orderDirection, orderBySystemField,
sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
filterCallback);
}
@@ -890,32 +835,16 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
return base.GetDatabaseFieldNameForOrderBy(orderBy);
}
/// <summary>
/// This is the underlying method that processes most queries for this repository
/// </summary>
/// <param name="sqlFull">
/// The full SQL with the outer join to return all data required to create an IContent
/// </param>
/// <param name="sqlIds">
/// The Id SQL without the outer join to just return all document ids - used to process the properties for the content item
/// </param>
/// <param name="withCache"></param>
/// <returns></returns>
private IEnumerable<IContent> ProcessQuery(Sql sqlFull, Sql sqlIds, bool withCache = false)
private IEnumerable<IContent> ProcessQuery(Sql sql, bool withCache = false)
{
// fetch returns a list so it's ok to iterate it in this method
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sqlFull);
var dtos = Database.Fetch<DocumentDto, ContentVersionDto, ContentDto, NodeDto, DocumentPublishedReadOnlyDto>(sql);
if (dtos.Count == 0) return Enumerable.Empty<IContent>();
var content = new IContent[dtos.Count];
var defs = new List<DocumentDefinition>();
var templateIds = new List<int>();
//track the looked up content types, even though the content types are cached
// they still need to be deep cloned out of the cache and we don't want to add
// the overhead of deep cloning them on every item in this loop
var contentTypes = new Dictionary<int, IContentType>();
for (var i = 0; i < dtos.Count; i++)
{
var dto = dtos[i];
@@ -934,19 +863,9 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
// else, need to fetch from the database
// content type repository is full-cache so OK to get each one independently
IContentType contentType;
if (contentTypes.ContainsKey(dto.ContentVersionDto.ContentDto.ContentTypeId))
{
contentType = contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId];
}
else
{
contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
contentTypes[dto.ContentVersionDto.ContentDto.ContentTypeId] = contentType;
}
content[i] = ContentFactory.BuildEntity(dto, contentType);
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
content[i] = factory.BuildEntity(dto);
// need template
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
@@ -967,7 +886,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
.ToDictionary(x => x.Id, x => x);
// load all properties for all documents from database in 1 query
var propertyData = GetPropertyCollection(sqlIds, defs);
var propertyData = GetPropertyCollection(sql, defs);
// assign
var dtoIndex = 0;
@@ -987,7 +906,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
cc.ResetDirtyProperties(false);
((Entity) cc).ResetDirtyProperties(false);
}
return content;
@@ -1004,7 +923,8 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
{
var contentType = _contentTypeRepository.Get(dto.ContentVersionDto.ContentDto.ContentTypeId);
var content = ContentFactory.BuildEntity(dto, contentType);
var factory = new ContentFactory(contentType, NodeObjectTypeId, dto.NodeId);
var content = factory.BuildEntity(dto);
//Check if template id is set on DocumentDto, and get ITemplate if it is.
if (dto.TemplateId.HasValue && dto.TemplateId.Value > 0)
@@ -62,27 +62,17 @@ namespace Umbraco.Core.Persistence.Repositories
protected override IEnumerable<EntityContainer> PerformGetAll(params int[] ids)
{
if (ids.Any())
{
//we need to batch these in groups of 2000 so we don't exceed the max 2100 limit
return ids.InGroupsOf(2000).SelectMany(@group =>
{
var sql = GetBaseQuery(false)
.Where("nodeObjectType=@umbracoObjectTypeId", new {umbracoObjectTypeId = NodeObjectTypeId})
.Where(string.Format("{0} IN (@ids)", SqlSyntax.GetQuotedColumnName("id")), new {ids = @group});
sql.OrderBy<NodeDto>(x => x.Level, SqlSyntax);
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
});
}
else
//we need to batch these in groups of 2000 so we don't exceed the max 2100 limit
return ids.InGroupsOf(2000).SelectMany(@group =>
{
var sql = GetBaseQuery(false)
.Where("nodeObjectType=@umbracoObjectTypeId", new {umbracoObjectTypeId = NodeObjectTypeId});
.Where("nodeObjectType=@umbracoObjectTypeId", new { umbracoObjectTypeId = NodeObjectTypeId })
.Where(string.Format("{0} IN (@ids)", SqlSyntax.GetQuotedColumnName("id")), new { ids = @group });
sql.OrderBy<NodeDto>(x => x.Level, SqlSyntax);
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
}
});
}
protected override IEnumerable<EntityContainer> PerformGetByQuery(IQuery<EntityContainer> query)
@@ -96,6 +96,5 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetPagedResultsByQuery(IQuery<IContent> query, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, IQuery<IContent> filter = null);
}
}
@@ -38,6 +38,15 @@ namespace Umbraco.Core.Persistence.Repositories
/// <returns>An Enumerable list of <see cref="IMedia"/> objects</returns>
IEnumerable<IMedia> GetPagedResultsByQuery(IQuery<IMedia> query, long pageIndex, int pageSize, out long totalRecords,
string orderBy, Direction orderDirection, bool orderBySystemField, string filter = "");
/// <summary>
/// Gets paged media descendants as XML by path
/// </summary>
/// <param name="path">Path starts with</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of media items</returns>
IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, out long totalRecords);
}
}
@@ -73,6 +73,6 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="content"></param>
/// <param name="xml"></param>
void AddOrUpdatePreviewXml(IMember content, Func<IMember, XElement> xml);
}
}
@@ -67,16 +67,5 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="id">Id of the <see cref="TEntity"/> object to delete versions from</param>
/// <param name="versionDate">Latest version date</param>
void DeleteVersions(int id, DateTime versionDate);
/// <summary>
/// Gets paged content descendants as XML by path
/// </summary>
/// <param name="path">Path starts with</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="orderBy"></param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of content items</returns>
IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, string[] orderBy, out long totalRecords);
}
}
@@ -76,7 +76,7 @@ namespace Umbraco.Core.Persistence.Repositories
var sqlClause = GetBaseQuery(false);
var translator = new SqlTranslator<IMedia>(sqlClause, query);
var sql = translator.Translate()
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
.OrderBy<NodeDto>(x => x.SortOrder);
return ProcessQuery(sql);
}
@@ -84,23 +84,18 @@ namespace Umbraco.Core.Persistence.Repositories
#endregion
#region Overrides of PetaPocoRepositoryBase<int,IMedia>
protected override Sql GetBaseQuery(BaseQueryType queryType)
{
var sql = new Sql();
sql.Select(queryType == BaseQueryType.Count ? "COUNT(*)" : (queryType == BaseQueryType.Ids ? "cmsContentVersion.contentId" : "*"))
.From<ContentVersionDto>(SqlSyntax)
.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId, SqlSyntax)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
return sql;
}
protected override Sql GetBaseQuery(bool isCount)
{
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
var sql = new Sql();
sql.Select(isCount ? "COUNT(*)" : "*")
.From<ContentVersionDto>()
.InnerJoin<ContentDto>()
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<NodeDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
}
protected override string GetBaseWhereClause()
@@ -153,11 +148,6 @@ namespace Umbraco.Core.Persistence.Repositories
var content = new IMedia[dtos.Count];
var defs = new List<DocumentDefinition>();
//track the looked up content types, even though the content types are cached
// they still need to be deep cloned out of the cache and we don't want to add
// the overhead of deep cloning them on every item in this loop
var contentTypes = new Dictionary<int, IMediaType>();
for (var i = 0; i < dtos.Count; i++)
{
var dto = dtos[i];
@@ -175,19 +165,9 @@ namespace Umbraco.Core.Persistence.Repositories
// else, need to fetch from the database
// content type repository is full-cache so OK to get each one independently
IMediaType contentType;
if (contentTypes.ContainsKey(dto.ContentDto.ContentTypeId))
{
contentType = contentTypes[dto.ContentDto.ContentTypeId];
}
else
{
contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
contentTypes[dto.ContentDto.ContentTypeId] = contentType;
}
content[i] = MediaFactory.BuildEntity(dto, contentType);
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
content[i] = factory.BuildEntity(dto);
// need properties
defs.Add(new DocumentDefinition(
@@ -215,7 +195,7 @@ namespace Umbraco.Core.Persistence.Repositories
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
cc.ResetDirtyProperties(false);
((Entity) cc).ResetDirtyProperties(false);
}
return content;
@@ -225,16 +205,26 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sql = GetBaseQuery(false);
sql.Where("cmsContentVersion.VersionId = @VersionId", new { VersionId = versionId });
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
sql.OrderByDescending<ContentVersionDto>(x => x.VersionDate);
var dto = Database.Fetch<ContentVersionDto, ContentDto, NodeDto>(sql).FirstOrDefault();
if (dto == null)
return null;
var content = CreateMediaFromDto(dto, versionId, sql);
var mediaType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
return content;
var factory = new MediaFactory(mediaType, NodeObjectTypeId, dto.NodeId);
var media = factory.BuildEntity(dto);
var properties = GetPropertyCollection(sql, new[] { new DocumentDefinition(dto.NodeId, dto.VersionId, media.UpdateDate, media.CreateDate, mediaType) });
media.Properties = properties[dto.NodeId];
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
((Entity)media).ResetDirtyProperties(false);
return media;
}
public void RebuildXmlStructures(Func<IMedia, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null)
@@ -255,7 +245,7 @@ namespace Umbraco.Core.Persistence.Repositories
query = query
.WhereIn<ContentDto>(x => x.ContentTypeId, contentTypeIdsA, SqlSyntax);
query = query
.Where<NodeDto>(x => x.NodeId > baseId, SqlSyntax)
.Where<NodeDto>(x => x.NodeId > baseId)
.OrderBy<NodeDto>(x => x.NodeId, SqlSyntax);
var xmlItems = ProcessQuery(SqlSyntax.SelectTop(query, groupSize))
.Select(x => new ContentXmlDto { NodeId = x.Id, Xml = serializer(x).ToString() })
@@ -505,13 +495,37 @@ namespace Umbraco.Core.Persistence.Repositories
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
}
return GetPagedResultsByQuery<ContentVersionDto>(query, pageIndex, pageSize, out totalRecords,
return GetPagedResultsByQuery<ContentVersionDto, Models.Media>(query, pageIndex, pageSize, out totalRecords,
new Tuple<string, string>("cmsContentVersion", "contentId"),
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
filterCallback);
}
/// <summary>
/// Gets paged media descendants as XML by path
/// </summary>
/// <param name="path">Path starts with</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of media items</returns>
public IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, out long totalRecords)
{
Sql query;
if (path == "-1")
{
query = new Sql().Select("nodeId, xml").From("cmsContentXml").Where("nodeId IN (SELECT id FROM umbracoNode WHERE nodeObjectType = @0)", Guid.Parse(Constants.ObjectTypes.Media)).OrderBy("nodeId");
}
else
{
query = new Sql().Select("nodeId, xml").From("cmsContentXml").Where("nodeId IN (SELECT id FROM umbracoNode WHERE path LIKE @0)", path.EnsureEndsWith(",%")).OrderBy("nodeId");
}
var pagedResult = Database.Page<ContentXmlDto>(pageIndex+1, pageSize, query);
totalRecords = pagedResult.TotalItems;
return pagedResult.Items.Select(dto => XElement.Parse(dto.Xml));
}
/// <summary>
/// Private method to create a media object from a ContentDto
/// </summary>
@@ -522,8 +536,9 @@ namespace Umbraco.Core.Persistence.Repositories
private IMedia CreateMediaFromDto(ContentVersionDto dto, Guid versionId, Sql docSql)
{
var contentType = _mediaTypeRepository.Get(dto.ContentDto.ContentTypeId);
var media = MediaFactory.BuildEntity(dto, contentType);
var factory = new MediaFactory(contentType, NodeObjectTypeId, dto.NodeId);
var media = factory.BuildEntity(dto);
var docDef = new DocumentDefinition(dto.NodeId, versionId, media.UpdateDate, media.CreateDate, contentType);
@@ -107,29 +107,24 @@ namespace Umbraco.Core.Persistence.Repositories
#region Overrides of PetaPocoRepositoryBase<int,IMembershipUser>
protected override Sql GetBaseQuery(BaseQueryType queryType)
protected override Sql GetBaseQuery(bool isCount)
{
var sql = new Sql();
sql.Select(queryType == BaseQueryType.Count ? "COUNT(*)" : (queryType == BaseQueryType.Ids ? "cmsMember.nodeId" : "*"))
.From<MemberDto>(SqlSyntax)
.InnerJoin<ContentVersionDto>(SqlSyntax)
.On<ContentVersionDto, MemberDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentDto>(SqlSyntax)
.On<ContentVersionDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
sql.Select(isCount ? "COUNT(*)" : "*")
.From<MemberDto>()
.InnerJoin<ContentVersionDto>()
.On<ContentVersionDto, MemberDto>(left => left.NodeId, right => right.NodeId)
.InnerJoin<ContentDto>()
.On<ContentVersionDto, ContentDto>(left => left.NodeId, right => right.NodeId)
//We're joining the type so we can do a query against the member type - not sure if this adds much overhead or not?
// the execution plan says it doesn't so we'll go with that and in that case, it might be worth joining the content
// types by default on the document and media repo's so we can query by content type there too.
.InnerJoin<ContentTypeDto>(SqlSyntax)
.On<ContentTypeDto, ContentDto>(SqlSyntax, left => left.NodeId, right => right.ContentTypeId)
.InnerJoin<NodeDto>(SqlSyntax)
.On<ContentDto, NodeDto>(SqlSyntax, left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId, SqlSyntax);
.InnerJoin<ContentTypeDto>().On<ContentTypeDto, ContentDto>(left => left.NodeId, right => right.ContentTypeId)
.InnerJoin<NodeDto>()
.On<ContentDto, NodeDto>(left => left.NodeId, right => right.NodeId)
.Where<NodeDto>(x => x.NodeObjectType == NodeObjectTypeId);
return sql;
}
protected override Sql GetBaseQuery(bool isCount)
{
return GetBaseQuery(isCount ? BaseQueryType.Count : BaseQueryType.Full);
}
protected override string GetBaseWhereClause()
@@ -386,7 +381,7 @@ namespace Umbraco.Core.Persistence.Repositories
.Where(GetBaseWhereClause(), new { Id = id })
.OrderByDescending<ContentVersionDto>(x => x.VersionDate, SqlSyntax);
return ProcessQuery(sql, true);
}
}
public void RebuildXmlStructures(Func<IMember, XElement> serializer, int groupSize = 200, IEnumerable<int> contentTypeIds = null)
{
@@ -622,9 +617,9 @@ namespace Umbraco.Core.Persistence.Repositories
filterCallback = () => new Tuple<string, object[]>(sbWhere.ToString().Trim(), args.ToArray());
}
return GetPagedResultsByQuery<MemberDto>(query, pageIndex, pageSize, out totalRecords,
return GetPagedResultsByQuery<MemberDto, Member>(query, pageIndex, pageSize, out totalRecords,
new Tuple<string, string>("cmsMember", "nodeId"),
(sqlFull, sqlIds) => ProcessQuery(sqlFull), orderBy, orderDirection, orderBySystemField,
sql => ProcessQuery(sql), orderBy, orderDirection, orderBySystemField,
filterCallback);
}
@@ -1,12 +1,10 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
@@ -27,6 +25,8 @@ using Umbraco.Core.IO;
namespace Umbraco.Core.Persistence.Repositories
{
using SqlSyntax;
internal abstract class VersionableRepositoryBase<TId, TEntity> : PetaPocoRepositoryBase<TId, TEntity>
where TEntity : class, IAggregateRoot
{
@@ -137,40 +137,6 @@ namespace Umbraco.Core.Persistence.Repositories
#endregion
/// <summary>
/// Gets paged document descendants as XML by path
/// </summary>
/// <param name="path">Path starts with</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="orderBy"></param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of content items</returns>
public virtual IEnumerable<XElement> GetPagedXmlEntriesByPath(string path, long pageIndex, int pageSize, string[] orderBy, out long totalRecords)
{
var query = new Sql().Select(string.Format("umbracoNode.id, cmsContentXml.{0}", SqlSyntax.GetQuotedColumnName("xml")))
.From("umbracoNode")
.InnerJoin("cmsContentXml").On("cmsContentXml.nodeId = umbracoNode.id");
if (path == "-1")
{
query.Where("umbracoNode.nodeObjectType = @type", new { type = NodeObjectTypeId });
}
else
{
query.Where(string.Format("umbracoNode.{0} LIKE (@0)", SqlSyntax.GetQuotedColumnName("path")), path.EnsureEndsWith(",%"));
}
//each order by param needs to be in a bracket! see: https://github.com/toptensoftware/PetaPoco/issues/177
query.OrderBy(orderBy == null
? "(umbracoNode.id)"
: string.Join(",", orderBy.Select(x => string.Format("({0})", SqlSyntax.GetQuotedColumnName(x)))));
var pagedResult = Database.Page<ContentXmlDto>(pageIndex + 1, pageSize, query);
totalRecords = pagedResult.TotalItems;
return pagedResult.Items.Select(dto => XElement.Parse(dto.Xml));
}
public int CountDescendants(int parentId, string contentTypeAlias = null)
{
var pathMatch = parentId == -1
@@ -382,8 +348,12 @@ namespace Umbraco.Core.Persistence.Repositories
ON CustomPropData.CustomPropValContentId = umbracoNode.id
", sortedInt, sortedDecimal, sortedDate, sortedString, nodeIdSelect.Item2, nodeIdSelect.Item1, versionQuery, sortedSql.Arguments.Length, newestQuery);
//insert this just above the last WHERE
string newSql = sortedSql.SQL.Insert(sortedSql.SQL.LastIndexOf("WHERE"), outerJoinTempTable);
//insert this just above the first LEFT OUTER JOIN (for cmsDocument) or the last WHERE (everything else)
string newSql;
if (nodeIdSelect.Item1 == "cmsDocument")
newSql = sortedSql.SQL.Insert(sortedSql.SQL.IndexOf("LEFT OUTER JOIN"), outerJoinTempTable);
else
newSql = sortedSql.SQL.Insert(sortedSql.SQL.LastIndexOf("WHERE"), outerJoinTempTable);
var newArgs = sortedSql.Arguments.ToList();
newArgs.Add(orderBy);
@@ -400,14 +370,11 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
if (orderBySystemField && orderBy != "umbracoNode.id")
{
//no matter what we always MUST order the result also by umbracoNode.id to ensure that all records being ordered by are unique.
// if we do not do this then we end up with issues where we are ordering by a field that has duplicate values (i.e. the 'text' column
// is empty for many nodes)
// see: http://issues.umbraco.org/issue/U4-8831
sortedSql.OrderBy("umbracoNode.id");
}
//no matter what we always MUST order the result also by umbracoNode.id to ensure that all records being ordered by are unique.
// if we do not do this then we end up with issues where we are ordering by a field that has duplicate values (i.e. the 'text' column
// is empty for many nodes)
// see: http://issues.umbraco.org/issue/U4-8831
sortedSql.OrderBy("umbracoNode.id");
return sortedSql;
@@ -417,6 +384,7 @@ namespace Umbraco.Core.Persistence.Repositories
/// A helper method for inheritors to get the paged results by query in a way that minimizes queries
/// </summary>
/// <typeparam name="TDto">The type of the d.</typeparam>
/// <typeparam name="TContentBase">The 'true' entity type (i.e. Content, Member, etc...)</typeparam>
/// <param name="query">The query.</param>
/// <param name="pageIndex">Index of the page.</param>
/// <param name="pageSize">Size of the page.</param>
@@ -429,30 +397,34 @@ namespace Umbraco.Core.Persistence.Repositories
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
/// <returns></returns>
/// <exception cref="System.ArgumentNullException">orderBy</exception>
protected IEnumerable<TEntity> GetPagedResultsByQuery<TDto>(IQuery<TEntity> query, long pageIndex, int pageSize, out long totalRecords,
protected IEnumerable<TEntity> GetPagedResultsByQuery<TDto, TContentBase>(IQuery<TEntity> query, long pageIndex, int pageSize, out long totalRecords,
Tuple<string, string> nodeIdSelect,
Func<Sql, Sql, IEnumerable<TEntity>> processQuery,
Func<Sql, IEnumerable<TEntity>> processQuery,
string orderBy,
Direction orderDirection,
bool orderBySystemField,
Func<Tuple<string, object[]>> defaultFilter = null)
where TContentBase : class, IAggregateRoot, TEntity
{
if (orderBy == null) throw new ArgumentNullException("orderBy");
// Get base query for returning IDs
var sqlBaseIds = GetBaseQuery(BaseQueryType.Ids);
// Get base query for returning all data
var sqlBaseFull = GetBaseQuery(BaseQueryType.Full);
// Get base query
var sqlBase = GetBaseQuery(false);
if (query == null) query = new Query<TEntity>();
var translatorIds = new SqlTranslator<TEntity>(sqlBaseIds, query);
var sqlQueryIds = translatorIds.Translate();
var translatorFull = new SqlTranslator<TEntity>(sqlBaseFull, query);
var sqlQueryFull = translatorFull.Translate();
var translator = new SqlTranslator<TEntity>(sqlBase, query);
var sqlQuery = translator.Translate();
// Note we can't do multi-page for several DTOs like we can multi-fetch and are doing in PerformGetByQuery,
// but actually given we are doing a Get on each one (again as in PerformGetByQuery), we only need the node Id.
// So we'll modify the SQL.
var sqlNodeIds = new Sql(
sqlQuery.SQL.Replace("SELECT *", string.Format("SELECT {0}.{1}", nodeIdSelect.Item1, nodeIdSelect.Item2)),
sqlQuery.Arguments);
//get sorted and filtered sql
var sqlNodeIdsWithSort = GetSortedSqlForPagedResults(
GetFilteredSqlForPagedResults(sqlQueryIds, defaultFilter),
GetFilteredSqlForPagedResults(sqlNodeIds, defaultFilter),
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
// Get page of results and total count
@@ -461,7 +433,7 @@ namespace Umbraco.Core.Persistence.Repositories
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
//NOTE: We need to check the actual items returned, not the 'totalRecords', that is because if you request a page number
// that doesn't actually have any data on it, the totalRecords will still indicate there are records but there are none in
// that doesn't actually have any data on it, the totalRecords will still indicate there are records but there are none in
// the pageResult, then the GetAll will actually return ALL records in the db.
if (pagedResult.Items.Any())
{
@@ -470,23 +442,29 @@ namespace Umbraco.Core.Persistence.Repositories
string sqlStringCount, sqlStringPage;
Database.BuildPageQueries<TDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
//We need to make this FULL query an inner join on the paged ID query
var splitQuery = sqlQueryFull.SQL.Split(new[] { "WHERE " }, StringSplitOptions.None);
var fullQueryWithPagedInnerJoin = new Sql(splitQuery[0])
//if this is for sql server, the sqlPage will start with a SELECT * but we don't want that, we only want to return the nodeId
sqlStringPage = sqlStringPage
.Replace("SELECT *",
//This ensures we only take the field name of the node id select and not the table name - since the resulting select
// will ony work with the field name.
"SELECT " + nodeIdSelect.Item2);
//We need to make this an inner join on the paged query
var splitQuery = sqlQuery.SQL.Split(new[] { "WHERE " }, StringSplitOptions.None);
var withInnerJoinSql = new Sql(splitQuery[0])
.Append("INNER JOIN (")
//join the paged query with the paged query arguments
.Append(sqlStringPage, args)
.Append(") temp ")
.Append(string.Format("ON {0}.{1} = temp.{1}", nodeIdSelect.Item1, nodeIdSelect.Item2))
//add the original where clause back with the original arguments
.Where(splitQuery[1], sqlQueryIds.Arguments);
.Where(splitQuery[1], sqlQuery.Arguments);
//get sorted and filtered sql
var fullQuery = GetSortedSqlForPagedResults(
GetFilteredSqlForPagedResults(fullQueryWithPagedInnerJoin, defaultFilter),
GetFilteredSqlForPagedResults(withInnerJoinSql, defaultFilter),
orderDirection, orderBy, orderBySystemField, nodeIdSelect);
return processQuery(fullQuery, sqlNodeIdsWithSort);
return processQuery(fullQuery);
}
else
{
@@ -498,11 +476,11 @@ namespace Umbraco.Core.Persistence.Repositories
protected IDictionary<int, PropertyCollection> GetPropertyCollection(
Sql docSql,
IReadOnlyCollection<DocumentDefinition> documentDefs)
IEnumerable<DocumentDefinition> documentDefs)
{
if (documentDefs.Count == 0) return new Dictionary<int, PropertyCollection>();
if (documentDefs.Any() == false) return new Dictionary<int, PropertyCollection>();
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
// the statement to go get the property data for all of the items by using an inner join
var parsedOriginalSql = "SELECT {0} " + docSql.SQL.Substring(docSql.SQL.IndexOf("FROM", StringComparison.Ordinal));
//now remove everything from an Orderby clause and beyond
@@ -511,12 +489,23 @@ namespace Umbraco.Core.Persistence.Repositories
parsedOriginalSql = parsedOriginalSql.Substring(0, parsedOriginalSql.LastIndexOf("ORDER BY ", StringComparison.Ordinal));
}
//This retrieves all pre-values for all data types that are referenced for all property types
// that exist in the data set.
//Benchmarks show that eagerly loading these so that we can lazily read the property data
// below (with the use of Query intead of Fetch) go about 30% faster, so we'll eagerly load
// this now since we cannot execute another reader inside of reading the property data.
var preValsSql = new Sql(@"SELECT a.id, a.value, a.sortorder, a.alias, a.datatypeNodeId
var propSql = new Sql(@"SELECT cmsPropertyData.*
FROM cmsPropertyData
INNER JOIN cmsPropertyType
ON cmsPropertyData.propertytypeid = cmsPropertyType.id
INNER JOIN
(" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData
ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId
LEFT OUTER JOIN cmsDataTypePreValues
ON cmsPropertyType.dataTypeId = cmsDataTypePreValues.datatypeNodeId", docSql.Arguments);
var allPropertyData = Database.Fetch<PropertyDataDto>(propSql);
//This is a lazy access call to get all prevalue data for the data types that make up all of these properties which we use
// below if any property requires tag support
var allPreValues = new Lazy<IEnumerable<DataTypePreValueDto>>(() =>
{
var preValsSql = new Sql(@"SELECT a.id, a.value, a.sortorder, a.alias, a.datatypeNodeId
FROM cmsDataTypePreValues a
WHERE EXISTS(
SELECT DISTINCT b.id as preValIdInner
@@ -528,78 +517,25 @@ WHERE EXISTS(
ON cmsPropertyType.contentTypeId = docData.contentType
WHERE a.id = b.id)", docSql.Arguments);
var allPreValues = Database.Fetch<DataTypePreValueDto>(preValsSql);
//It's Important with the sort order here! We require this to be sorted by node id,
// this is required because this data set can be huge depending on the page size. Due
// to it's size we need to be smart about iterating over the property values to build
// the document. Before we used to use Linq to get the property data for a given content node
// and perform a Distinct() call. This kills performance because that would mean if we had 7000 nodes
// and on each iteration we will perform a lookup on potentially 100,000 property rows against the node
// id which turns out to be a crazy amount of iterations. Instead we know it's sorted by this value we'll
// keep an index stored of the rows being read so we never have to re-iterate the entire data set
// on each document iteration.
var propSql = new Sql(@"SELECT cmsPropertyData.*
FROM cmsPropertyData
INNER JOIN cmsPropertyType
ON cmsPropertyData.propertytypeid = cmsPropertyType.id
INNER JOIN
(" + string.Format(parsedOriginalSql, "cmsContent.nodeId, cmsContentVersion.VersionId") + @") as docData
ON cmsPropertyData.versionId = docData.VersionId AND cmsPropertyData.contentNodeId = docData.nodeId
ORDER BY contentNodeId, propertytypeid
", docSql.Arguments);
//This does NOT fetch all data into memory in a list, this will read
// over the records as a data reader, this is much better for performance and memory,
// but it means that during the reading of this data set, nothing else can be read
// from SQL server otherwise we'll get an exception.
var allPropertyData = Database.Query<PropertyDataDto>(propSql);
return Database.Fetch<DataTypePreValueDto>(preValsSql);
});
var result = new Dictionary<int, PropertyCollection>();
var propertiesWithTagSupport = new Dictionary<string, SupportTagsAttribute>();
//used to track the resolved composition property types per content type so we don't have to re-resolve (ToArray) the list every time
var resolvedCompositionProperties = new Dictionary<int, PropertyType[]>();
//keep track of the current property data item being enumerated
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
var hasCurrent = false; // initially there is no enumerator.Current
try
//iterate each definition grouped by it's content type - this will mean less property type iterations while building
// up the property collections
foreach (var compositionGroup in documentDefs.GroupBy(x => x.Composition))
{
//This must be sorted by node id because this is how we are sorting the query to lookup property types above,
// which allows us to more efficiently iterate over the large data set of property values
foreach (var def in documentDefs.OrderBy(x => x.Id))
var compositionProperties = compositionGroup.Key.CompositionPropertyTypes.ToArray();
foreach (var def in compositionGroup)
{
// get the resolved properties from our local cache, or resolve them and put them in cache
PropertyType[] compositionProperties;
if (resolvedCompositionProperties.ContainsKey(def.Composition.Id))
{
compositionProperties = resolvedCompositionProperties[def.Composition.Id];
}
else
{
compositionProperties = def.Composition.CompositionPropertyTypes.ToArray();
resolvedCompositionProperties[def.Composition.Id] = compositionProperties;
}
var propertyDataDtos = allPropertyData.Where(x => x.NodeId == def.Id).Distinct();
// assemble the dtos for this def
// use the available enumerator.Current if any else move to next
var propertyDataDtos = new List<PropertyDataDto>();
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
{
if (propertyDataSetEnumerator.Current.NodeId == def.Id)
{
hasCurrent = false; // enumerator.Current is not available
propertyDataDtos.Add(propertyDataSetEnumerator.Current);
}
else
{
hasCurrent = true; // enumerator.Current is available for another def
break; // no more propertyDataDto for this def
}
}
var properties = PropertyFactory.BuildEntity(propertyDataDtos, compositionProperties, def.CreateDate, def.VersionDate).ToArray();
var propertyFactory = new PropertyFactory(compositionProperties, def.Version, def.Id, def.CreateDate, def.VersionDate);
var properties = propertyFactory.BuildEntity(propertyDataDtos.ToArray()).ToArray();
foreach (var property in properties)
{
@@ -616,7 +552,7 @@ ORDER BY contentNodeId, propertytypeid
propertiesWithTagSupport[property.PropertyType.PropertyEditorAlias] = tagSupport;
//this property has tags, so we need to extract them and for that we need the prevals which we've already looked up
var preValData = allPreValues.Where(x => x.DataTypeNodeId == property.PropertyType.DataTypeDefinitionId)
var preValData = allPreValues.Value.Where(x => x.DataTypeNodeId == property.PropertyType.DataTypeDefinitionId)
.Distinct()
.ToArray();
@@ -639,13 +575,8 @@ ORDER BY contentNodeId, propertytypeid
result[def.Id] = new PropertyCollection(properties);
}
}
finally
{
propertyDataSetEnumerator.Dispose();
}
return result;
}
public class DocumentDefinition
@@ -757,12 +688,5 @@ ORDER BY contentNodeId, propertytypeid
return allsuccess;
}
/// <summary>
/// For Paging, repositories must support returning different query for the query type specified
/// </summary>
/// <param name="queryType"></param>
/// <returns></returns>
protected abstract Sql GetBaseQuery(BaseQueryType queryType);
}
}
+2 -32
View File
@@ -585,7 +585,7 @@ namespace Umbraco.Core.Services
[Obsolete("Use the overload with 'long' parameter types instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
public IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
{
long total;
var result = GetPagedDescendants(id, Convert.ToInt64(pageIndex), pageSize, out total, orderBy, orderDirection, true, filter);
@@ -604,7 +604,7 @@ namespace Umbraco.Core.Services
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
public IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
{
return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filter);
}
@@ -1764,31 +1764,6 @@ namespace Umbraco.Core.Services
return true;
}
/// <summary>
/// Gets paged content descendants as XML by path
/// </summary>
/// <param name="path">Path starts with</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of content items</returns>
public IEnumerable<XElement> GetPagedXmlEntries(string path, long pageIndex, int pageSize, out long totalRecords)
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize,
//This order by is VERY important! This allows us to figure out what is implicitly not published, see ContentRepository.BuildXmlCache and
// UmbracoContentIndexer.PerformIndexAll which uses the logic based on this sort order
new[] {"level", "parentID", "sortOrder"},
out totalRecords);
return contents;
}
}
/// <summary>
/// This builds the Xml document used for the XML cache
/// </summary>
@@ -2217,11 +2192,6 @@ namespace Umbraco.Core.Services
}
}
if (string.IsNullOrWhiteSpace(content.Name))
{
throw new ArgumentException("Cannot save content with empty name.");
}
using (new WriteLock(Locker))
{
var uow = UowProvider.GetUnitOfWork();
@@ -719,13 +719,8 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional id of the user saving the ContentType</param>
public void Save(IContentType contentType, int userId = 0)
{
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
return;
if (string.IsNullOrWhiteSpace(contentType.Name))
{
throw new ArgumentException("Cannot save content type with empty name.");
}
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
return;
using (new WriteLock(Locker))
{
+2 -7
View File
@@ -361,13 +361,8 @@ namespace Umbraco.Core.Services
/// <param name="userId">Id of the user issueing the save</param>
public void Save(IDataTypeDefinition dataTypeDefinition, int userId = 0)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
return;
if (string.IsNullOrWhiteSpace(dataTypeDefinition.Name))
{
throw new ArgumentException("Cannot save datatype with empty name.");
}
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IDataTypeDefinition>(dataTypeDefinition), this))
return;
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow))
+2 -16
View File
@@ -2,7 +2,6 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
@@ -96,19 +95,6 @@ namespace Umbraco.Core.Services
/// </summary>
public interface IContentService : IService
{
/// <summary>
/// Gets all XML entries found in the cmsContentXml table based on the given path
/// </summary>
/// <param name="path">Path starts with</param>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of content items</returns>
/// <remarks>
/// If -1 is passed, then this will return all content xml entries, otherwise will return all descendents from the path
/// </remarks>
IEnumerable<XElement> GetPagedXmlEntries(string path, long pageIndex, int pageSize, out long totalRecords);
/// <summary>
/// This builds the Xml document used for the XML cache
/// </summary>
@@ -259,7 +245,7 @@ namespace Umbraco.Core.Services
[Obsolete("Use the overload with 'long' parameter types instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
IEnumerable<IContent> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
@@ -273,7 +259,7 @@ namespace Umbraco.Core.Services
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IContent> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of <see cref="IContent"/> objects by Parent Id
+2 -2
View File
@@ -169,7 +169,7 @@ namespace Umbraco.Core.Services
[Obsolete("Use the overload with 'long' parameter types instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
@@ -183,7 +183,7 @@ namespace Umbraco.Core.Services
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "");
string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "");
/// <summary>
/// Gets a collection of <see cref="IMedia"/> objects by Parent Id
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Xml.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
@@ -14,15 +13,6 @@ namespace Umbraco.Core.Services
/// </summary>
public interface IMemberService : IMembershipMemberService
{
/// <summary>
/// Gets all XML entries found in the cmsContentXml table
/// </summary>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of content items</returns>
IEnumerable<XElement> GetPagedXmlEntries(long pageIndex, int pageSize, out long totalRecords);
/// <summary>
/// Rebuilds all xml content in the cmsContentXml table for all documents
/// </summary>
+11 -16
View File
@@ -142,24 +142,19 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the user deleting the macro</param>
public void Save(IMacro macro, int userId = 0)
{
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMacro>(macro), this))
return;
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMacro>(macro), this))
return;
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateMacroRepository(uow))
{
repository.AddOrUpdate(macro);
uow.Commit();
if (string.IsNullOrWhiteSpace(macro.Name))
{
throw new ArgumentException("Cannot save macro with empty name.");
}
Saved.RaiseEvent(new SaveEventArgs<IMacro>(macro, false), this);
}
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateMacroRepository(uow))
{
repository.AddOrUpdate(macro);
uow.Commit();
Saved.RaiseEvent(new SaveEventArgs<IMacro>(macro, false), this);
}
Audit(AuditType.Save, "Save Macro performed by user", userId, -1);
Audit(AuditType.Save, "Save Macro performed by user", userId, -1);
}
///// <summary>
+3 -7
View File
@@ -451,7 +451,7 @@ namespace Umbraco.Core.Services
[Obsolete("Use the overload with 'long' parameter types instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
public IEnumerable<IMedia> GetPagedDescendants(int id, int pageIndex, int pageSize, out int totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
{
long total;
var result = GetPagedDescendants(id, Convert.ToInt64(pageIndex), pageSize, out total, orderBy, orderDirection, true, filter);
@@ -470,7 +470,7 @@ namespace Umbraco.Core.Services
/// <param name="orderDirection">Direction to order by</param>
/// <param name="filter">Search text filter</param>
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
public IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "")
public IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "")
{
return GetPagedDescendants(id, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, true, filter);
}
@@ -837,11 +837,7 @@ namespace Umbraco.Core.Services
{
return OperationStatus.Cancelled(evtMsgs);
}
}
if (string.IsNullOrWhiteSpace(media.Name))
{
throw new ArgumentException("Cannot save media with empty name.");
}
var uow = UowProvider.GetUnitOfWork();
@@ -1228,7 +1224,7 @@ namespace Umbraco.Core.Services
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateMediaRepository(uow))
{
var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize, null, out totalRecords);
var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize, out totalRecords);
return contents;
}
}
@@ -612,26 +612,6 @@ namespace Umbraco.Core.Services
Audit(AuditType.Publish, "MemberService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, -1);
}
/// <summary>
/// Gets paged member descendants as XML by path
/// </summary>
/// <param name="pageIndex">Page number</param>
/// <param name="pageSize">Page size</param>
/// <param name="totalRecords">Total records the query would return without paging</param>
/// <returns>A paged enumerable of XML entries of member items</returns>
public IEnumerable<XElement> GetPagedXmlEntries(long pageIndex, int pageSize, out long totalRecords)
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateMemberRepository(uow))
{
var contents = repository.GetPagedXmlEntriesByPath("-1", pageIndex, pageSize, null, out totalRecords);
return contents;
}
}
#endregion
#region IMembershipMemberService Implementation
@@ -998,11 +978,6 @@ namespace Umbraco.Core.Services
}
}
if (string.IsNullOrWhiteSpace(entity.Name))
{
throw new ArgumentException("Cannot save member with empty name.");
}
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateMemberRepository(uow))
{
@@ -78,11 +78,6 @@ namespace Umbraco.Core.Services
if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IMemberType>(memberType), this))
return;
if (string.IsNullOrWhiteSpace(memberType.Name))
{
throw new ArgumentException("Cannot save MemberType with empty name.");
}
using (new WriteLock(Locker))
{
var uow = UowProvider.GetUnitOfWork();
-22
View File
@@ -125,11 +125,6 @@ namespace Umbraco.Core.Services
{
if (userType == null) throw new ArgumentNullException("userType");
if (string.IsNullOrWhiteSpace(username))
{
throw new ArgumentException("Cannot create user with empty username.");
}
//TODO: PUT lock here!!
var uow = UowProvider.GetUnitOfWork();
@@ -317,15 +312,6 @@ namespace Umbraco.Core.Services
return;
}
if (string.IsNullOrWhiteSpace(entity.Username))
{
throw new ArgumentException("Cannot save user with empty username.");
}
if (string.IsNullOrWhiteSpace(entity.Name))
{
throw new ArgumentException("Cannot save user with empty name.");
}
var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateUserRepository(uow))
{
@@ -367,14 +353,6 @@ namespace Umbraco.Core.Services
{
foreach (var member in entities)
{
if (string.IsNullOrWhiteSpace(member.Username))
{
throw new ArgumentException("Cannot save user with empty username.");
}
if (string.IsNullOrWhiteSpace(member.Name))
{
throw new ArgumentException("Cannot save user with empty name.");
}
repository.AddOrUpdate(member);
}
//commit the whole lot in one go
+24
View File
@@ -0,0 +1,24 @@
namespace Umbraco.Core.Sync
{
/// <summary>
/// The type of Cold Boot taking place
/// </summary>
public enum ColdBootType
{
/// <summary>
/// Indicates there was no cold boot
/// </summary>
NoColdBoot,
/// <summary>
/// This indicates that there is no lasysynced file for the current machine/appid
/// </summary>
NeverSynced,
/// <summary>
/// This indicates that the number of instructions needing to be processed exceeds the value stored
/// for the <see cref="DatabaseServerMessengerOptions.MaxProcessingInstructionCount"/>
/// </summary>
ExceedsMaxProcessingInstructionCount
}
}
@@ -43,6 +43,11 @@ namespace Umbraco.Core.Sync
protected DatabaseServerMessengerOptions Options { get; private set; }
protected ApplicationContext ApplicationContext { get { return _appContext; } }
/// <summary>
/// Returns the cold boot type detected for the current app domain
/// </summary>
public ColdBootType ColdBootType { get; private set; }
public DatabaseServerMessenger(ApplicationContext appContext, bool distributedEnabled, DatabaseServerMessengerOptions options)
: base(distributedEnabled)
{
@@ -146,11 +151,12 @@ namespace Umbraco.Core.Sync
/// </remarks>
private void Initialize()
{
ColdBootType = ColdBootType.NoColdBoot;
lock (_locko)
{
if (_released) return;
var coldboot = false;
if (_lastId < 0) // never synced before
{
// we haven't synced - in this case we aren't going to sync the whole thing, we will assume this is a new
@@ -159,7 +165,7 @@ namespace Umbraco.Core.Sync
+ " The server will build its caches and indexes, and then adjust its last synced Id to the latest found in"
+ " the database and maintain cache updates based on that Id.");
coldboot = true;
ColdBootType = ColdBootType.NeverSynced;
}
else
{
@@ -175,11 +181,11 @@ namespace Umbraco.Core.Sync
+ " to the latest found in the database and maintain cache updates based on that Id.",
() => count, () => Options.MaxProcessingInstructionCount);
coldboot = true;
ColdBootType = ColdBootType.ExceedsMaxProcessingInstructionCount;
}
}
if (coldboot)
if (ColdBootType != ColdBootType.NoColdBoot)
{
// go get the last id in the db and store it
// note: do it BEFORE initializing otherwise some instructions might get lost
+3 -4
View File
@@ -49,9 +49,8 @@
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="ImageProcessor, Version=2.5.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.5.2\lib\net45\ImageProcessor.dll</HintPath>
<Private>True</Private>
<Reference Include="ImageProcessor, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.5.1\lib\net45\ImageProcessor.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\log4net-mediumtrust.2.0.0\lib\log4net.dll</HintPath>
@@ -467,7 +466,6 @@
<Compile Include="Persistence\RecordPersistenceType.cs" />
<Compile Include="Persistence\Relators\AccessRulesRelator.cs" />
<Compile Include="Persistence\Repositories\AuditRepository.cs" />
<Compile Include="Persistence\Repositories\BaseQueryType.cs" />
<Compile Include="Persistence\Repositories\EntityContainerRepository.cs" />
<Compile Include="Persistence\Repositories\DomainRepository.cs" />
<Compile Include="Persistence\Repositories\ExternalLoginRepository.cs" />
@@ -1313,6 +1311,7 @@
<Compile Include="Strings\ContentBaseExtensions.cs" />
<Compile Include="Strings\Diff.cs" />
<Compile Include="Sync\BatchedWebServiceServerMessenger.cs" />
<Compile Include="Sync\ColdBootType.cs" />
<Compile Include="Sync\IServerRegistrar2.cs" />
<Compile Include="Sync\ServerRole.cs" />
<Compile Include="Sync\DatabaseServerMessenger.cs" />
+1 -1
View File
@@ -2,7 +2,7 @@
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="ImageProcessor" version="2.5.2" targetFramework="net45" />
<package id="ImageProcessor" version="2.5.1" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Identity.Owin" version="2.2.1" targetFramework="net45" />
@@ -67,66 +67,6 @@ namespace Umbraco.Tests.Persistence.Repositories
return repository;
}
/// <summary>
/// This tests the regression issue of U4-9438
/// </summary>
/// <remarks>
/// The problem was the iteration of the property data in VersionableRepositoryBase when a content item
/// in the list actually doesn't have any property types, it would still skip over a property row.
/// To test, we have 3 content items, the first has properties, the second doesn't and the third does.
/// </remarks>
[Test]
public void Property_Data_Assigned_Correctly()
{
// Arrange
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
ContentTypeRepository contentTypeRepository;
var allContent = new List<IContent>();
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
var emptyContentType = MockedContentTypes.CreateBasicContentType();
var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
var content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
var content2 = MockedContent.CreateBasicContent(emptyContentType);
var content3 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
// Act
contentTypeRepository.AddOrUpdate(emptyContentType);
contentTypeRepository.AddOrUpdate(hasPropertiesContentType);
repository.AddOrUpdate(content1);
repository.AddOrUpdate(content2);
repository.AddOrUpdate(content3);
unitOfWork.Commit();
allContent.Add(content1);
allContent.Add(content2);
allContent.Add(content3);
}
// Assert
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
{
//this will cause the GetPropertyCollection to execute and we need to ensure that
// all of the properties and property types are all correct
var result = repository.GetAll(allContent.Select(x => x.Id).ToArray()).ToArray();
foreach (var content in result)
{
foreach (var contentProperty in content.Properties)
{
//prior to the fix, the 2nd document iteration in the GetPropertyCollection would have caused
//the enumerator to move forward past the first property of the 3rd document which would have
//ended up not assiging a property to the 3rd document. This would have ended up with the 3rd
//document still having 3 properties but the last one would not have been assigned an identity
//because the property data would not have been assigned.
Assert.IsTrue(contentProperty.HasIdentity);
}
}
}
}
[Test]
public void Rebuild_Xml_Structures_With_Non_Latest_Version()
{
@@ -172,38 +172,6 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
[Test]
public void Can_Get_All_Containers()
{
var provider = new PetaPocoUnitOfWorkProvider(Logger);
var unitOfWork = provider.GetUnitOfWork();
EntityContainer container1, container2, container3;
using (var containerRepository = CreateContainerRepository(unitOfWork, Constants.ObjectTypes.DocumentTypeContainerGuid))
{
container1 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid) { Name = "container1" };
containerRepository.AddOrUpdate(container1);
container2 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid) { Name = "container2" };
containerRepository.AddOrUpdate(container2);
container3 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid) { Name = "container3" };
containerRepository.AddOrUpdate(container3);
unitOfWork.Commit();
Assert.That(container1.Id, Is.GreaterThan(0));
Assert.That(container2.Id, Is.GreaterThan(0));
Assert.That(container3.Id, Is.GreaterThan(0));
}
using (var containerRepository = CreateContainerRepository(unitOfWork, Constants.ObjectTypes.DocumentTypeContainerGuid))
{
var found1 = containerRepository.Get(container1.Id);
Assert.IsNotNull(found1);
var found2 = containerRepository.Get(container2.Id);
Assert.IsNotNull(found2);
var found3 = containerRepository.Get(container3.Id);
Assert.IsNotNull(found3);
var allContainers = containerRepository.GetAll();
Assert.AreEqual(3, allContainers.Count());
}
}
[Test]
public void Can_Delete_Container()
{
@@ -1,8 +1,6 @@
using System;
using System.Linq;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Store;
using Moq;
using NUnit.Framework;
@@ -33,15 +31,12 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Ensure_Children_Are_Sorted()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var result = searcher.Search(searcher.CreateSearchCriteria().Id(1111).Compile());
Assert.IsNotNull(result);
Assert.AreEqual(1, result.TotalItemCount);
@@ -65,15 +60,12 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Ensure_Result_Has_All_Values()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var result = searcher.Search(searcher.CreateSearchCriteria().Id(1111).Compile());
Assert.IsNotNull(result);
Assert.AreEqual(1, result.TotalItemCount);
@@ -27,7 +27,6 @@ using UmbracoExamine;
using UmbracoExamine.DataServices;
using umbraco.BusinessLogic;
using System.Linq;
using Lucene.Net.Index;
namespace Umbraco.Tests.PublishedContent
{
@@ -107,14 +106,11 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Ensure_Children_Sorted_With_Examine()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var ctx = GetUmbracoContext("/test", 1234);
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
@@ -139,14 +135,11 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Do_Not_Find_In_Recycle_Bin()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var ctx = GetUmbracoContext("/test", 1234);
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
@@ -182,14 +175,11 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Children_With_Examine()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var ctx = GetUmbracoContext("/test", 1234);
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
@@ -207,14 +197,11 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Descendants_With_Examine()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var ctx = GetUmbracoContext("/test", 1234);
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
@@ -232,14 +219,11 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void DescendantsOrSelf_With_Examine()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var ctx = GetUmbracoContext("/test", 1234);
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
@@ -257,15 +241,12 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void Ancestors_With_Examine()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
var ctx = GetUmbracoContext("/test", 1234);
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
@@ -279,15 +260,12 @@ namespace Umbraco.Tests.PublishedContent
[Test]
public void AncestorsOrSelf_With_Examine()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
using (var luceneDir = new RAMDirectory())
{
//var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir);
indexer.RebuildIndex();
var ctx = GetUmbracoContext("/test", 1234);
//var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var cache = new ContextualPublishedMediaCache(new PublishedMediaCache(ctx.Application, searcher, indexer), ctx);
//we are using the media.xml media to test the examine results implementation, see the media.xml file in the ExamineHelpers namespace
@@ -668,17 +668,6 @@ namespace Umbraco.Tests.Services
Assert.Throws<Exception>(() => contentService.CreateContent("Test", -1, "umbAliasDoesntExist"));
}
[Test]
public void Cannot_Save_Content_With_Empty_Name()
{
// Arrange
var contentService = ServiceContext.ContentService;
var content = new Content(string.Empty, -1, ServiceContext.ContentTypeService.GetContentType("umbTextpage"));
// Act & Assert
Assert.Throws<ArgumentException>(() => contentService.Save(content));
}
[Test]
public void Can_Get_Content_By_Id()
{
@@ -304,42 +304,6 @@ namespace Umbraco.Tests.Services
Assert.IsNull(deletedContentType);
}
[Test]
public void Can_Create_Container()
{
// Arrange
var cts = ServiceContext.ContentTypeService;
// Act
var container = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid);
container.Name = "container1";
cts.SaveContentTypeContainer(container);
// Assert
var createdContainer = cts.GetContentTypeContainer(container.Id);
Assert.IsNotNull(createdContainer);
}
[Test]
public void Can_Get_All_Containers()
{
// Arrange
var cts = ServiceContext.ContentTypeService;
// Act
var container1 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid);
container1.Name = "container1";
cts.SaveContentTypeContainer(container1);
var container2 = new EntityContainer(Constants.ObjectTypes.DocumentTypeGuid);
container2.Name = "container2";
cts.SaveContentTypeContainer(container2);
// Assert
var containers = cts.GetContentTypeContainers(new int[0]);
Assert.AreEqual(2, containers.Count());
}
[Test]
public void Deleting_ContentType_Sends_Correct_Number_Of_DeletedEntities_In_Events()
{
@@ -753,16 +717,6 @@ namespace Umbraco.Tests.Services
Assert.DoesNotThrow(() => service.GetContentType("advancedPage"));
}
[Test]
public void Cannot_Save_ContentType_With_Empty_Name()
{
// Arrange
var contentType = MockedContentTypes.CreateSimpleContentType("contentType", string.Empty);
// Act & Assert
Assert.Throws<ArgumentException>(() => ServiceContext.ContentTypeService.Save(contentType));
}
[Test]
public void Cannot_Rename_PropertyType_Alias_On_Composition_Which_Would_Cause_Conflict_In_Other_Composition()
{
@@ -221,18 +221,5 @@ namespace Umbraco.Tests.Services
Assert.AreEqual("preVal1", preVals.PreValuesAsArray.First().Value);
Assert.AreEqual("preVal2", preVals.PreValuesAsArray.Last().Value);
}
[Test]
public void Cannot_Save_DataType_With_Empty_Name()
{
// Arrange
var dataTypeService = ServiceContext.DataTypeService;
// Act
var dataTypeDefinition = new DataTypeDefinition(-1, "Test.TestEditor") { Name = string.Empty, DatabaseType = DataTypeDatabaseType.Ntext };
// Act & Assert
Assert.Throws<ArgumentException>(() => dataTypeService.Save(dataTypeDefinition));
}
}
}
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
@@ -218,17 +217,6 @@ namespace Umbraco.Tests.Services
}
[Test]
public void Cannot_Save_Macro_With_Empty_Name()
{
// Arrange
var macroService = ServiceContext.MacroService;
var macro = new Macro("test", string.Empty, scriptPath: "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
// Act & Assert
Assert.Throws<ArgumentException>(() => macroService.Save(macro));
}
//[Test]
//public void Can_Get_Many_By_Alias()
//{
@@ -81,19 +81,6 @@ namespace Umbraco.Tests.Services
Assert.That(mediaChild.Trashed, Is.False);
}
[Test]
public void Cannot_Save_Media_With_Empty_Name()
{
// Arrange
var mediaService = ServiceContext.MediaService;
var mediaType = MockedContentTypes.CreateVideoMediaType();
ServiceContext.ContentTypeService.Save(mediaType);
var media = mediaService.CreateMedia(string.Empty, -1, "video");
// Act & Assert
Assert.Throws<ArgumentException>(() => mediaService.Save(media));
}
[Test]
public void Ensure_Content_Xml_Created()
{
@@ -185,18 +185,6 @@ namespace Umbraco.Tests.Services
Assert.AreEqual(2, membersInRole.Count());
}
[Test]
public void Cannot_Save_Member_With_Empty_Name()
{
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
ServiceContext.MemberTypeService.Save(memberType);
IMember member = MockedMember.CreateSimpleMember(memberType, string.Empty, "test@test.com", "pass", "test");
// Act & Assert
Assert.Throws<ArgumentException>(() => ServiceContext.MemberService.Save(member));
}
[TestCase("MyTestRole1", "test1", StringPropertyMatchType.StartsWith, 1)]
[TestCase("MyTestRole1", "test", StringPropertyMatchType.StartsWith, 3)]
[TestCase("MyTestRole1", "test1", StringPropertyMatchType.Exact, 1)]
@@ -173,16 +173,6 @@ namespace Umbraco.Tests.Services
}
}
[Test]
public void Cannot_Save_MemberType_With_Empty_Name()
{
// Arrange
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType("memberTypeAlias", string.Empty);
// Act & Assert
Assert.Throws<ArgumentException>(() => ServiceContext.MemberTypeService.Save(memberType));
}
//[Test]
//public void Can_Save_MemberType_Structure_And_Create_A_Member_Based_On_It()
//{
@@ -490,43 +490,6 @@ namespace Umbraco.Tests.Services
Assert.IsTrue(result4.AllowedSections.Contains("test"));
}
[Test]
public void Cannot_Create_User_With_Empty_Username()
{
// Arrange
var userService = ServiceContext.UserService;
var userType = userService.GetUserTypeByAlias("admin");
// Act & Assert
Assert.Throws<ArgumentException>(() => userService.CreateUserWithIdentity(string.Empty, "john@umbraco.io", userType));
}
[Test]
public void Cannot_Save_User_With_Empty_Username()
{
// Arrange
var userService = ServiceContext.UserService;
var userType = userService.GetUserTypeByAlias("admin");
var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io", userType);
user.Username = string.Empty;
// Act & Assert
Assert.Throws<ArgumentException>(() => userService.Save(user));
}
[Test]
public void Cannot_Save_User_With_Empty_Name()
{
// Arrange
var userService = ServiceContext.UserService;
var userType = userService.GetUserTypeByAlias("admin");
var user = userService.CreateUserWithIdentity("John Doe", "john@umbraco.io", userType);
user.Name = string.Empty;
// Act & Assert
Assert.Throws<ArgumentException>(() => userService.Save(user));
}
[Test]
public void Get_By_Profile_Username()
{
@@ -6,18 +6,9 @@ namespace Umbraco.Tests.TestHelpers.Entities
{
public class MockedContent
{
public static Content CreateBasicContent(IContentType contentType)
{
var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
content.ResetDirtyProperties(false);
return content;
}
public static Content CreateSimpleContent(IContentType contentType)
{
var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
var content = new Content("Home", -1, contentType) { Language = "en-US", Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
object obj =
new
{
@@ -35,7 +26,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
public static Content CreateSimpleContent(IContentType contentType, string name, int parentId)
{
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 };
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
object obj =
new
{
@@ -53,7 +44,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
public static Content CreateSimpleContent(IContentType contentType, string name, IContent parent)
{
var content = new Content(name, parent, contentType) { CreatorId = 0, WriterId = 0 };
var content = new Content(name, parent, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
object obj =
new
{
@@ -71,7 +62,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
public static Content CreateTextpageContent(IContentType contentType, string name, int parentId)
{
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0};
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0};
object obj =
new
{
@@ -90,7 +81,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
public static Content CreateSimpleContentWithSpecialDatabaseTypes(IContentType contentType, string name, int parentId, string decimalValue, string intValue, DateTime datetimeValue)
{
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 };
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
object obj = new
{
decimalProperty = decimalValue,
@@ -105,7 +96,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
public static Content CreateAllTypesContent(IContentType contentType, string name, int parentId)
{
var content = new Content("Random Content Name", parentId, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
var content = new Content("Random Content Name", parentId, contentType) { Language = "en-US", Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
content.SetValue("isTrue", true);
content.SetValue("number", 42);
@@ -139,7 +130,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
for (int i = 0; i < amount; i++)
{
var name = "Textpage No-" + i;
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 };
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
object obj =
new
{
@@ -7,13 +7,6 @@ namespace Umbraco.Tests.TestHelpers.Entities
{
public class MockedContentTypes
{
/// <summary>
/// Creates a content type without any properties
/// </summary>
/// <param name="alias"></param>
/// <param name="name"></param>
/// <param name="parent"></param>
/// <returns></returns>
public static ContentType CreateBasicContentType(string alias = "basePage", string name = "Base Page",
ContentType parent = null)
{
+2 -4
View File
@@ -57,8 +57,8 @@
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.81.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.81\lib\net45\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
@@ -163,8 +163,6 @@
<Compile Include="Routing\NiceUrlRoutesTests.cs" />
<Compile Include="TestHelpers\Entities\MockedPropertyTypes.cs" />
<Compile Include="TryConvertToTests.cs" />
<Compile Include="UmbracoExamine\RandomIdRAMDirectory.cs" />
<Compile Include="UmbracoExamine\UmbracoContentIndexerTests.cs" />
<Compile Include="Web\AngularIntegration\AngularAntiForgeryTests.cs" />
<Compile Include="Web\AngularIntegration\ContentModelSerializationTests.cs" />
<Compile Include="Web\AngularIntegration\JsInitializationTests.cs" />
+37 -25
View File
@@ -1,8 +1,6 @@
using System;
using System.Linq;
using Examine;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Lucene.Net.Store;
using NUnit.Framework;
using Umbraco.Tests.TestHelpers;
@@ -17,39 +15,53 @@ namespace Umbraco.Tests.UmbracoExamine
[Test]
public void Events_Ignoring_Node()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
{
//change the parent id so that they are all ignored
var existingCriteria = indexer.IndexerData;
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
999); //change to 999
//change the parent id so that they are all ignored
var existingCriteria = _indexer.IndexerData;
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
999); //change to 999
var isIgnored = false;
var isIgnored = false;
EventHandler<IndexingNodeDataEventArgs> ignoringNode = (s, e) =>
{
isIgnored = true;
};
EventHandler<IndexingNodeDataEventArgs> ignoringNode = (s, e) =>
{
isIgnored = true;
};
indexer.IgnoringNode += ignoringNode;
_indexer.IgnoringNode += ignoringNode;
//get a node from the data repo
var node = _contentService.GetPublishedContentByXPath("//*[string-length(@id)>0 and number(@id)>0]")
.Root
.Elements()
.First();
//get a node from the data repo
var node = _contentService.GetPublishedContentByXPath("//*[string-length(@id)>0 and number(@id)>0]")
.Root
.Elements()
.First();
indexer.ReIndexNode(node, IndexTypes.Content);
_indexer.ReIndexNode(node, IndexTypes.Content);
Assert.IsTrue(isIgnored);
}
Assert.IsTrue(isIgnored);
}
private readonly TestContentService _contentService = new TestContentService();
private static UmbracoExamineSearcher _searcher;
private static UmbracoContentIndexer _indexer;
private Lucene.Net.Store.Directory _luceneDir;
public override void Initialize()
{
base.Initialize();
_luceneDir = new RAMDirectory();
_indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir);
_indexer.RebuildIndex();
_searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir);
}
public override void TearDown()
{
base.TearDown();
_luceneDir.Dispose();
}
}
}
@@ -7,7 +7,6 @@ using Examine.LuceneEngine.Config;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Lucene.Net.Store;
using Moq;
using Umbraco.Core;
@@ -34,7 +33,7 @@ namespace Umbraco.Tests.UmbracoExamine
internal static class IndexInitializer
{
public static UmbracoContentIndexer GetUmbracoIndexer(
IndexWriter writer,
Directory luceneDir,
Analyzer analyzer = null,
IDataService dataService = null,
IContentService contentService = null,
@@ -42,8 +41,7 @@ namespace Umbraco.Tests.UmbracoExamine
IDataTypeService dataTypeService = null,
IMemberService memberService = null,
IUserService userService = null,
IContentTypeService contentTypeService = null,
bool supportUnpublishedContent = false)
IContentTypeService contentTypeService = null)
{
if (dataService == null)
{
@@ -179,17 +177,15 @@ namespace Umbraco.Tests.UmbracoExamine
var indexCriteria = indexSet.ToIndexCriteria(dataService, UmbracoContentIndexer.IndexFieldPolicies);
var i = new UmbracoContentIndexer(indexCriteria,
writer,
dataService,
contentService,
mediaService,
dataTypeService,
userService,
contentTypeService,
false)
{
SupportUnpublishedContent = supportUnpublishedContent
};
luceneDir, //custom lucene directory
dataService,
contentService,
mediaService,
dataTypeService,
userService,
contentTypeService,
analyzer,
false);
//i.IndexSecondsInterval = 1;
@@ -197,14 +193,13 @@ namespace Umbraco.Tests.UmbracoExamine
return i;
}
public static UmbracoExamineSearcher GetUmbracoSearcher(IndexWriter writer, Analyzer analyzer = null)
public static UmbracoExamineSearcher GetUmbracoSearcher(Directory luceneDir, Analyzer analyzer = null)
{
if (analyzer == null)
{
analyzer = new StandardAnalyzer(Version.LUCENE_29);
}
return new UmbracoExamineSearcher(writer, analyzer);
return new UmbracoExamineSearcher(luceneDir, analyzer);
}
public static LuceneSearcher GetLuceneSearcher(Directory luceneDir)
+169 -181
View File
@@ -1,11 +1,11 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Examine;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Providers;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
@@ -15,230 +15,218 @@ using UmbracoExamine;
namespace Umbraco.Tests.UmbracoExamine
{
/// <summary>
/// Tests the standard indexing capabilities
/// </summary>
[DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)]
[TestFixture, RequiresSTA]
public class IndexTest : ExamineBaseTest
{
/// <summary>
/// Check that the node signalled as protected in the content service is not present in the index.
/// </summary>
[Test]
public void Index_Protected_Content_Not_Indexed()
{
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
{
indexer.RebuildIndex();
///// <summary>
/// <summary>
/// Check that the node signalled as protected in the content service is not present in the index.
/// </summary>
[Test]
public void Index_Protected_Content_Not_Indexed()
{
var protectedQuery = new BooleanQuery();
protectedQuery.Add(
new BooleanClause(
new TermQuery(new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content)),
BooleanClause.Occur.MUST));
var protectedQuery = new BooleanQuery();
protectedQuery.Add(
new BooleanClause(
new TermQuery(new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content)),
BooleanClause.Occur.MUST));
protectedQuery.Add(
new BooleanClause(
new TermQuery(new Term(LuceneIndexer.IndexNodeIdFieldName, TestContentService.ProtectedNode.ToString())),
BooleanClause.Occur.MUST));
protectedQuery.Add(
new BooleanClause(
new TermQuery(new Term(LuceneIndexer.IndexNodeIdFieldName, TestContentService.ProtectedNode.ToString())),
BooleanClause.Occur.MUST));
var collector = new AllHitsCollector(false, true);
var s = searcher.GetSearcher();
s.Search(protectedQuery, collector);
var collector = new AllHitsCollector(false, true);
var s = _searcher.GetSearcher();
s.Search(protectedQuery, collector);
Assert.AreEqual(0, collector.Count, "Protected node should not be indexed");
}
Assert.AreEqual(0, collector.Count, "Protected node should not be indexed");
}
}
[Test]
public void Index_Move_Media_From_Non_Indexable_To_Indexable_ParentID()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
{
indexer.RebuildIndex();
[Test]
public void Index_Move_Media_From_Non_Indexable_To_Indexable_ParentID()
{
//change parent id to 1116
var existingCriteria = _indexer.IndexerData;
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
1116);
//rebuild so it excludes children unless they are under 1116
_indexer.RebuildIndex();
var mediaService = new TestMediaService();
//ensure that node 2112 doesn't exist
var results = _searcher.Search(_searcher.CreateSearchCriteria().Id(2112).Compile());
Assert.AreEqual(0, results.Count());
//change parent id to 1116
var existingCriteria = indexer.IndexerData;
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
1116);
//get a node from the data repo (this one exists underneath 2222)
var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
.Root
.Elements()
.Where(x => (int)x.Attribute("id") == 2112)
.First();
//rebuild so it excludes children unless they are under 1116
indexer.RebuildIndex();
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
Assert.AreEqual("-1,1111,2222,2112", currPath);
//ensure that node 2112 doesn't exist
var results = searcher.Search(searcher.CreateSearchCriteria().Id(2112).Compile());
Assert.AreEqual(0, results.TotalItemCount);
//now mimic moving 2112 to 1116
//node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
node.SetAttributeValue("path", "-1,1116,2112");
node.SetAttributeValue("parentID", "1116");
//get a node from the data repo (this one exists underneath 2222)
var node = mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
.Root
.Elements()
.First(x => (int)x.Attribute("id") == 2112);
//now reindex the node, this should first delete it and then WILL add it because of the parent id constraint
_indexer.ReIndexNode(node, IndexTypes.Media);
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
Assert.AreEqual("-1,1111,2222,2112", currPath);
//RESET the parent id
existingCriteria = ((IndexCriteria)_indexer.IndexerData);
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
null);
//now mimic moving 2112 to 1116
//node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
node.SetAttributeValue("path", "-1,1116,2112");
node.SetAttributeValue("parentID", "1116");
//now ensure it's deleted
var newResults = _searcher.Search(_searcher.CreateSearchCriteria().Id(2112).Compile());
Assert.AreEqual(1, newResults.Count());
}
//now reindex the node, this should first delete it and then WILL add it because of the parent id constraint
indexer.ReIndexNode(node, IndexTypes.Media);
[Test]
[Ignore]
public void Index_Move_Media_To_Non_Indexable_ParentID()
{
//get a node from the data repo (this one exists underneath 2222)
var node = _mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
.Root
.Elements()
.Where(x => (int)x.Attribute("id") == 2112)
.First();
//RESET the parent id
existingCriteria = ((IndexCriteria)indexer.IndexerData);
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
null);
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
Assert.AreEqual("-1,1111,2222,2112", currPath);
//now ensure it's deleted
var newResults = searcher.Search(searcher.CreateSearchCriteria().Id(2112).Compile());
Assert.AreEqual(1, newResults.TotalItemCount);
}
//ensure it's indexed
_indexer.ReIndexNode(node, IndexTypes.Media);
}
//change the parent node id to be the one it used to exist under
var existingCriteria = _indexer.IndexerData;
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
2222);
[Test]
public void Index_Move_Media_To_Non_Indexable_ParentID()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
{
indexer.RebuildIndex();
//now mimic moving the node underneath 1116 instead of 2222
node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
node.SetAttributeValue("parentID", "1116");
var mediaService = new TestMediaService();
//now reindex the node, this should first delete it and then NOT add it because of the parent id constraint
_indexer.ReIndexNode(node, IndexTypes.Media);
//get a node from the data repo (this one exists underneath 2222)
var node = mediaService.GetLatestMediaByXpath("//*[string-length(@id)>0 and number(@id)>0]")
.Root
.Elements()
.First(x => (int)x.Attribute("id") == 2112);
//RESET the parent id
existingCriteria = ((IndexCriteria)_indexer.IndexerData);
_indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
null);
var currPath = (string)node.Attribute("path"); //should be : -1,1111,2222,2112
Assert.AreEqual("-1,1111,2222,2112", currPath);
//now ensure it's deleted
var results = _searcher.Search(_searcher.CreateSearchCriteria().Id(2112).Compile());
Assert.AreEqual(0, results.Count());
//ensure it's indexed
indexer.ReIndexNode(node, IndexTypes.Media);
//change the parent node id to be the one it used to exist under
var existingCriteria = indexer.IndexerData;
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
2222);
//now mimic moving the node underneath 1116 instead of 2222
node.SetAttributeValue("path", currPath.Replace("2222", "1116"));
node.SetAttributeValue("parentID", "1116");
//now reindex the node, this should first delete it and then NOT add it because of the parent id constraint
indexer.ReIndexNode(node, IndexTypes.Media);
//RESET the parent id
existingCriteria = ((IndexCriteria)indexer.IndexerData);
indexer.IndexerData = new IndexCriteria(existingCriteria.StandardFields, existingCriteria.UserFields, existingCriteria.IncludeNodeTypes, existingCriteria.ExcludeNodeTypes,
null);
//now ensure it's deleted
var results = searcher.Search(searcher.CreateSearchCriteria().Id(2112).Compile());
Assert.AreEqual(0, results.TotalItemCount);
}
}
}
/// <summary>
/// This will ensure that all 'Content' (not media) is cleared from the index using the Lucene API directly.
/// We then call the Examine method to re-index Content and do some comparisons to ensure that it worked correctly.
/// </summary>
[Test]
public void Index_Reindex_Content()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer, supportUnpublishedContent: true))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
{
indexer.RebuildIndex();
/// <summary>
/// This will ensure that all 'Content' (not media) is cleared from the index using the Lucene API directly.
/// We then call the Examine method to re-index Content and do some comparisons to ensure that it worked correctly.
/// </summary>
[Test]
public void Index_Reindex_Content()
{
var s = (IndexSearcher)_searcher.GetSearcher();
var s = (IndexSearcher)searcher.GetSearcher();
//first delete all 'Content' (not media). This is done by directly manipulating the index with the Lucene API, not examine!
var contentTerm = new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content);
var writer = _indexer.GetIndexWriter();
writer.DeleteDocuments(contentTerm);
writer.Commit();
//first delete all 'Content' (not media). This is done by directly manipulating the index with the Lucene API, not examine!
//make sure the content is gone. This is done with lucene APIs, not examine!
var collector = new AllHitsCollector(false, true);
var query = new TermQuery(contentTerm);
s = (IndexSearcher)_searcher.GetSearcher(); //make sure the searcher is up do date.
s.Search(query, collector);
Assert.AreEqual(0, collector.Count);
var contentTerm = new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content);
writer.DeleteDocuments(contentTerm);
writer.Commit();
//call our indexing methods
_indexer.IndexAll(IndexTypes.Content);
//make sure the content is gone. This is done with lucene APIs, not examine!
var collector = new AllHitsCollector(false, true);
var query = new TermQuery(contentTerm);
s = (IndexSearcher)searcher.GetSearcher(); //make sure the searcher is up do date.
s.Search(query, collector);
Assert.AreEqual(0, collector.Count);
collector = new AllHitsCollector(false, true);
s = (IndexSearcher)_searcher.GetSearcher(); //make sure the searcher is up do date.
s.Search(query, collector);
//var ids = new List<string>();
//for (var i = 0; i < collector.Count;i++)
//{
// ids.Add(s.Doc(collector.GetDocId(i)).GetValues("__NodeId")[0]);
//}
Assert.AreEqual(20, collector.Count);
}
//call our indexing methods
indexer.IndexAll(IndexTypes.Content);
/// <summary>
/// This will delete an item from the index and ensure that all children of the node are deleted too!
/// </summary>
[Test]
[Ignore]
public void Index_Delete_Index_Item_Ensure_Heirarchy_Removed()
{
collector = new AllHitsCollector(false, true);
s = (IndexSearcher)searcher.GetSearcher(); //make sure the searcher is up do date.
s.Search(query, collector);
//var ids = new List<string>();
//for (var i = 0; i < collector.Count;i++)
//{
// ids.Add(s.Doc(collector.GetDocId(i)).GetValues("__NodeId")[0]);
//}
Assert.AreEqual(21, collector.Count);
}
}
//now delete a node that has children
/// <summary>
/// This will delete an item from the index and ensure that all children of the node are deleted too!
/// </summary>
[Test]
public void Index_Delete_Index_Item_Ensure_Heirarchy_Removed()
{
_indexer.DeleteFromIndex(1140.ToString());
//this node had children: 1141 & 1142, let's ensure they are also removed
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
{
indexer.RebuildIndex();
var results = _searcher.Search(_searcher.CreateSearchCriteria().Id(1141).Compile());
Assert.AreEqual(0, results.Count());
//now delete a node that has children
results = _searcher.Search(_searcher.CreateSearchCriteria().Id(1142).Compile());
Assert.AreEqual(0, results.Count());
indexer.DeleteFromIndex(1140.ToString());
//this node had children: 1141 & 1142, let's ensure they are also removed
}
var results = searcher.Search(searcher.CreateSearchCriteria().Id(1141).Compile());
Assert.AreEqual(0, results.TotalItemCount);
#region Private methods and properties
results = searcher.Search(searcher.CreateSearchCriteria().Id(1142).Compile());
Assert.AreEqual(0, results.TotalItemCount);
}
}
#region Initialize and Cleanup
public override void TearDown()
{
base.TearDown();
private readonly TestContentService _contentService = new TestContentService();
private readonly TestMediaService _mediaService = new TestMediaService();
private static UmbracoExamineSearcher _searcher;
private static UmbracoContentIndexer _indexer;
#endregion
#region Initialize and Cleanup
private Lucene.Net.Store.Directory _luceneDir;
public override void TearDown()
{
base.TearDown();
_luceneDir.Dispose();
UmbracoExamineSearcher.DisableInitializationCheck = null;
BaseUmbracoIndexer.DisableInitializationCheck = null;
}
#endregion
}
public override void Initialize()
{
base.Initialize();
_luceneDir = new RAMDirectory();
_indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir);
_indexer.RebuildIndex();
_searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir);
}
#endregion
}
}
@@ -1,14 +0,0 @@
using System;
using Lucene.Net.Store;
namespace Umbraco.Tests.UmbracoExamine
{
public class RandomIdRAMDirectory : RAMDirectory
{
private readonly string _lockId = Guid.NewGuid().ToString();
public override string GetLockID()
{
return _lockId;
}
}
}
+31 -13
View File
@@ -8,8 +8,6 @@ using Examine.LuceneEngine.Providers;
using Lucene.Net.Store;
using NUnit.Framework;
using Examine.LuceneEngine.SearchCriteria;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.Index;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.UmbracoExamine
@@ -22,17 +20,19 @@ namespace Umbraco.Tests.UmbracoExamine
[Test]
public void Test_Sort_Order_Sorting()
{
using (var luceneDir = new RandomIdRAMDirectory())
using (var writer = new IndexWriter(luceneDir, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_29), IndexWriter.MaxFieldLength.LIMITED))
using (var indexer = IndexInitializer.GetUmbracoIndexer(writer, null,
//var newIndexFolder = new DirectoryInfo(Path.Combine("App_Data\\SearchTests", Guid.NewGuid().ToString()));
//System.IO.Directory.CreateDirectory(newIndexFolder.FullName);
using (var luceneDir = new RAMDirectory())
//using (var luceneDir = new SimpleFSDirectory(newIndexFolder))
{
var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir, null,
new TestDataService()
{
ContentService = new TestContentService(TestFiles.umbraco_sort)
},
supportUnpublishedContent: true))
using (var searcher = IndexInitializer.GetUmbracoSearcher(writer))
{
indexer.RebuildIndex();
{
ContentService = new TestContentService(TestFiles.umbraco_sort)
});
indexer.RebuildIndex();
var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
var s = (LuceneSearcher)searcher;
var luceneSearcher = s.GetSearcher();
@@ -69,7 +69,25 @@ namespace Umbraco.Tests.UmbracoExamine
currentSort = sort;
}
return true;
}
}
//[Test]
//public void Test_Index_Type_With_German_Analyzer()
//{
// using (var luceneDir = new RAMDirectory())
// {
// var indexer = IndexInitializer.GetUmbracoIndexer(luceneDir,
// new GermanAnalyzer());
// indexer.RebuildIndex();
// var searcher = IndexInitializer.GetUmbracoSearcher(luceneDir);
// }
//}
//private readonly TestContentService _contentService = new TestContentService();
//private readonly TestMediaService _mediaService = new TestMediaService();
//private static UmbracoExamineSearcher _searcher;
//private static UmbracoContentIndexer _indexer;
//private Lucene.Net.Store.Directory _luceneDir;
}
}
@@ -1,107 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using UmbracoExamine;
namespace Umbraco.Tests.UmbracoExamine
{
[TestFixture]
public class UmbracoContentIndexerTests : ExamineBaseTest
{
[Test]
public void Get_Serialized_Content_No_Published_Content()
{
var contentSet = new List<IContent>
{
Mock.Of<IContent>(c => c.Id == 1 && c.Path == "-1,1" && c.Published && c.Level == 1),
Mock.Of<IContent>(c => c.Id == 2 && c.Path == "-1,2" && c.Published && c.Level == 1),
Mock.Of<IContent>(c => c.Id == 3 && c.Path == "-1,3" && c.Published == false && c.Level == 1), // no
Mock.Of<IContent>(c => c.Id == 4 && c.Path == "-1,4" && c.Published == false && c.Level == 1), // no
Mock.Of<IContent>(c => c.Id == 5 && c.Path == "-1,1,5" && c.Published && c.Level == 2),
Mock.Of<IContent>(c => c.Id == 6 && c.Path == "-1,2,6" && c.Published == false && c.Level == 2), // no
Mock.Of<IContent>(c => c.Id == 7 && c.Path == "-1,3,7" && c.Published && c.Level == 2), // no
Mock.Of<IContent>(c => c.Id == 8 && c.Path == "-1,4,8" && c.Published && c.Level == 2), // no
Mock.Of<IContent>(c => c.Id == 9 && c.Path == "-1,4,9" && c.Published && c.Level == 2), // no
Mock.Of<IContent>(c => c.Id == 10 && c.Path == "-1,1,5,10" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 15 && c.Path == "-1,1,5,15" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 11 && c.Path == "-1,2,6,11" && c.Published && c.Level == 3), // no
Mock.Of<IContent>(c => c.Id == 16 && c.Path == "-1,2,6,16" && c.Published && c.Level == 3), // no
Mock.Of<IContent>(c => c.Id == 12 && c.Path == "-1,3,7,12" && c.Published && c.Level == 3), // no
Mock.Of<IContent>(c => c.Id == 17 && c.Path == "-1,3,7,17" && c.Published && c.Level == 3), // no
Mock.Of<IContent>(c => c.Id == 13 && c.Path == "-1,4,8,13" && c.Published && c.Level == 3), // no
Mock.Of<IContent>(c => c.Id == 18 && c.Path == "-1,4,8,18" && c.Published && c.Level == 3), // no
Mock.Of<IContent>(c => c.Id == 14 && c.Path == "-1,4,9,14" && c.Published && c.Level == 3), // no
Mock.Of<IContent>(c => c.Id == 19 && c.Path == "-1,4,9,19" && c.Published && c.Level == 3), // no
};
//ensure the rest of the required values are populted
foreach (var content in contentSet)
{
var mock = Mock.Get(content);
mock.Setup(x => x.ContentType).Returns(Mock.Of<IContentType>(type => type.Icon == "hello"));
}
contentSet.Sort((a, b) => Comparer<int>.Default.Compare(a.Level, b.Level));
var published = new HashSet<string>();
var result = UmbracoContentIndexer.GetSerializedContent(false, content => new XElement("test"), contentSet, published)
.WhereNotNull()
.ToArray();
Assert.AreEqual(5, result.Length);
}
[Test]
public void Get_Serialized_Content_With_Published_Content()
{
var contentSet = new List<IContent>
{
Mock.Of<IContent>(c => c.Id == 1 && c.Path == "-1,1" && c.Published && c.Level == 1),
Mock.Of<IContent>(c => c.Id == 2 && c.Path == "-1,2" && c.Published && c.Level == 1),
Mock.Of<IContent>(c => c.Id == 3 && c.Path == "-1,3" && c.Published == false && c.Level == 1),
Mock.Of<IContent>(c => c.Id == 4 && c.Path == "-1,4" && c.Published == false && c.Level == 1),
Mock.Of<IContent>(c => c.Id == 5 && c.Path == "-1,1,5" && c.Published && c.Level == 2),
Mock.Of<IContent>(c => c.Id == 6 && c.Path == "-1,2,6" && c.Published == false && c.Level == 2),
Mock.Of<IContent>(c => c.Id == 7 && c.Path == "-1,3,7" && c.Published && c.Level == 2),
Mock.Of<IContent>(c => c.Id == 8 && c.Path == "-1,4,8" && c.Published && c.Level == 2),
Mock.Of<IContent>(c => c.Id == 9 && c.Path == "-1,4,9" && c.Published && c.Level == 2),
Mock.Of<IContent>(c => c.Id == 10 && c.Path == "-1,1,5,10" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 15 && c.Path == "-1,1,5,15" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 11 && c.Path == "-1,2,6,11" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 16 && c.Path == "-1,2,6,16" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 12 && c.Path == "-1,3,7,12" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 17 && c.Path == "-1,3,7,17" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 13 && c.Path == "-1,4,8,13" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 18 && c.Path == "-1,4,8,18" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 14 && c.Path == "-1,4,9,14" && c.Published && c.Level == 3),
Mock.Of<IContent>(c => c.Id == 19 && c.Path == "-1,4,9,19" && c.Published && c.Level == 3),
};
//ensure the rest of the required values are populted
foreach (var content in contentSet)
{
var mock = Mock.Get(content);
mock.Setup(x => x.ContentType).Returns(Mock.Of<IContentType>(type => type.Icon == "hello"));
}
contentSet.Sort((a, b) => Comparer<int>.Default.Compare(a.Level, b.Level));
var published = new HashSet<string>();
var result = UmbracoContentIndexer.GetSerializedContent(true, content => new XElement("test"), contentSet, published)
.WhereNotNull()
.ToArray();
Assert.AreEqual(19, result.Length);
}
}
}
+1 -1
View File
@@ -2,7 +2,7 @@
<packages>
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="Examine" version="0.1.81" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
@@ -204,7 +204,7 @@ angular.module('umbraco.services')
//when it's successful, return the user data
setCurrentUser(data);
var result = { user: data, authenticated: true, lastUserId: lastUserId, loginType: "credentials" };
var result = { user: data, authenticated: true, lastUserId: lastUserId };
//broadcast a global event
eventsService.emit("app.authenticated", result);
@@ -232,7 +232,7 @@ angular.module('umbraco.services')
authResource.getCurrentUser()
.then(function (data) {
var result = { user: data, authenticated: true, lastUserId: lastUserId, loginType: "implicit" };
var result = { user: data, authenticated: true, lastUserId: lastUserId };
//TODO: This is a mega backwards compatibility hack... These variables SHOULD NOT exist in the server variables
// since they are not supposed to be dynamic but I accidentally added them there in 7.1.5 IIRC so some people might
@@ -8,7 +8,7 @@
* The main application controller
*
*/
function MainController($scope, $rootScope, $location, $routeParams, $timeout, $http, $log, appState, treeService, notificationsService, userService, navigationService, historyService, updateChecker, assetsService, eventsService, umbRequestHelper, tmhDynamicLocale, localStorageService) {
function MainController($scope, $rootScope, $location, $routeParams, $timeout, $http, $log, appState, treeService, notificationsService, userService, navigationService, historyService, updateChecker, assetsService, eventsService, umbRequestHelper, tmhDynamicLocale) {
//the null is important because we do an explicit bool check on this in the view
//the avatar is by default the umbraco logo
@@ -81,14 +81,6 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
$location.path("/").search("");
historyService.removeAll();
treeService.clearCache();
//if the user changed, clearout local storage too - could contain sensitive data
localStorageService.clearAll();
}
//if this is a new login (i.e. the user entered credentials), then clear out local storage - could contain sensitive data
if (data.loginType === "credentials") {
localStorageService.clearAll();
}
//Load locale file
+2 -3
View File
@@ -1,6 +1,6 @@
/** Executed when the application starts, binds to events and set global state */
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService',
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService) {
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache',
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache) {
//This sets the default jquery ajax headers to include our csrf token, we
// need to user the beforeSend method because our token changes per user/login so
@@ -13,7 +13,6 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
/** Listens for authentication and checks if our required assets are loaded, if/once they are we'll broadcast a ready event */
eventsService.on("app.authenticated", function(evt, data) {
assetsService._loadInitAssets().then(function() {
appState.setGlobalState("isReady", true);
@@ -1,7 +1,7 @@
//used for the media picker dialog
angular.module("umbraco")
.controller("Umbraco.Overlays.MediaPickerController",
function ($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, localStorageService, localizationService) {
function($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, $cookieStore, localizationService) {
if (!$scope.model.title) {
$scope.model.title = localizationService.localize("defaultdialogs_selectMedia");
@@ -15,7 +15,7 @@ angular.module("umbraco")
$scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false;
$scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
$scope.cropSize = dialogOptions.cropSize;
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
$scope.lastOpenedNode = $cookieStore.get("umbLastOpenedMediaNodeId");
if ($scope.onlyImages) {
$scope.acceptedFileTypes = mediaHelper
.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes);
@@ -133,7 +133,8 @@ angular.module("umbraco")
});
$scope.currentFolder = folder;
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
// for some reason i cannot set cookies with cookieStore
document.cookie = "umbLastOpenedMediaNodeId=" + folder.id;
};
@@ -34,24 +34,18 @@
fields: {},
file: file
}).progress(function (evt) {
// hack: in some browsers the progress event is called after success
// this prevents the UI from going back to a uploading state
if(vm.zipFile.uploadStatus !== "done" && vm.zipFile.uploadStatus !== "error") {
// set view state to uploading
vm.state = 'uploading';
// set view state to uploading
vm.state = 'uploading';
// calculate progress in percentage
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
// calculate progress in percentage
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
// set percentage property on file
vm.zipFile.uploadProgress = progressPercentage;
// set percentage property on file
vm.zipFile.uploadProgress = progressPercentage;
// set uploading status on file
vm.zipFile.uploadStatus = "uploading";
}
// set uploading status on file
vm.zipFile.uploadStatus = "uploading";
}).success(function (data, status, headers, config) {
@@ -12,8 +12,8 @@
<div class="umb-package-list__item" ng-repeat="installedPackage in vm.installedPackages">
<div class="umb-package-list__item-icon">
<i ng-if="!installedPackage.iconUrl" class="icon-box"></i>
<img ng-if="installedPackage.iconUrl" ng-src="{{installedPackage.iconUrl}}" />
<i ng-if="!installedPackage.icon" class="icon-box"></i>
<img ng-if="installedPackage.icon" ng-src="{{installedPackage.icon}}" />
</div>
<div class="umb-package-list__item-content">
@@ -2,7 +2,7 @@ angular.module("umbraco")
.controller("Umbraco.PropertyEditors.GoogleMapsController",
function ($element, $rootScope, $scope, notificationsService, dialogService, assetsService, $log, $timeout) {
assetsService.loadJs('https://www.google.com/jsapi')
assetsService.loadJs('http://www.google.com/jsapi')
.then(function () {
google.load("maps", "3",
{
+10 -12
View File
@@ -127,20 +127,19 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.81.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.81\lib\net45\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="ImageProcessor, Version=2.5.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.5.2\lib\net45\ImageProcessor.dll</HintPath>
<Private>True</Private>
<Reference Include="ImageProcessor, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.5.1\lib\net45\ImageProcessor.dll</HintPath>
</Reference>
<Reference Include="ImageProcessor.Web, Version=4.8.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.Web.4.8.2\lib\net45\ImageProcessor.Web.dll</HintPath>
<Private>True</Private>
<Reference Include="ImageProcessor.Web, Version=4.7.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.Web.4.7.2\lib\net45\ImageProcessor.Web.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=1.2.11.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -168,8 +167,7 @@
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.IO.RecyclableMemoryStream, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.1\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
<Private>True</Private>
<HintPath>..\packages\Microsoft.IO.RecyclableMemoryStream.1.2.0\lib\net45\Microsoft.IO.RecyclableMemoryStream.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Owin">
<HintPath>..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll</HintPath>
@@ -2423,9 +2421,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7590</DevelopmentServerPort>
<DevelopmentServerPort>7570</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7590</IISUrl>
<IISUrl>http://localhost:7570</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -13,7 +13,6 @@
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="Application/NamespaceManager.js" PathNameAlias="UmbracoClient" Priority="0" />
<umb:JsInclude ID="JsInclude3" runat="server" FilePath="ui/jquery.js" PathNameAlias="UmbracoClient" Priority="1" />
<umb:JsInclude ID="JsInclude4" runat="server" FilePath="lib/jquery-migrate/jquery-migrate.min.js" PathNameAlias="UmbracoRoot" Priority="1" />
<umb:JsInclude ID="JsInclude6" runat="server" FilePath="ui/base2.js" PathNameAlias="UmbracoClient" Priority="1" />
<umb:JsInclude ID="JsInclude11" runat="server" FilePath="UI/knockout.js" PathNameAlias="UmbracoClient" Priority="3" />
<umb:JsInclude ID="JsInclude12" runat="server" FilePath="UI/knockout.mapping.js" PathNameAlias="UmbracoClient" Priority="4" />
@@ -48,15 +48,6 @@ namespace Umbraco.Web.UI.Umbraco.Dashboard {
/// </remarks>
protected global::ClientDependency.Core.Controls.JsInclude JsInclude3;
/// <summary>
/// JsInclude4 control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::ClientDependency.Core.Controls.JsInclude JsInclude4;
/// <summary>
/// JsInclude6 control.
/// </summary>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<caching currentCache="DiskCache">
<caches>
<cache name="DiskCache" type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web" maxDays="365" browserMaxDays="7" trimCache="false">
<cache name="DiskCache" type="ImageProcessor.Web.Caching.DiskCache, ImageProcessor.Web" maxDays="365" browserMaxDays="7">
<settings>
<setting key="VirtualCachePath" value="~/app_data/cache" />
</settings>
+4 -4
View File
@@ -4,9 +4,9 @@
<package id="ClientDependency" version="1.9.2" targetFramework="net45" />
<package id="ClientDependency-Mvc5" version="1.8.0.0" targetFramework="net45" />
<package id="dotless" version="1.4.1.0" targetFramework="net45" />
<package id="Examine" version="0.1.81" targetFramework="net45" />
<package id="ImageProcessor" version="2.5.2" targetFramework="net45" />
<package id="ImageProcessor.Web" version="4.8.2" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="ImageProcessor" version="2.5.1" targetFramework="net45" />
<package id="ImageProcessor.Web" version="4.7.2" targetFramework="net45" />
<package id="ImageProcessor.Web.Config" version="2.3.0" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
@@ -22,7 +22,7 @@
<package id="Microsoft.CodeAnalysis.Analyzers" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.CodeAnalysis.Common" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.CodeAnalysis.CSharp" version="1.0.0" targetFramework="net45" />
<package id="Microsoft.IO.RecyclableMemoryStream" version="1.2.1" targetFramework="net45" />
<package id="Microsoft.IO.RecyclableMemoryStream" version="1.2.0" targetFramework="net45" />
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net45" />
<package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net45" />
@@ -1142,7 +1142,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<area alias="modelsBuilder">
<key alias="buildingModels">Building models</key>
<key alias="waitingMessage">this can take a bit of time, don't worry</key>
<key alias="waitingMessage">this can take abit of time, don't worry</key>
<key alias="modelsGenerated">Models generated</key>
<key alias="modelsGeneratedError">Models could not be generated</key>
<key alias="modelsExceptionInUlog">Models generation has failed, see exception in U log</key>
@@ -27,9 +27,6 @@
<key alias="publish">Опубликовать</key>
<key alias="refreshNode">Обновить узлы</key>
<key alias="republish">Опубликовать весь сайт</key>
<key alias="SetPermissionsForThePage">Установить разрешения для страницы '%0%'</key>
<key alias="chooseWhereToMove">Выберите, куда переместить</key>
<key alias="toInTheTreeStructureBelow">В структуре документов ниже</key>
<key alias="restore" version="7.3.0">Восстановить</key>
<key alias="rights">Разрешения</key>
<key alias="rollback">Откатить</key>
@@ -192,7 +189,7 @@
<key alias="memberrole">Роль участника</key>
<key alias="membertype">Тип участника</key>
<key alias="noDate">Дата не указана</key>
<key alias="nodeName">Заголовок ссылки</key>
<key alias="nodeName">Заголовок страницы</key>
<key alias="notmemberof">Не является членом групп(ы)</key>
<key alias="otherElements">Свойства</key>
<key alias="parentNotPublished">Этот документ опубликован, но скрыт, потому что его родительский документ '%0%' не опубликован</key>
@@ -344,10 +341,9 @@
<key alias="viewCacheItem">Просмотр элемента кэша</key>
<key alias="createFolder">Создать папку...</key>
<key alias="relateToOriginalLabel">Связать с оригиналом</key>
<key alias="includeDescendants">Включая все дочерние</key>
<key alias="theFriendliestCommunity">Самое дружелюбное сообщество</key>
<key alias="linkToPage">Ссылка на страницу</key>
<key alias="openInNewWindow">Открывать ссылку в новом окне или вкладке браузера</key>
<key alias="openInNewWindow">Открывает документ по ссылке в новом окне или вкладке браузера</key>
<key alias="linkToMedia">Ссылка на медиа-файл</key>
<key alias="selectMedia">Выбрать медиа</key>
<key alias="selectIcon">Выбрать значок</key>
@@ -131,7 +131,9 @@ namespace Umbraco.Web.Cache
ClearAllIsolatedCacheByEntityType<IMediaType>();
ClearAllIsolatedCacheByEntityType<IMember>();
ClearAllIsolatedCacheByEntityType<IMemberType>();
//all property type cache
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.PropertyTypeCacheKey);
//all content type property cache
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.ContentTypePropertiesCacheKey);
//all content type cache
@@ -264,6 +266,12 @@ namespace Umbraco.Web.Cache
/// </returns>
private static void ClearContentTypeCache(JsonPayload payload)
{
//clears the cache for each property type associated with the content type
foreach (var pid in payload.PropertyTypeIds)
{
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(CacheKeys.PropertyTypeCacheKey + pid);
}
//clears the cache associated with the Content type itself
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(string.Format("{0}{1}", CacheKeys.ContentTypeCacheKey, payload.Id));
//clears the cache associated with the content type properties collection
+2 -2
View File
@@ -74,7 +74,7 @@ namespace Umbraco.Web.Cache
public override void Remove(int id)
{
ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
content.Instance.ClearDocumentCache(id, false);
content.Instance.ClearDocumentCache(id);
DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
@@ -95,7 +95,7 @@ namespace Umbraco.Web.Cache
public override void Remove(IContent instance)
{
ApplicationContext.Current.ApplicationCache.ClearPartialViewCache();
content.Instance.ClearDocumentCache(new Document(instance), false);
content.Instance.ClearDocumentCache(new Document(instance));
XmlPublishedContent.ClearRequest();
DistributedCache.Instance.ClearAllMacroCacheOnCurrentServer();
DistributedCache.Instance.ClearXsltCacheOnCurrentServer();
+1 -1
View File
@@ -614,7 +614,7 @@ namespace Umbraco.Web.Editors
.Select(Mapper.Map<EntityBasic>);
// entities are in "some" order, put them back in order
var xref = entities.ToDictionary(x => x.Key);
var xref = entities.ToDictionary(x => x.Id);
var result = keysArray.Select(x => xref.ContainsKey(x) ? xref[x] : null).Where(x => x != null);
return result;
+4 -9
View File
@@ -4,26 +4,21 @@ using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Http;
using System.Web.SessionState;
using AutoMapper;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using umbraco;
using Umbraco.Core;
namespace Umbraco.Web.Editors
{
/// <summary>
/// API controller to deal with Macro data
/// </summary>
/// <remarks>
/// Note that this implements IRequiresSessionState which will enable HttpContext.Session - generally speaking we don't normally
/// enable this for webapi controllers, however since this controller is used to render macro content and macros can access
/// Session, we don't want it to throw null reference exceptions.
/// </remarks>
[PluginController("UmbracoApi")]
public class MacroController : UmbracoAuthorizedJsonController, IRequiresSessionState
public class MacroController : UmbracoAuthorizedJsonController
{
/// <summary>
/// Gets the macro parameters to be filled in for a particular macro
/// </summary>
@@ -129,6 +124,6 @@ namespace Umbraco.Web.Editors
"text/html");
return result;
}
}
}
+5 -98
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Net.Http;
@@ -28,7 +27,6 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using System.Linq;
using System.Runtime.Serialization;
using System.Web.Http.Controllers;
using Umbraco.Web.WebApi.Binders;
using Umbraco.Web.WebApi.Filters;
using umbraco;
@@ -38,7 +36,6 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Persistence.FaultHandling;
using Umbraco.Web.UI;
using Notification = Umbraco.Web.Models.ContentEditing.Notification;
using Umbraco.Core.Persistence;
namespace Umbraco.Web.Editors
{
@@ -47,22 +44,9 @@ namespace Umbraco.Web.Editors
/// access to ALL of the methods on this controller will need access to the media application.
/// </remarks>
[PluginController("UmbracoApi")]
[UmbracoApplicationAuthorize(Constants.Applications.Media)]
[MediaControllerControllerConfiguration]
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Media)]
public class MediaController : ContentControllerBase
{
/// <summary>
/// Configures this controller with a custom action selector
/// </summary>
private class MediaControllerControllerConfigurationAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetChildren", "id", typeof(int), typeof(Guid), typeof(string))));
}
}
/// <summary>
/// Constructor
/// </summary>
@@ -188,7 +172,7 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Returns the child media objects - using the entity INT id
/// Returns the child media objects
/// </summary>
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>), "Items")]
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(int id,
@@ -225,58 +209,6 @@ namespace Umbraco.Web.Editors
return pagedResult;
}
/// <summary>
/// Returns the child media objects - using the entity GUID id
/// </summary>
/// <param name="id"></param>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="orderBySystemField"></param>
/// <param name="filter"></param>
/// <returns></returns>
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>), "Items")]
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(Guid id,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
{
var entity = Services.EntityService.GetByKey(id);
if (entity != null)
{
return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
[Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(string id,
int pageNumber = 0,
int pageSize = 0,
string orderBy = "SortOrder",
Direction orderDirection = Direction.Ascending,
bool orderBySystemField = true,
string filter = "")
{
foreach (var type in new[] { typeof(int), typeof(Guid) })
{
var parsed = id.TryConvertTo(type);
if (parsed)
{
//oooh magic! will auto select the right overload
return GetChildren((dynamic)parsed.Result);
}
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
/// <summary>
/// Moves an item to the recycle bin, if it is already there then it will permanently delete it
/// </summary>
@@ -516,37 +448,12 @@ namespace Umbraco.Web.Editors
}
//get the string json from the request
int parentId; bool entityFound;
string currentFolderId = result.FormData["currentFolder"];
if (int.TryParse(currentFolderId, out parentId) == false)
int parentId;
if (int.TryParse(result.FormData["currentFolder"], out parentId) == false)
{
// if a guid then try to look up the entity
Guid idGuid;
if (Guid.TryParse(currentFolderId, out idGuid))
{
var entity = Services.EntityService.GetByKey(idGuid);
if (entity != null)
{
entityFound = true;
parentId = entity.Id;
}
else
{
throw new EntityNotFoundException(currentFolderId, "The passed id doesn't exist");
}
}
else
{
return Request.CreateValidationErrorResponse("The request was not formatted correctly, the currentFolder is not an integer or Guid");
}
if (entityFound == false)
{
return Request.CreateValidationErrorResponse("The request was not formatted correctly, the currentFolder is not an integer or Guid");
}
return Request.CreateValidationErrorResponse("The request was not formatted correctly, the currentFolder is not an integer");
}
//ensure the user has access to this folder by parent id!
if (CheckPermissions(
new Dictionary<string, object>(),
+1 -53
View File
@@ -11,11 +11,6 @@ using System.Net;
using System.Net.Http;
using Umbraco.Web.WebApi;
using Umbraco.Core.Services;
using Umbraco.Core.Models.EntityBase;
using System;
using System.ComponentModel;
using System.Web.Http.Controllers;
using Umbraco.Core;
namespace Umbraco.Web.Editors
{
@@ -29,21 +24,8 @@ namespace Umbraco.Web.Editors
[PluginController("UmbracoApi")]
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes)]
[EnableOverrideAuthorization]
[MediaTypeControllerControllerConfigurationAttribute]
public class MediaTypeController : ContentTypeControllerBase
{
/// <summary>
/// Configures this controller with a custom action selector
/// </summary>
private class MediaTypeControllerControllerConfigurationAttribute : Attribute, IControllerConfiguration
{
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetAllowedChildren", "contentId", typeof(int), typeof(Guid), typeof(string))));
}
}
/// <summary>
/// Constructor
/// </summary>
@@ -188,7 +170,7 @@ namespace Umbraco.Web.Editors
/// <summary>
/// Returns the allowed child content type objects for the content item id passed in - based on an INT id
/// Returns the allowed child content type objects for the content item id passed in
/// </summary>
/// <param name="contentId"></param>
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
@@ -232,40 +214,6 @@ namespace Umbraco.Web.Editors
return basics;
}
/// <summary>
/// Returns the allowed child content type objects for the content item id passed in - based on a GUID id
/// </summary>
/// <param name="contentId"></param>
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
public IEnumerable<ContentTypeBasic> GetAllowedChildren(Guid contentId)
{
var entity = ApplicationContext.Services.EntityService.GetByKey(contentId);
if (entity != null)
{
return GetAllowedChildren(entity.Id);
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
[Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")]
[EditorBrowsable(EditorBrowsableState.Never)]
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
public IEnumerable<ContentTypeBasic> GetAllowedChildren(string contentId)
{
foreach (var type in new[] { typeof(int), typeof(Guid) })
{
var parsed = contentId.TryConvertTo(type);
if (parsed)
{
//oooh magic! will auto select the right overload
return GetAllowedChildren((dynamic)parsed.Result);
}
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
/// <summary>
/// Move the media type
/// </summary>
@@ -1,84 +0,0 @@
using System;
using System.Linq;
using System.Web;
using System.Web.Http.Controllers;
using Umbraco.Core;
namespace Umbraco.Web.Editors
{
/// <summary>
/// This is used to auto-select specific actions on controllers that would otherwise be ambiguous based on a single parameter type
/// </summary>
/// <remarks>
/// As an example, lets say we have 2 methods: GetChildren(int id) and GetChildren(Guid id), by default Web Api won't allow this since
/// it won't know what to select, but if this Tuple is passed in new Tuple{string, string}("GetChildren", "id")
/// </remarks>
internal class ParameterSwapControllerActionSelector : ApiControllerActionSelector
{
private readonly ParameterSwapInfo[] _actions;
/// <summary>
/// Constructor accepting a list of action name + parameter name
/// </summary>
/// <param name="actions"></param>
public ParameterSwapControllerActionSelector(params ParameterSwapInfo[] actions)
{
_actions = actions;
}
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
var found = _actions.FirstOrDefault(x => controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Path).InvariantEndsWith(x.ActionName));
if (found != null)
{
var id = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query).Get(found.ParamName);
if (id != null)
{
var idTypes = found.SupportedTypes;
foreach (var idType in idTypes)
{
var converted = id.TryConvertTo(idType);
if (converted)
{
var method = MatchByType(idType, controllerContext, found);
if (method != null)
return method;
}
}
}
}
return base.SelectAction(controllerContext);
}
private static ReflectedHttpActionDescriptor MatchByType(Type idType, HttpControllerContext controllerContext, ParameterSwapInfo found)
{
var controllerType = controllerContext.Controller.GetType();
var methods = controllerType.GetMethods().Where(info => info.Name == found.ActionName).ToArray();
if (methods.Length > 1)
{
//choose the one that has the parameter with the T type
var method = methods.FirstOrDefault(x => x.GetParameters().FirstOrDefault(p => p.Name == found.ParamName && p.ParameterType == idType) != null);
return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, method);
}
return null;
}
internal class ParameterSwapInfo
{
public string ActionName { get; private set; }
public string ParamName { get; private set; }
public Type[] SupportedTypes { get; private set; }
public ParameterSwapInfo(string actionName, string paramName, params Type[] supportedTypes)
{
ActionName = actionName;
ParamName = paramName;
SupportedTypes = supportedTypes;
}
}
}
}
@@ -81,7 +81,7 @@ namespace Umbraco.Web
/// Use focal point, to generate an output image using the focal point instead of the predefined crop
/// </param>
/// <param name="useCropDimensions">
/// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters.
/// Use crop dimensions to have the output image sized according to the predefined crop sizes, this will override the width and height parameters>.
/// </param>
/// <param name="cacheBuster">
/// Add a serialised date of the last edit of the item to ensure client cache refresh when updated
@@ -81,7 +81,7 @@ namespace Umbraco.Web.Install.InstallSteps
{
var client = new System.Net.WebClient();
var values = new NameValueCollection { { "name", admin.Name }, { "email", admin.Email} };
client.UploadValues("https://shop.umbraco.com/base/Ecom/SubmitEmail/installer.aspx", values);
client.UploadValues("https://umbraco.com/base/Ecom/SubmitEmail/installer.aspx", values);
}
catch { /* fail in silence */ }
}
@@ -147,4 +147,4 @@ namespace Umbraco.Web.Install.InstallSteps
}
}
}
}
}
@@ -3,10 +3,8 @@ using System.Collections.Generic;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Web.WebApi;
namespace Umbraco.Web.Mvc
{
@@ -95,13 +93,6 @@ namespace Umbraco.Web.Mvc
}
//look in this namespace to create the controller
controllerPluginRoute.DataTokens.Add("Namespaces", new[] {controllerType.Namespace});
//Special case! Check if the controller type implements IRequiresSessionState and if so use our
//custom webapi session handler
if (typeof(IRequiresSessionState).IsAssignableFrom(controllerType))
{
controllerPluginRoute.RouteHandler = new SessionHttpControllerRouteHandler();
}
}
//Don't look anywhere else except this namespace!
@@ -109,9 +100,9 @@ namespace Umbraco.Web.Mvc
//constraints: only match controllers ending with 'controllerSuffixName' and only match this controller's ID for this route
if (controllerSuffixName.IsNullOrWhiteSpace() == false)
{
controllerPluginRoute.Constraints = new RouteValueDictionary(
new Dictionary<string, object>
{
controllerPluginRoute.Constraints = new RouteValueDictionary(
new Dictionary<string, object>
{
{"controller", @"(\w+)" + controllerSuffixName}
});
@@ -92,12 +92,7 @@ namespace Umbraco.Web.PropertyEditors
//swallow...on purpose, there's a chance that this isn't json and we don't want that to affect
// the website.
}
catch (ArgumentException)
{
//swallow on purpose to prevent this error:
// Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject.
}
}
}
}
@@ -202,13 +202,11 @@ namespace Umbraco.Web.Trees
/// <returns></returns>
protected override bool HasPathAccess(string id, FormDataCollection queryStrings)
{
var entity = GetEntityFromId(id);
if (entity == null)
var content = Services.ContentService.GetById(int.Parse(id));
if (content == null)
{
return false;
}
IContent content = Services.ContentService.GetById(entity.Id);
return Security.CurrentUser.HasPathAccess(content);
}
@@ -96,7 +96,7 @@ namespace Umbraco.Web.Trees
LogHelper.Warn<ContentTreeControllerBase>("The user " + Security.CurrentUser.Username + " does not have access to the tree node " + id);
return new TreeNodeCollection();
}
// So there's an alt id specified, it's not the root node and the user has access to it, great! But there's one thing we
// need to consider:
// If the tree is being rendered in a dialog view we want to render only the children of the specified id, but
@@ -110,7 +110,7 @@ namespace Umbraco.Web.Trees
id = Constants.System.Root.ToString(CultureInfo.InvariantCulture);
}
}
var entities = GetChildEntities(id);
nodes.AddRange(entities.Select(entity => GetSingleTreeNode(entity, id, queryStrings)).Where(node => node != null));
return nodes;
@@ -122,34 +122,23 @@ namespace Umbraco.Web.Trees
protected IEnumerable<IUmbracoEntity> GetChildEntities(string id)
{
// use helper method to ensure we support both integer and guid lookups
int iid;
// look up from GUID if it's not an integer
if (int.TryParse(id, out iid) == false)
{
var idEntity = GetEntityFromId(id);
if (idEntity == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
iid = idEntity.Id;
throw new InvalidCastException("The id for the media tree must be an integer");
}
//if a request is made for the root node data but the user's start node is not the default, then
// we need to return their start node data
if (iid == Constants.System.Root && UserStartNode != Constants.System.Root)
{
//just return their single start node, it will show up under the 'Content' label
var startNode = Services.EntityService.Get(UserStartNode, UmbracoObjectType);
if (startNode != null)
return new[] { startNode };
else
if (startNode == null)
{
throw new EntityNotFoundException(UserStartNode, "User's start content node could not be found");
}
return new[] { startNode };
}
return Services.EntityService.GetChildren(iid, UmbracoObjectType).ToArray();
@@ -187,9 +176,9 @@ namespace Umbraco.Web.Trees
{
id = altStartId;
}
var nodes = GetTreeNodesInternal(id, queryStrings);
//only render the recycle bin if we are not in dialog and the start id id still the root
if (IsDialog(queryStrings) == false && id == Constants.System.Root.ToInvariantString())
{
@@ -221,9 +210,8 @@ namespace Umbraco.Web.Trees
/// </remarks>
private TreeNodeCollection GetTreeNodesInternal(string id, FormDataCollection queryStrings)
{
IUmbracoEntity current = GetEntityFromId(id);
//before we get the children we need to see if this is a container node
var current = Services.EntityService.Get(int.Parse(id), UmbracoObjectType);
//test if the parent is a listview / container
if (current != null && current.IsContainer())
@@ -298,32 +286,5 @@ namespace Umbraco.Web.Trees
{
return allowedUserOptions.Select(x => x.Action).OfType<ActionBrowse>().Any();
}
/// <summary>
/// Get an entity via an id that can be either an integer or a Guid
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
internal IUmbracoEntity GetEntityFromId(string id)
{
IUmbracoEntity entity;
Guid idGuid = Guid.Empty;
int idInt;
if (Guid.TryParse(id, out idGuid))
{
entity = Services.EntityService.GetByKey(idGuid, UmbracoObjectType);
}
else if (int.TryParse(id, out idInt))
{
entity = Services.EntityService.Get(idInt, UmbracoObjectType);
}
else
{
return null;
}
return entity;
}
}
}
+2 -4
View File
@@ -112,8 +112,8 @@
<Reference Include="dotless.Core, Version=1.4.1.0, Culture=neutral, PublicKeyToken=96b446c9e63eae34, processorArchitecture=MSIL">
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.81.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.81\lib\net45\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.70.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.70.0\lib\Examine.dll</HintPath>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.4.9.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
<HintPath>..\packages\HtmlAgilityPack.1.4.9\lib\Net45\HtmlAgilityPack.dll</HintPath>
@@ -277,7 +277,6 @@
<Compile Include="Editors\EditorValidationResolver.cs" />
<Compile Include="Editors\EditorValidator.cs" />
<Compile Include="Editors\GravatarController.cs" />
<Compile Include="Editors\ParameterSwapControllerActionSelector.cs" />
<Compile Include="HealthCheck\Checks\Config\AbstractConfigCheck.cs" />
<Compile Include="HealthCheck\Checks\Config\AcceptableConfiguration.cs" />
<Compile Include="HealthCheck\Checks\Config\ConfigurationService.cs" />
@@ -956,7 +955,6 @@
<Compile Include="WebApi\NamespaceHttpControllerSelector.cs" />
<Compile Include="WebApi\PrefixlessBodyModelValidator.cs" />
<Compile Include="WebApi\PrefixlessBodyModelValidatorAttribute.cs" />
<Compile Include="WebApi\SessionHttpControllerRouteHandler.cs" />
<Compile Include="WebApi\UmbracoApiController.cs" />
<Compile Include="WebApi\UmbracoApiControllerBase.cs" />
<Compile Include="WebApi\UmbracoApiControllerResolver.cs" />
@@ -1,31 +0,0 @@
using System.Web;
using System.Web.Http.WebHost;
using System.Web.Routing;
using System.Web.SessionState;
namespace Umbraco.Web.WebApi
{
/// <summary>
/// A custom WebApi route handler that enables session on the HttpContext - use with caution!
/// </summary>
/// <remarks>
/// WebApi controllers (and REST in general) shouldn't have session state enabled since it's stateless,
/// enabling session state puts additional locks on requests so only use this when absolutley needed
/// </remarks>
internal class SessionHttpControllerRouteHandler : HttpControllerRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new SessionHttpControllerHandler(requestContext.RouteData);
}
/// <summary>
/// A custom WebApi handler that enables session on the HttpContext
/// </summary>
private class SessionHttpControllerHandler : HttpControllerHandler, IRequiresSessionState
{
public SessionHttpControllerHandler(RouteData routeData) : base(routeData)
{ }
}
}
}
@@ -166,8 +166,6 @@ namespace Umbraco.Web.WebServices
var msg = ValidateLuceneIndexer(indexerName, out indexer);
if (msg.IsSuccessStatusCode)
{
LogHelper.Info<ExamineManagementApiController>(string.Format("Rebuilding index '{0}'", indexerName));
//remove it in case there's a handler there alraedy
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
//now add a single handler
@@ -203,8 +201,6 @@ namespace Umbraco.Web.WebServices
//ensure it's not listening anymore
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
LogHelper.Info<ExamineManagementApiController>(string.Format("Rebuilding index '{0}' done, {1} items committed (can differ from the number of items in the index)", indexer.Name, indexer.CommitCount));
var cacheKey = "temp_indexing_op_" + indexer.Name;
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheItem(cacheKey);
}
@@ -270,10 +266,7 @@ namespace Umbraco.Web.WebServices
var val = p.GetValue(indexer, null);
if (val == null)
{
// Do not warn for new new attribute that is optional
if(string.Equals(p.Name, "DirectoryFactory", StringComparison.InvariantCultureIgnoreCase) == false)
LogHelper.Warn<ExamineManagementApiController>("Property value was null when setting up property on indexer: " + indexer.Name + " property: " + p.Name);
LogHelper.Warn<ExamineManagementApiController>("Property value was null when setting up property on indexer: " + indexer.Name + " property: " + p.Name);
val = string.Empty;
}
indexerModel.ProviderProperties.Add(p.Name, val.ToString());
+1 -1
View File
@@ -3,7 +3,7 @@
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="ClientDependency" version="1.9.2" targetFramework="net45" />
<package id="dotless" version="1.4.1.0" targetFramework="net45" />
<package id="Examine" version="0.1.81" targetFramework="net45" />
<package id="Examine" version="0.1.70.0" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Markdown" version="1.14.7" targetFramework="net45" />
@@ -394,11 +394,6 @@ namespace umbraco
}
public virtual void ClearDocumentCache(int documentId)
{
ClearDocumentCache(documentId, true);
}
internal virtual void ClearDocumentCache(int documentId, bool removeDbXmlEntry)
{
// Get the document
Document d;
@@ -413,7 +408,7 @@ namespace umbraco
ClearDocumentXmlCache(documentId);
return;
}
ClearDocumentCache(d, removeDbXmlEntry);
ClearDocumentCache(d);
}
/// <summary>
@@ -421,8 +416,7 @@ namespace umbraco
/// This means the node gets unpublished from the website.
/// </summary>
/// <param name="doc">The document</param>
/// <param name="removeDbXmlEntry"></param>
internal void ClearDocumentCache(Document doc, bool removeDbXmlEntry)
internal void ClearDocumentCache(Document doc)
{
var e = new DocumentCacheEventArgs();
FireBeforeClearDocumentCache(doc, e);
@@ -431,13 +425,8 @@ namespace umbraco
{
XmlNode x;
//Hack: this is here purely for backwards compat if someone for some reason is using the
// ClearDocumentCache(int documentId) method and expecting it to remove the xml
if (removeDbXmlEntry)
{
// remove from xml db cache
doc.XmlRemoveFromDB();
}
// remove from xml db cache
doc.XmlRemoveFromDB();
// clear xml cache
ClearDocumentXmlCache(doc.Id);
@@ -2,7 +2,6 @@ using System;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Collections;
using System.ComponentModel;
using System.IO;
using Umbraco.Core.IO;
using System.Linq;
@@ -12,8 +11,6 @@ namespace umbraco.controls
/// <summary>
/// Summary description for ContentTypeControl.
/// </summary>
[Obsolete("No longer used, will be removed in v8")]
[EditorBrowsable(EditorBrowsableState.Never)]
public class ContentTypeControl : uicontrols.TabView
{
public event System.EventHandler OnSave;
@@ -3,7 +3,6 @@ using System.Collections;
using System.Configuration.Provider;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
@@ -321,14 +320,13 @@ namespace umbraco.cms.presentation.user
}
// Populate dropdowns
var allContentTypes = Services.ContentTypeService.GetAllContentTypes().ToList();
foreach (var dt in allContentTypes)
{
cDocumentType.Items.Add(new ListItem(dt.Name, dt.Alias));
}
foreach (DocumentType dt in DocumentType.GetAllAsList())
cDocumentType.Items.Add(
new ListItem(dt.Text, dt.Alias)
);
// populate fields
var fields = new ArrayList();
ArrayList fields = new ArrayList();
cDescription.ID = "cDescription";
cCategories.ID = "cCategories";
cExcerpt.ID = "cExcerpt";
@@ -336,9 +334,9 @@ namespace umbraco.cms.presentation.user
cCategories.Items.Add(new ListItem(ui.Text("choose"), ""));
cExcerpt.Items.Add(new ListItem(ui.Text("choose"), ""));
foreach (var pt in allContentTypes.SelectMany(x => x.PropertyTypes).OrderBy(x => x.Name))
foreach (PropertyType pt in PropertyType.GetAll())
{
if (fields.Contains(pt.Alias) == false)
if (!fields.Contains(pt.Alias))
{
cDescription.Items.Add(new ListItem(string.Format("{0} ({1})", pt.Name, pt.Alias), pt.Alias));
cCategories.Items.Add(new ListItem(string.Format("{0} ({1})", pt.Name, pt.Alias), pt.Alias));
+1 -15
View File
@@ -49,7 +49,6 @@ namespace UmbracoExamine
/// <param name="indexPath"></param>
/// <param name="dataService"></param>
/// <param name="analyzer"></param>
/// <param name="async"></param>
protected BaseUmbracoIndexer(IIndexCriteria indexerData, DirectoryInfo indexPath, IDataService dataService, Analyzer analyzer, bool async)
: base(indexerData, indexPath, analyzer, async)
{
@@ -62,19 +61,6 @@ namespace UmbracoExamine
DataService = dataService;
}
/// <summary>
/// Creates an NRT indexer
/// </summary>
/// <param name="indexerData"></param>
/// <param name="writer"></param>
/// <param name="async"></param>
/// <param name="dataService"></param>
protected BaseUmbracoIndexer(IIndexCriteria indexerData, IndexWriter writer, IDataService dataService, bool async)
: base(indexerData, writer, async)
{
DataService = dataService;
}
#endregion
/// <summary>
@@ -109,7 +95,7 @@ namespace UmbracoExamine
/// Determines if the manager will call the indexing methods when content is saved or deleted as
/// opposed to cache being updated.
/// </summary>
public bool SupportUnpublishedContent { get; protected internal set; }
public bool SupportUnpublishedContent { get; protected set; }
/// <summary>
/// The data service used for retreiving and submitting data to the cms
@@ -14,7 +14,7 @@ namespace UmbracoExamine.Config
public static class IndexSetExtensions
{
internal static IIndexCriteria ToIndexCriteria(this IndexSet set, IDataService svc,
StaticFieldCollection indexFieldPolicies)
IEnumerable<StaticField> indexFieldPolicies)
{
return new LazyIndexCriteria(set, svc, indexFieldPolicies);
}
@@ -29,7 +29,7 @@ namespace UmbracoExamine.Config
/// <returns></returns>
public static IIndexCriteria ToIndexCriteria(this IndexSet set, IDataService svc)
{
return set.ToIndexCriteria(svc, new StaticFieldCollection());
return set.ToIndexCriteria(svc, Enumerable.Empty<StaticField>());
}
}
@@ -12,7 +12,7 @@ namespace UmbracoExamine.Config
public LazyIndexCriteria(
IndexSet set,
IDataService svc,
StaticFieldCollection indexFieldPolicies)
IEnumerable<StaticField> indexFieldPolicies)
{
if (set == null) throw new ArgumentNullException("set");
if (indexFieldPolicies == null) throw new ArgumentNullException("indexFieldPolicies");
@@ -35,9 +35,8 @@ namespace UmbracoExamine.Config
foreach (var u in userProps)
{
var field = new IndexField() { Name = u };
StaticField policy;
if (indexFieldPolicies.TryGetValue(u, out policy))
var policy = indexFieldPolicies.FirstOrDefault(x => x.Name == u);
if (policy != null)
{
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
@@ -56,9 +55,8 @@ namespace UmbracoExamine.Config
foreach (var s in sysProps)
{
var field = new IndexField() { Name = s };
StaticField policy;
if (indexFieldPolicies.TryGetValue(s, out policy))
var policy = indexFieldPolicies.FirstOrDefault(x => x.Name == s);
if (policy != null)
{
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
@@ -1,28 +0,0 @@
using System.Collections.ObjectModel;
namespace UmbracoExamine
{
internal class StaticFieldCollection : KeyedCollection<string, StaticField>
{
protected override string GetKeyForItem(StaticField item)
{
return item.Name;
}
/// <summary>
/// Implements TryGetValue using the underlying dictionary
/// </summary>
/// <param name="key"></param>
/// <param name="field"></param>
/// <returns></returns>
public bool TryGetValue(string key, out StaticField field)
{
if (Dictionary == null)
{
field = null;
return false;
}
return Dictionary.TryGetValue(key, out field);
}
}
}

Some files were not shown because too many files have changed in this diff Show More