diff --git a/src/Umbraco.Core/CodeAnnotations/FriendlyNameAttribute.cs b/src/Umbraco.Core/CodeAnnotations/FriendlyNameAttribute.cs
index 54d47cca17..226b74266b 100644
--- a/src/Umbraco.Core/CodeAnnotations/FriendlyNameAttribute.cs
+++ b/src/Umbraco.Core/CodeAnnotations/FriendlyNameAttribute.cs
@@ -5,6 +5,7 @@ namespace Umbraco.Core.CodeAnnotations
///
/// Attribute to add a Friendly Name string with an UmbracoObjectType enum value
///
+ [AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
internal class FriendlyNameAttribute : Attribute
{
///
diff --git a/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs b/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs
index e6f887a2c8..8a44ba1589 100644
--- a/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs
+++ b/src/Umbraco.Core/CodeAnnotations/UmbracoObjectTypeAttribute.cs
@@ -5,6 +5,7 @@ namespace Umbraco.Core.CodeAnnotations
///
/// Attribute to associate a GUID string and Type with an UmbracoObjectType Enum value
///
+ [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
internal class UmbracoObjectTypeAttribute : Attribute
{
public UmbracoObjectTypeAttribute(string objectId)
diff --git a/src/Umbraco.Core/Models/UmbracoEntity.cs b/src/Umbraco.Core/Models/UmbracoEntity.cs
index ebb4477557..4791606d2c 100644
--- a/src/Umbraco.Core/Models/UmbracoEntity.cs
+++ b/src/Umbraco.Core/Models/UmbracoEntity.cs
@@ -18,6 +18,8 @@ namespace Umbraco.Core.Models
private bool _trashed;
private bool _hasChildren;
private bool _isPublished;
+ private bool _isDraft;
+ private bool _hasPendingChanges;
private Guid _nodeObjectTypeId;
private static readonly PropertyInfo CreatorIdSelector = ExpressionHelper.GetPropertyInfo(x => x.CreatorId);
@@ -29,6 +31,8 @@ namespace Umbraco.Core.Models
private static readonly PropertyInfo TrashedSelector = ExpressionHelper.GetPropertyInfo(x => x.Trashed);
private static readonly PropertyInfo HasChildrenSelector = ExpressionHelper.GetPropertyInfo(x => x.HasChildren);
private static readonly PropertyInfo IsPublishedSelector = ExpressionHelper.GetPropertyInfo(x => x.IsPublished);
+ private static readonly PropertyInfo IsDraftSelector = ExpressionHelper.GetPropertyInfo(x => x.IsDraft);
+ private static readonly PropertyInfo HasPendingChangesSelector = ExpressionHelper.GetPropertyInfo(x => x.HasPendingChanges);
private static readonly PropertyInfo NodeObjectTypeIdSelector = ExpressionHelper.GetPropertyInfo(x => x.NodeObjectTypeId);
public UmbracoEntity()
@@ -157,6 +161,32 @@ namespace Umbraco.Core.Models
}
}
+ public bool IsDraft
+ {
+ get { return _isPublished; }
+ set
+ {
+ SetPropertyValueAndDetectChanges(o =>
+ {
+ _isDraft = value;
+ return _isDraft;
+ }, _isDraft, IsDraftSelector);
+ }
+ }
+
+ public bool HasPendingChanges
+ {
+ get { return _hasPendingChanges; }
+ set
+ {
+ SetPropertyValueAndDetectChanges(o =>
+ {
+ _hasPendingChanges = value;
+ return _hasPendingChanges;
+ }, _hasPendingChanges, HasPendingChangesSelector);
+ }
+ }
+
public Guid NodeObjectTypeId
{
get { return _nodeObjectTypeId; }
diff --git a/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs
index 84067fabd7..a97f1fe976 100644
--- a/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs
+++ b/src/Umbraco.Core/Models/UmbracoObjectTypesExtensions.cs
@@ -51,7 +51,15 @@ namespace Umbraco.Core.Models
if (UmbracoObjectTypeCache.ContainsKey(umbracoObjectType))
return UmbracoObjectTypeCache[umbracoObjectType];
- var attribute = umbracoObjectType.GetType().FirstAttribute();
+ var type = typeof(UmbracoObjectTypes);
+ var memInfo = type.GetMember(umbracoObjectType.ToString());
+ var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
+ false);
+
+ if (attributes.Length == 0)
+ return Guid.Empty;
+
+ var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
if (attribute == null)
return Guid.Empty;
@@ -77,7 +85,15 @@ namespace Umbraco.Core.Models
/// a string of the FriendlyName
public static string GetFriendlyName(this UmbracoObjectTypes umbracoObjectType)
{
- var attribute = umbracoObjectType.GetType().FirstAttribute();
+ var type = typeof(UmbracoObjectTypes);
+ var memInfo = type.GetMember(umbracoObjectType.ToString());
+ var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
+ false);
+
+ if (attributes.Length == 0)
+ return string.Empty;
+
+ var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
if (attribute == null)
return string.Empty;
diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
index e07110809c..e3fec16cf4 100644
--- a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs
@@ -1,4 +1,5 @@
-using System.Globalization;
+using System;
+using System.Globalization;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Repositories;
@@ -20,9 +21,16 @@ namespace Umbraco.Core.Persistence.Factories
ParentId = dto.ParentId,
Path = dto.Path,
SortOrder = dto.SortOrder,
- HasChildren = dto.Children > 0,
- IsPublished = dto.HasPublishedVersion.HasValue && dto.HasPublishedVersion.Value > 0
+ HasChildren = dto.Children > 0
};
+
+ entity.IsPublished = dto.PublishedVersion != default(Guid) ||
+ (dto.NewestVersion != default(Guid) && dto.PublishedVersion == dto.NewestVersion);
+ entity.IsDraft = dto.NewestVersion != default(Guid) &&
+ (dto.PublishedVersion == default(Guid) || dto.PublishedVersion != dto.NewestVersion);
+ entity.HasPendingChanges = dto.PublishedVersion != default(Guid) && dto.NewestVersion != default(Guid) &&
+ dto.PublishedVersion != dto.NewestVersion;
+
return entity;
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
index a7b221916c..a4a0e08e5d 100644
--- a/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/EntityRepository.cs
@@ -59,7 +59,7 @@ namespace Umbraco.Core.Persistence.Repositories
public virtual IUmbracoEntity Get(int id, Guid objectTypeId)
{
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
- var sql = GetBaseWhere(GetBase, isContent, objectTypeId, id).Append(GetGroupBy());
+ var sql = GetBaseWhere(GetBase, isContent, objectTypeId, id).Append(GetGroupBy(isContent));
var nodeDto = _work.Database.FirstOrDefault(sql);
if (nodeDto == null)
return null;
@@ -82,7 +82,7 @@ namespace Umbraco.Core.Persistence.Repositories
else
{
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
- var sql = GetBaseWhere(GetBase, isContent, objectTypeId).Append(GetGroupBy());
+ var sql = GetBaseWhere(GetBase, isContent, objectTypeId).Append(GetGroupBy(isContent));
var dtos = _work.Database.Fetch(sql);
var factory = new UmbracoEntityFactory();
@@ -99,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sqlClause = GetBase(false);
var translator = new SqlTranslator(sqlClause, query);
- var sql = translator.Translate().Append(GetGroupBy());
+ var sql = translator.Translate().Append(GetGroupBy(false));
var dtos = _work.Database.Fetch(sql);
@@ -114,7 +114,7 @@ namespace Umbraco.Core.Persistence.Repositories
bool isContent = objectTypeId == new Guid(Constants.ObjectTypes.Document);
var sqlClause = GetBaseWhere(GetBase, isContent, objectTypeId);
var translator = new SqlTranslator(sqlClause, query);
- var sql = translator.Translate().Append(GetGroupBy());
+ var sql = translator.Translate().Append(GetGroupBy(isContent));
var dtos = _work.Database.Fetch(sql);
@@ -143,22 +143,26 @@ namespace Umbraco.Core.Persistence.Repositories
"main.text",
"main.nodeObjectType",
"main.createDate",
- "COUNT(parent.parentID) as children",
- isContent
- ? "SUM(CONVERT(int, document.published)) as published"
- : "SUM(0) as published"
+ "COUNT(parent.parentID) as children"
};
+ if (isContent)
+ {
+ columns.Add("published.versionId as publishedVerison");
+ columns.Add("latest.versionId as newestVersion");
+ }
+
var sql = new Sql()
.Select(columns.ToArray())
- .From("FROM umbracoNode main")
+ .From("umbracoNode main")
.LeftJoin("umbracoNode parent").On("parent.parentID = main.id");
- //NOTE Should this account for newest = 1 ? Scenarios: unsaved, saved not published, published
-
if (isContent)
- sql.LeftJoin("cmsDocument document").On("document.nodeId = main.id");
+ {
+ sql.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE published = 1 GROUP BY nodeId, versionId) as published").On("main.id = published.nodeId");
+ sql.LeftJoin("(SELECT nodeId, versionId FROM cmsDocument WHERE newest = 1 GROUP BY nodeId, versionId) as latest").On("main.id = latest.nodeId");
+ }
return sql;
}
@@ -174,7 +178,7 @@ namespace Umbraco.Core.Persistence.Repositories
{
var sql = baseQuery(isContent)
.Where("main.id = @Id", new {Id = id})
- .Append(GetGroupBy());
+ .Append(GetGroupBy(isContent));
return sql;
}
@@ -186,12 +190,31 @@ namespace Umbraco.Core.Persistence.Repositories
return sql;
}
- protected virtual Sql GetGroupBy()
+ protected virtual Sql GetGroupBy(bool isContent)
{
+ var columns = new List