diff --git a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs
index 0ae721943d..14fef80f0d 100644
--- a/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs
+++ b/src/Umbraco.Core/Cache/DeepCloneRuntimeCacheProvider.cs
@@ -26,6 +26,9 @@ namespace Umbraco.Core.Cache
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
{
+ if (innerProvider.GetType() == typeof(DeepCloneRuntimeCacheProvider))
+ throw new InvalidOperationException("A " + typeof(DeepCloneRuntimeCacheProvider) + " cannot wrap another instance of " + typeof(DeepCloneRuntimeCacheProvider));
+
InnerProvider = innerProvider;
}
@@ -105,9 +108,11 @@ namespace Umbraco.Core.Cache
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
if (value == null) return null; // do not store null values (backward compat)
+ //Clone/reset to go into the cache
return CheckCloneableAndTracksChanges(value);
}, timeout, isSliding, priority, removedCallback, dependentFiles);
+ //Clone/reset to go out of the cache
return CheckCloneableAndTracksChanges(cached);
}
diff --git a/src/Umbraco.Core/Models/Content.cs b/src/Umbraco.Core/Models/Content.cs
index ec73e1ff5e..cef06ec4f7 100644
--- a/src/Umbraco.Core/Models/Content.cs
+++ b/src/Umbraco.Core/Models/Content.cs
@@ -274,6 +274,9 @@ namespace Umbraco.Core.Models
///
public bool HasPublishedVersion { get { return PublishedVersionGuid != default(Guid); } }
+ [IgnoreDataMember]
+ internal DateTime PublishedDate { get; set; }
+
///
/// Changes the Trashed state of the content object
///
diff --git a/src/Umbraco.Core/Models/Rdbms/DocumentPublishedReadOnlyDto.cs b/src/Umbraco.Core/Models/Rdbms/DocumentPublishedReadOnlyDto.cs
index 4a7e359d91..7c6507f499 100644
--- a/src/Umbraco.Core/Models/Rdbms/DocumentPublishedReadOnlyDto.cs
+++ b/src/Umbraco.Core/Models/Rdbms/DocumentPublishedReadOnlyDto.cs
@@ -19,5 +19,8 @@ namespace Umbraco.Core.Models.Rdbms
[Column("newest")]
public bool Newest { get; set; }
+
+ [Column("updateDate")]
+ public DateTime VersionDate { get; set; }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
index 5e170f47f4..ad35b81ffb 100644
--- a/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
+++ b/src/Umbraco.Core/ObjectResolution/ManyObjectsResolverBase.cs
@@ -22,6 +22,7 @@ namespace Umbraco.Core.ObjectResolution
private readonly string _httpContextKey;
private readonly List _instanceTypes = new List();
private IEnumerable _sortedValues;
+ private readonly Func _httpContextGetter;
private int _defaultPluginWeight = 100;
@@ -42,12 +43,7 @@ namespace Umbraco.Core.ObjectResolution
if (logger == null) throw new ArgumentNullException("logger");
CanResolveBeforeFrozen = false;
if (scope == ObjectLifetimeScope.HttpRequest)
- {
- if (HttpContext.Current == null)
- throw new InvalidOperationException("Use alternative constructor accepting a HttpContextBase object in order to set the lifetime scope to HttpRequest when HttpContext.Current is null");
-
- CurrentHttpContext = new HttpContextWrapper(HttpContext.Current);
- }
+ _httpContextGetter = () => new HttpContextWrapper(HttpContext.Current);
ServiceProvider = serviceProvider;
Logger = logger;
@@ -84,7 +80,7 @@ namespace Umbraco.Core.ObjectResolution
LifetimeScope = ObjectLifetimeScope.HttpRequest;
_httpContextKey = GetType().FullName;
ServiceProvider = serviceProvider;
- CurrentHttpContext = httpContext;
+ _httpContextGetter = () => httpContext;
_instanceTypes = new List();
InitializeAppInstances();
@@ -160,7 +156,16 @@ namespace Umbraco.Core.ObjectResolution
/// Gets or sets the used to initialize this object, if any.
///
/// If not null, then LifetimeScope will be ObjectLifetimeScope.HttpRequest.
- protected HttpContextBase CurrentHttpContext { get; private set; }
+ protected HttpContextBase CurrentHttpContext
+ {
+ get
+ {
+ var context = _httpContextGetter == null ? null : _httpContextGetter();
+ if (context == null)
+ throw new InvalidOperationException("Cannot use this resolver with lifetime 'HttpRequest' when there is no current HttpContext. Either use the ctor accepting an HttpContextBase, or use the resolver from within a request exclusively.");
+ return context;
+ }
+ }
///
/// Returns the service provider used to instantiate objects
@@ -196,7 +201,7 @@ namespace Umbraco.Core.ObjectResolution
///
/// Gets or sets the default type weight.
///
- /// Determines the weight of types that do not have a WeightAttribute set on
+ /// Determines the weight of types that do not have a WeightAttribute set on
/// them, when calling GetSortedValues.
protected virtual int DefaultPluginWeight
{
@@ -276,7 +281,7 @@ namespace Umbraco.Core.ObjectResolution
/// Removes a type.
///
/// The type to remove.
- /// the resolver does not support removing types, or
+ /// the resolver does not support removing types, or
/// the type is not a valid type for the resolver.
public virtual void RemoveType(Type value)
{
@@ -296,7 +301,7 @@ namespace Umbraco.Core.ObjectResolution
/// Removes a type.
///
/// The type to remove.
- /// the resolver does not support removing types, or
+ /// the resolver does not support removing types, or
/// the type is not a valid type for the resolver.
public void RemoveType()
where T : TResolved
@@ -309,7 +314,7 @@ namespace Umbraco.Core.ObjectResolution
///
/// The types to add.
/// The types are appended at the end of the list.
- /// the resolver does not support adding types, or
+ /// the resolver does not support adding types, or
/// a type is not a valid type for the resolver, or a type is already in the collection of types.
protected void AddTypes(IEnumerable types)
{
@@ -336,7 +341,7 @@ namespace Umbraco.Core.ObjectResolution
///
/// The type to add.
/// The type is appended at the end of the list.
- /// the resolver does not support adding types, or
+ /// the resolver does not support adding types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.
public virtual void AddType(Type value)
{
@@ -362,7 +367,7 @@ namespace Umbraco.Core.ObjectResolution
///
/// The type to add.
/// The type is appended at the end of the list.
- /// the resolver does not support adding types, or
+ /// the resolver does not support adding types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.
public void AddType()
where T : TResolved
@@ -404,7 +409,7 @@ namespace Umbraco.Core.ObjectResolution
///
/// The zero-based index at which the type should be inserted.
/// The type to insert.
- /// the resolver does not support inserting types, or
+ /// the resolver does not support inserting types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.
/// is out of range.
public virtual void InsertType(int index, Type value)
@@ -430,7 +435,7 @@ namespace Umbraco.Core.ObjectResolution
/// Inserts a type at the beginning of the list.
///
/// The type to insert.
- /// the resolver does not support inserting types, or
+ /// the resolver does not support inserting types, or
/// the type is not a valid type for the resolver, or the type is already in the collection of types.
public virtual void InsertType(Type value)
{
@@ -464,7 +469,7 @@ namespace Umbraco.Core.ObjectResolution
///
/// The existing type before which to insert.
/// The type to insert.
- /// the resolver does not support inserting types, or
+ /// the resolver does not support inserting types, or
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
/// or the new type is already in the collection of types.
public virtual void InsertTypeBefore(Type existingType, Type value)
@@ -498,7 +503,7 @@ namespace Umbraco.Core.ObjectResolution
///
/// The existing type before which to insert.
/// The type to insert.
- /// the resolver does not support inserting types, or
+ /// the resolver does not support inserting types, or
/// one of the types is not a valid type for the resolver, or the existing type is not in the collection,
/// or the new type is already in the collection of types.
public void InsertTypeBefore()
diff --git a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
index 0532eab6b1..512f02e8b5 100644
--- a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs
@@ -72,6 +72,9 @@ namespace Umbraco.Core.Persistence.Factories
content.PublishedVersionGuid = publishedDto == null
? (dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId)
: publishedDto.VersionId;
+ content.PublishedDate = publishedDto == null
+ ? (dto.DocumentPublishedReadOnlyDto == null ? default(DateTime) : dto.DocumentPublishedReadOnlyDto.VersionDate)
+ : publishedDto.VersionDate;
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
index ae656b3f5b..a34a77d3b4 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
@@ -513,11 +513,13 @@ namespace Umbraco.Core.Persistence.Repositories
dto.DocumentPublishedReadOnlyDto = new DocumentPublishedReadOnlyDto
{
VersionId = dto.VersionId,
+ VersionDate = dto.UpdateDate,
Newest = true,
NodeId = dto.NodeId,
- Published = true
+ Published = true
};
- ((Content)entity).PublishedVersionGuid = dto.VersionId;
+ ((Content) entity).PublishedVersionGuid = dto.VersionId;
+ ((Content) entity).PublishedDate = dto.UpdateDate;
}
entity.ResetDirtyProperties();
@@ -688,22 +690,26 @@ namespace Umbraco.Core.Persistence.Repositories
dto.DocumentPublishedReadOnlyDto = new DocumentPublishedReadOnlyDto
{
VersionId = dto.VersionId,
+ VersionDate = dto.UpdateDate,
Newest = true,
NodeId = dto.NodeId,
Published = true
};
- ((Content)entity).PublishedVersionGuid = dto.VersionId;
+ ((Content) entity).PublishedVersionGuid = dto.VersionId;
+ ((Content) entity).PublishedDate = dto.UpdateDate;
}
else if (publishedStateChanged)
{
dto.DocumentPublishedReadOnlyDto = new DocumentPublishedReadOnlyDto
{
- VersionId = default(Guid),
+ VersionId = default (Guid),
+ VersionDate = default (DateTime),
Newest = false,
NodeId = dto.NodeId,
Published = false
};
- ((Content)entity).PublishedVersionGuid = default(Guid);
+ ((Content) entity).PublishedVersionGuid = default(Guid);
+ ((Content) entity).PublishedDate = default (DateTime);
}
entity.ResetDirtyProperties();
@@ -975,7 +981,7 @@ order by umbracoNode.{2}, umbracoNode.parentID, umbracoNode.sortOrder",
}
//order by update date DESC, if there is corrupted published flags we only want the latest!
- var publishedSql = new Sql(@"SELECT cmsDocument.nodeId, cmsDocument.published, cmsDocument.versionId, cmsDocument.newest
+ var publishedSql = new Sql(@"SELECT cmsDocument.nodeId, cmsDocument.published, cmsDocument.versionId, cmsDocument.updateDate, cmsDocument.newest
FROM cmsDocument INNER JOIN cmsContentVersion ON cmsContentVersion.VersionId = cmsDocument.versionId
WHERE cmsDocument.published = 1 AND cmsDocument.nodeId IN
(" + parsedOriginalSql + @")
diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
index c3387b1faf..13081cb2a4 100644
--- a/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/ContentTypeBaseRepository.cs
@@ -1252,5 +1252,19 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern",
while (aliases.Contains(test = alias + i)) i++;
return test;
}
+
+ ///
+ /// Given the path of a content item, this will return true if the content item exists underneath a list view content item
+ ///
+ ///
+ ///
+ public bool HasContainerInPath(string contentPath)
+ {
+ var ids = contentPath.Split(',').Select(int.Parse);
+ var sql = new Sql(@"SELECT COUNT(*) FROM cmsContentType
+INNER JOIN cmsContent ON cmsContentType.nodeId=cmsContent.contentType
+WHERE cmsContent.nodeId IN (@ids) AND cmsContentType.isContainer=@isContainer", new { ids, isContainer = true });
+ return Database.ExecuteScalar(sql) > 0;
+ }
}
}
diff --git a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs
index 071bf7eba8..e3da00b410 100644
--- a/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/DataTypeDefinitionRepository.cs
@@ -276,47 +276,33 @@ AND umbracoNode.id <> @id",
public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId)
{
- var cached = IsolatedCache.GetCacheItemsByKeySearch(GetPrefixedCacheKey(dataTypeId));
- if (cached != null && cached.Any())
- {
- //return from the cache, ensure it's a cloned result
- return (PreValueCollection)cached.First().DeepClone();
- }
-
- return GetAndCachePreValueCollection(dataTypeId);
- }
-
- internal static string GetCacheKeyRegex(int preValueId)
- {
- return CacheKeys.DataTypePreValuesCacheKey + @"[-\d]+-([\d]*,)*" + preValueId + @"(?!\d)[,\d$]*";
+ var collection = GetCachedPreValueCollection(dataTypeId);
+ return collection;
}
+ ///
+ /// Gets a specific PreValue by its Id
+ ///
+ /// Id of the PreValue to retrieve the value from
+ /// PreValue as a string
public string GetPreValueAsString(int preValueId)
{
- //We need to see if we can find the cached PreValueCollection based on the cache key above
+ var collections = RuntimeCache.GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + "_");
- var cached = IsolatedCache.GetCacheItemsByKeyExpression(GetCacheKeyRegex(preValueId));
- if (cached != null && cached.Any())
- {
- //return from the cache
- var collection = cached.First();
- var preVal = collection.FormatAsDictionary().Single(x => x.Value.Id == preValueId);
- return preVal.Value.Value;
- }
+ var preValue = collections.SelectMany(x => x.FormatAsDictionary().Values).FirstOrDefault(x => x.Id == preValueId);
+ if (preValue != null)
+ return preValue.Value;
- //go and find the data type id for the pre val id passed in
-
- var dto = Database.FirstOrDefault("WHERE id = @preValueId", new { preValueId = preValueId });
+ var dto = Database.FirstOrDefault("WHERE id = @preValueId", new { preValueId });
if (dto == null)
- {
return string.Empty;
- }
- // go cache the collection
- var preVals = GetAndCachePreValueCollection(dto.DataTypeNodeId);
- //return the single value for this id
- var pv = preVals.FormatAsDictionary().Single(x => x.Value.Id == preValueId);
- return pv.Value.Value;
+ var collection = GetCachedPreValueCollection(dto.DataTypeNodeId);
+ if (collection == null)
+ return string.Empty;
+
+ preValue = collection.FormatAsDictionary().Values.FirstOrDefault(x => x.Id == preValueId);
+ return preValue == null ? string.Empty : preValue.Value;
}
public void AddOrUpdatePreValues(int dataTypeId, IDictionary values)
@@ -441,40 +427,28 @@ AND umbracoNode.id <> @id",
sortOrder++;
}
-
}
- private string GetPrefixedCacheKey(int dataTypeId)
+ private static string GetPrefixedCacheKey(int dataTypeId)
{
- return CacheKeys.DataTypePreValuesCacheKey + dataTypeId + "-";
+ return CacheKeys.DataTypePreValuesCacheKey + "_" + dataTypeId;
}
- private PreValueCollection GetAndCachePreValueCollection(int dataTypeId)
+ private PreValueCollection GetCachedPreValueCollection(int datetypeId)
{
- //go get the data
- var dtos = Database.Fetch("WHERE datatypeNodeId = @Id", new { Id = dataTypeId });
- var list = dtos.Select(x => new Tuple(new PreValue(x.Id, x.Value, x.SortOrder), x.Alias, x.SortOrder)).ToList();
- var collection = PreValueConverter.ConvertToPreValuesCollection(list);
-
- //now create the cache key, this needs to include all pre-value ids so that we can use this cached item in the GetPreValuesAsString method
- //the key will be: "UmbracoPreValDATATYPEID-CSVOFPREVALIDS
-
- var key = GetPrefixedCacheKey(dataTypeId)
- + string.Join(",", collection.FormatAsDictionary().Select(x => x.Value.Id).ToArray());
-
- //store into cache
- IsolatedCache.InsertCacheItem(key, () => collection,
- //30 mins
- new TimeSpan(0, 0, 30),
- //sliding is true
- true);
-
- return collection;
+ var key = GetPrefixedCacheKey(datetypeId);
+ return RuntimeCache.GetCacheItem(key, () =>
+ {
+ var dtos = Database.Fetch("WHERE datatypeNodeId = @Id", new { Id = datetypeId });
+ var list = dtos.Select(x => new Tuple(new PreValue(x.Id, x.Value, x.SortOrder), x.Alias, x.SortOrder)).ToList();
+ var collection = PreValueConverter.ConvertToPreValuesCollection(list);
+ return collection;
+ }, TimeSpan.FromMinutes(20), isSliding: true);
}
private string EnsureUniqueNodeName(string nodeName, int id = 0)
{
-
+
var sql = new Sql();
sql.Select("*")
@@ -575,7 +549,7 @@ AND umbracoNode.id <> @id",
}
//NOTE: We used to check that the Alias was unique for the given DataTypeNodeId prevalues list, BUT
- // in reality there is no need to check the uniqueness of this alias because the only way that this code executes is
+ // in reality there is no need to check the uniqueness of this alias because the only way that this code executes is
// based on an IDictionary dictionary being passed to this repository and a dictionary
// must have unique aliases by definition, so there is no need for this additional check
@@ -595,10 +569,10 @@ AND umbracoNode.id <> @id",
{
throw new InvalidOperationException("Cannot update a pre value for a data type that has no identity");
}
-
+
//NOTE: We used to check that the Alias was unique for the given DataTypeNodeId prevalues list, BUT
// this causes issues when sorting the pre-values (http://issues.umbraco.org/issue/U4-5670) but in reality
- // there is no need to check the uniqueness of this alias because the only way that this code executes is
+ // there is no need to check the uniqueness of this alias because the only way that this code executes is
// based on an IDictionary dictionary being passed to this repository and a dictionary
// must have unique aliases by definition, so there is no need for this additional check
@@ -613,7 +587,7 @@ AND umbracoNode.id <> @id",
Database.Update(dto);
}
-
+
}
internal static class PreValueConverter
diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs
index 61d83645b3..f118be3b76 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentTypeRepository.cs
@@ -8,6 +8,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
public interface IContentTypeRepository : IContentTypeCompositionRepository
{
+ ///
+ /// Given the path of a content item, this will return true if the content item exists underneath a list view content item
+ ///
+ ///
+ ///
+ bool HasContainerInPath(string contentPath);
+
///
/// Gets all entities of the specified query
///
diff --git a/src/Umbraco.Core/Persistence/RepositoryFactory.cs b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
index 8ba5e5727f..afb93f620f 100644
--- a/src/Umbraco.Core/Persistence/RepositoryFactory.cs
+++ b/src/Umbraco.Core/Persistence/RepositoryFactory.cs
@@ -49,7 +49,12 @@ namespace Umbraco.Core.Persistence
_cacheHelper.IsolatedRuntimeCache.CacheFactory = type =>
{
var cache = origFactory(type);
- return new DeepCloneRuntimeCacheProvider(cache);
+
+ //if the result is already a DeepCloneRuntimeCacheProvider then return it, otherwise
+ //wrap the result with a DeepCloneRuntimeCacheProvider
+ return cache is DeepCloneRuntimeCacheProvider
+ ? cache
+ : new DeepCloneRuntimeCacheProvider(cache);
};
}
diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs
index 28bb58fb5a..c2dfd687dd 100644
--- a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs
+++ b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs
@@ -5,6 +5,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence;
+using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -74,5 +75,20 @@ namespace Umbraco.Core.Services
{
return Enumerable.Empty();
}
+
+ ///
+ /// Given the path of a content item, this will return true if the content item exists underneath a list view content item
+ ///
+ ///
+ ///
+ public bool HasContainerInPath(string contentPath)
+ {
+ using (var uow = UowProvider.GetUnitOfWork())
+ {
+ // can use same repo for both content and media
+ var repository = RepositoryFactory.CreateContentTypeRepository(uow);
+ return repository.HasContainerInPath(contentPath);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/IContentTypeService.cs b/src/Umbraco.Core/Services/IContentTypeService.cs
index 2dcdf01291..46ee8520c6 100644
--- a/src/Umbraco.Core/Services/IContentTypeService.cs
+++ b/src/Umbraco.Core/Services/IContentTypeService.cs
@@ -11,6 +11,13 @@ namespace Umbraco.Core.Services
///
public interface IContentTypeService : IService
{
+ ///
+ /// Given the path of a content item, this will return true if the content item exists underneath a list view content item
+ ///
+ ///
+ ///
+ bool HasContainerInPath(string contentPath);
+
int CountContentTypes();
int CountMediaTypes();
diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs
index 4f1569ac7b..fc65c51e22 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs
@@ -46,23 +46,6 @@ namespace Umbraco.Tests.Persistence.Repositories
return new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of(), SqlSyntax, Constants.ObjectTypes.DataTypeContainerGuid);
}
- [TestCase("UmbracoPreVal87-21,3,48", 3, true)]
- [TestCase("UmbracoPreVal87-21,33,48", 3, false)]
- [TestCase("UmbracoPreVal87-21,33,48", 33, true)]
- [TestCase("UmbracoPreVal87-21,3,48", 33, false)]
- [TestCase("UmbracoPreVal87-21,3,48", 21, true)]
- [TestCase("UmbracoPreVal87-21,3,48", 48, true)]
- [TestCase("UmbracoPreVal87-22,33,48", 2, false)]
- [TestCase("UmbracoPreVal87-22,33,48", 22, true)]
- [TestCase("UmbracoPreVal87-22,33,44", 4, false)]
- [TestCase("UmbracoPreVal87-22,33,44", 44, true)]
- [TestCase("UmbracoPreVal87-22,333,44", 33, false)]
- [TestCase("UmbracoPreVal87-22,333,44", 333, true)]
- public void Pre_Value_Cache_Key_Tests(string cacheKey, int preValueId, bool outcome)
- {
- Assert.AreEqual(outcome, Regex.IsMatch(cacheKey, DataTypeDefinitionRepository.GetCacheKeyRegex(preValueId)));
- }
-
[Test]
public void Can_Move()
{
@@ -537,7 +520,7 @@ namespace Umbraco.Tests.Persistence.Repositories
}
var cached = cache.IsolatedRuntimeCache.GetCache().Result
- .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
+ .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + "_" + dtd.Id);
Assert.IsNotNull(cached);
Assert.AreEqual(1, cached.Count());
@@ -581,7 +564,7 @@ namespace Umbraco.Tests.Persistence.Repositories
}
var cached = cache.IsolatedRuntimeCache.GetCache().Result
- .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
+ .GetCacheItemsByKeySearch(CacheKeys.DataTypePreValuesCacheKey + "_" + dtd.Id);
Assert.IsNotNull(cached);
Assert.AreEqual(1, cached.Count());
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
index 34f5ecd282..2b7a6f7043 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml
@@ -993,7 +993,7 @@ To manage your website, simply open the Umbraco back office and start adding con
Dictionary item saved
Publishing failed because the parent page isn't published
Content published
- and visible at the website
+ and visible on the website
Content saved
Remember to publish to make changes visible
Sent For Approval
diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
index 7139d0e398..ce9618f679 100644
--- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
+++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml
@@ -982,7 +982,7 @@ To manage your website, simply open the Umbraco back office and start adding con
Dictionary item saved
Publishing failed because the parent page isn't published
Content published
- and visible at the website
+ and visible on the website
Content saved
Remember to publish to make changes visible
Sent For Approval
diff --git a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs
index fe629a6ccf..a5cc8d3806 100644
--- a/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs
+++ b/src/Umbraco.Web/Cache/DataTypeCacheRefresher.cs
@@ -103,13 +103,13 @@ namespace Umbraco.Web.Cache
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.IdToKeyCacheKey);
ApplicationContext.Current.ApplicationCache.RuntimeCache.ClearCacheByKeySearch(CacheKeys.KeyToIdCacheKey);
+ var dataTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache();
payloads.ForEach(payload =>
{
//clears the prevalue cache
- var dataTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache();
if (dataTypeCache)
- dataTypeCache.Result.ClearCacheByKeySearch(string.Format("{0}{1}", CacheKeys.DataTypePreValuesCacheKey, payload.Id));
-
+ dataTypeCache.Result.ClearCacheByKeySearch(string.Format("{0}_{1}", CacheKeys.DataTypePreValuesCacheKey, payload.Id));
+
PublishedContentType.ClearDataType(payload.Id);
});
diff --git a/src/Umbraco.Web/HealthCheck/Checks/Security/ClickJackingCheck.cs b/src/Umbraco.Web/HealthCheck/Checks/Security/ClickJackingCheck.cs
index bdfd504d73..54f72dc88a 100644
--- a/src/Umbraco.Web/HealthCheck/Checks/Security/ClickJackingCheck.cs
+++ b/src/Umbraco.Web/HealthCheck/Checks/Security/ClickJackingCheck.cs
@@ -64,7 +64,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
var url = HealthCheckContext.HttpContext.Request.Url;
// Access the site home page and check for the click-jack protection header or meta tag
- var useSsl = GlobalSettings.UseSSL || HealthCheckContext.HttpContext.Request.ServerVariables["SERVER_PORT"] == "443";
+ var serverVariables = HealthCheckContext.HttpContext.Request.ServerVariables;
+ var useSsl = GlobalSettings.UseSSL || serverVariables["SERVER_PORT"] == "443";
var address = string.Format("http{0}://{1}:{2}", useSsl ? "s" : "", url.Host.ToLower(), url.Port);
var request = WebRequest.Create(address);
request.Method = "GET";
diff --git a/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs b/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs
index cf279bf3f8..2ca63662d8 100644
--- a/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs
+++ b/src/Umbraco.Web/HealthCheck/Checks/Security/ExcessiveHeadersCheck.cs
@@ -49,7 +49,8 @@ namespace Umbraco.Web.HealthCheck.Checks.Security
var url = HealthCheckContext.HttpContext.Request.Url;
// Access the site home page and check for the headers
- var useSsl = GlobalSettings.UseSSL || HealthCheckContext.HttpContext.Request.ServerVariables["SERVER_PORT"] == "443";
+ var serverVariables = HealthCheckContext.HttpContext.Request.ServerVariables;
+ var useSsl = GlobalSettings.UseSSL || serverVariables["SERVER_PORT"] == "443";
var address = string.Format("http{0}://{1}:{2}", useSsl ? "s" : "", url.Host.ToLower(), url.Port);
var request = WebRequest.Create(address);
request.Method = "HEAD";
diff --git a/src/Umbraco.Web/HealthCheck/HealthCheckController.cs b/src/Umbraco.Web/HealthCheck/HealthCheckController.cs
index 919df88962..14bfaaea9f 100644
--- a/src/Umbraco.Web/HealthCheck/HealthCheckController.cs
+++ b/src/Umbraco.Web/HealthCheck/HealthCheckController.cs
@@ -48,12 +48,22 @@ namespace Umbraco.Web.HealthCheck
return healthCheckGroups;
}
+ [HttpGet]
public object GetStatus(Guid id)
{
var check = _healthCheckResolver.HealthChecks.FirstOrDefault(x => x.Id == id);
if (check == null) throw new InvalidOperationException("No health check found with ID " + id);
- return check.GetStatus();
+ try
+ {
+ //Core.Logging.LogHelper.Debug("Running health check: " + check.Name);
+ return check.GetStatus();
+ }
+ catch (Exception e)
+ {
+ Core.Logging.LogHelper.Error("Exception in health check: " + check.Name, e);
+ throw;
+ }
}
[HttpPost]
diff --git a/src/Umbraco.Web/HealthCheck/HealthCheckResolver.cs b/src/Umbraco.Web/HealthCheck/HealthCheckResolver.cs
index dfe5b792a5..7ae302fa49 100644
--- a/src/Umbraco.Web/HealthCheck/HealthCheckResolver.cs
+++ b/src/Umbraco.Web/HealthCheck/HealthCheckResolver.cs
@@ -19,7 +19,7 @@ namespace Umbraco.Web.HealthCheck
///
internal class HealthCheckResolver : LazyManyObjectsResolverBase, IHealthCheckResolver
{
- public HealthCheckResolver(ILogger logger, Func> lazyTypeList)
+ public HealthCheckResolver(ILogger logger, Func> lazyTypeList)
: base(new HealthCheckServiceProvider(), logger, lazyTypeList, ObjectLifetimeScope.HttpRequest)
{
}
@@ -51,7 +51,7 @@ namespace Umbraco.Web.HealthCheck
new HealthCheckContext(new HttpContextWrapper(HttpContext.Current), UmbracoContext.Current)
});
}
-
+
//use normal ctor
return Activator.CreateInstance(serviceType);
}
diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs
index 6f23ecee0f..37b002d297 100644
--- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs
@@ -37,7 +37,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.IsContainer, expression => expression.MapFrom(content => content.ContentType.IsContainer))
.ForMember(display => display.IsChildOfListView, expression => expression.Ignore())
.ForMember(display => display.Trashed, expression => expression.MapFrom(content => content.Trashed))
- .ForMember(display => display.PublishDate, expression => expression.MapFrom(content => GetPublishedDate(content, applicationContext)))
+ .ForMember(display => display.PublishDate, expression => expression.MapFrom(content => GetPublishedDate(content)))
.ForMember(display => display.TemplateAlias, expression => expression.MapFrom(content => content.Template.Alias))
.ForMember(display => display.HasPublishedVersion, expression => expression.MapFrom(content => content.HasPublishedVersion))
.ForMember(display => display.Urls,
@@ -78,6 +78,12 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.Alias, expression => expression.Ignore());
}
+ private static DateTime? GetPublishedDate(IContent content)
+ {
+ var date = ((Content) content).PublishedDate;
+ return date == default (DateTime) ? (DateTime?) null : date;
+ }
+
///
/// Maps the generic tab with custom properties for content
///
@@ -89,31 +95,9 @@ namespace Umbraco.Web.Models.Mapping
private static void AfterMap(IContent content, ContentItemDisplay display, IDataTypeService dataTypeService,
ILocalizedTextService localizedText, IContentTypeService contentTypeService)
{
- //map the IsChildOfListView (this is actually if it is a descendant of a list view!)
- //TODO: Fix this shorthand .Ancestors() lookup, at least have an overload to use the current
- if (content.HasIdentity)
- {
- var ancesctorListView = content.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer);
- display.IsChildOfListView = ancesctorListView != null;
- }
- else
- {
- //it's new so it doesn't have a path, so we need to look this up by it's parent + ancestors
- var parent = content.Parent();
- if (parent == null)
- {
- display.IsChildOfListView = false;
- }
- else if (parent.ContentType.IsContainer)
- {
- display.IsChildOfListView = true;
- }
- else
- {
- var ancesctorListView = parent.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer);
- display.IsChildOfListView = ancesctorListView != null;
- }
- }
+ // map the IsChildOfListView (this is actually if it is a descendant of a list view!)
+ var parent = content.Parent();
+ display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path));
//map the tree node url
if (HttpContext.Current != null)
@@ -229,26 +213,7 @@ namespace Umbraco.Web.Models.Mapping
}
///
- /// Gets the published date value for the IContent object
- ///
- ///
- ///
- ///
- private static DateTime? GetPublishedDate(IContent content, ApplicationContext applicationContext)
- {
- if (content.Published)
- {
- return content.UpdateDate;
- }
- if (content.HasPublishedVersion)
- {
- var published = applicationContext.Services.ContentService.GetPublishedVersion(content.Id);
- return published.UpdateDate;
- }
- return null;
- }
-
- ///
+ //TODO: This is horribly inneficient
/// Creates the list of action buttons allowed for this user - Publish, Send to publish, save, unpublish returned as the button's 'letter'
///
private class ActionButtonsResolver : ValueResolver>
diff --git a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs
index 453e1567ab..384ef332e2 100644
--- a/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs
+++ b/src/Umbraco.Web/Models/Mapping/MediaModelMapper.cs
@@ -42,7 +42,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.IsContainer, expression => expression.Ignore())
.ForMember(display => display.HasPublishedVersion, expression => expression.Ignore())
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
- .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, applicationContext.ProfilingLogger.Logger));
+ .AfterMap((media, display) => AfterMap(media, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService, applicationContext.Services.ContentTypeService, applicationContext.ProfilingLogger.Logger));
//FROM IMedia TO ContentItemBasic
config.CreateMap>()
@@ -67,34 +67,12 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore());
}
- private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, ILogger logger)
+ private static void AfterMap(IMedia media, MediaItemDisplay display, IDataTypeService dataTypeService, ILocalizedTextService localizedText, IContentTypeService contentTypeService, ILogger logger)
{
// Adapted from ContentModelMapper
//map the IsChildOfListView (this is actually if it is a descendant of a list view!)
- //TODO: Fix this shorthand .Ancestors() lookup, at least have an overload to use the current
- if (media.HasIdentity)
- {
- var ancesctorListView = media.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer);
- display.IsChildOfListView = ancesctorListView != null;
- }
- else
- {
- //it's new so it doesn't have a path, so we need to look this up by it's parent + ancestors
- var parent = media.Parent();
- if (parent == null)
- {
- display.IsChildOfListView = false;
- }
- else if (parent.ContentType.IsContainer)
- {
- display.IsChildOfListView = true;
- }
- else
- {
- var ancesctorListView = parent.Ancestors().FirstOrDefault(x => x.ContentType.IsContainer);
- display.IsChildOfListView = ancesctorListView != null;
- }
- }
+ var parent = media.Parent();
+ display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path));
//map the tree node url
if (HttpContext.Current != null)
diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs
index 3c97551eaf..5befbda7cf 100644
--- a/src/Umbraco.Web/UmbracoHelper.cs
+++ b/src/Umbraco.Web/UmbracoHelper.cs
@@ -1389,10 +1389,15 @@ namespace Umbraco.Web
return test ? new HtmlString(valueIfTrue) : new HtmlString(string.Empty);
}
- #endregion
+ #endregion
#region Prevalues
+ ///
+ /// Gets a specific PreValue by its Id
+ ///
+ /// Id of the PreValue to retrieve the value from
+ /// PreValue as a string
public string GetPreValueAsString(int id)
{
return DataTypeService.GetPreValueAsString(id);
diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs
index c86118b475..bc66e909cf 100644
--- a/src/UmbracoExamine/UmbracoContentIndexer.cs
+++ b/src/UmbracoExamine/UmbracoContentIndexer.cs
@@ -36,6 +36,7 @@ namespace UmbracoExamine
private readonly IUserService _userService;
private readonly IContentTypeService _contentTypeService;
private readonly EntityXmlSerializer _serializer = new EntityXmlSerializer();
+ private const int PageSize = 2;
#region Constructors
@@ -408,8 +409,7 @@ namespace UmbracoExamine
{
if (SupportedTypes.Contains(type) == false)
return;
-
- const int pageSize = 10000;
+
var pageIndex = 0;
DataService.LogService.AddInfoLog(-1, string.Format("PerformIndexAll - Start data queries - {0}", type));
@@ -445,6 +445,7 @@ namespace UmbracoExamine
//sorted by: umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder
var result = _contentService.GetPagedXmlEntries(path, pIndex, pSize, out totalContent).ToArray();
+ var more = result.Length == pSize;
//then like we do in the ContentRepository.BuildXmlCache we need to track what Parents have been processed
// already so that we can then exclude implicitly unpublished content items
@@ -480,7 +481,7 @@ namespace UmbracoExamine
filtered.Add(xml);
}
- return new Tuple(totalContent, filtered.ToArray());
+ return Tuple.Create(filtered.ToArray(), more);
},
i => _contentService.GetById(i));
}
@@ -498,13 +499,13 @@ namespace UmbracoExamine
IContent[] descendants;
if (SupportUnpublishedContent)
{
- descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total, "umbracoNode.id").ToArray();
+ descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, PageSize, out total, "umbracoNode.id").ToArray();
}
else
{
//get all paged records but order by level ascending, we need to do this because we need to track which nodes are not published so that we can determine
// which descendent nodes are implicitly not published
- descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total, "level", Direction.Ascending, true, (string)null).ToArray();
+ descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, PageSize, out total, "level", Direction.Ascending, true, (string)null).ToArray();
}
// need to store decendants count before filtering, in order for loop to work correctly
@@ -528,7 +529,7 @@ namespace UmbracoExamine
content, notPublished).WhereNotNull(), type);
pageIndex++;
- } while (currentPageSize == pageSize);
+ } while (currentPageSize == PageSize);
}
break;
@@ -546,7 +547,8 @@ namespace UmbracoExamine
{
long totalMedia;
var result = _mediaService.GetPagedXmlEntries(path, pIndex, pSize, out totalMedia).ToArray();
- return new Tuple(totalMedia, result);
+ var more = result.Length == pSize;
+ return Tuple.Create(result, more);
},
i => _mediaService.GetById(i));
@@ -574,39 +576,37 @@ namespace UmbracoExamine
string type,
int parentId,
Func getContentTypes,
- Func> getPagedXmlEntries,
+ Func> getPagedXmlEntries,
Func getContent)
where TContentType: IContentTypeComposition
{
- const int pageSize = 10000;
- var pageIndex = 0;
-
- XElement[] xElements;
+ var pageIndex = 0;
var contentTypes = getContentTypes();
var icons = contentTypes.ToDictionary(x => x.Id, y => y.Icon);
+ var parent = parentId == -1 ? null : getContent(parentId);
+ bool more;
do
{
- long total;
+ XElement[] xElements;
+
if (parentId == -1)
{
- var pagedElements = getPagedXmlEntries("-1", pageIndex, pageSize);
- total = pagedElements.Item1;
- xElements = pagedElements.Item2;
+ var pagedElements = getPagedXmlEntries("-1", pageIndex, PageSize);
+ xElements = pagedElements.Item1;
+ more = pagedElements.Item2;
+ }
+ else if (parent == null)
+ {
+ xElements = new XElement[0];
+ more = false;
}
else
{
- //Get the parent
- var parent = getContent(parentId);
- if (parent == null)
- xElements = new XElement[0];
- else
- {
- var pagedElements = getPagedXmlEntries(parent.Path, pageIndex, pageSize);
- total = pagedElements.Item1;
- xElements = pagedElements.Item2;
- }
+ var pagedElements = getPagedXmlEntries(parent.Path, pageIndex, PageSize);
+ xElements = pagedElements.Item1;
+ more = pagedElements.Item2;
}
//if specific types are declared we need to post filter them
@@ -627,7 +627,7 @@ namespace UmbracoExamine
AddNodesToIndex(xElements, type);
pageIndex++;
- } while (xElements.Length == pageSize);
+ } while (more);
}
internal static IEnumerable GetSerializedContent(
diff --git a/src/UmbracoExamine/UmbracoMemberIndexer.cs b/src/UmbracoExamine/UmbracoMemberIndexer.cs
index 9ca61164eb..1a3c9befd2 100644
--- a/src/UmbracoExamine/UmbracoMemberIndexer.cs
+++ b/src/UmbracoExamine/UmbracoMemberIndexer.cs
@@ -117,7 +117,7 @@ namespace UmbracoExamine
if (indexerData.UserFields.Any(x => x.Name == "_searchEmail") == false)
{
var field = new IndexField { Name = "_searchEmail" };
-
+
StaticField policy;
if (IndexFieldPolicies.TryGetValue("_searchEmail", out policy))
{
@@ -173,7 +173,8 @@ namespace UmbracoExamine
{
long totalContent;
var result = _memberService.GetPagedXmlEntries(pIndex, pSize, out totalContent).ToArray();
- return new Tuple(totalContent, result);
+ var more = result.Length == pSize;
+ return Tuple.Create(result, more);
},
i => _memberService.GetById(i));
}
@@ -219,7 +220,7 @@ namespace UmbracoExamine
{
stopwatch.Stop();
}
-
+
DataService.LogService.AddInfoLog(-1, string.Format("PerformIndexAll - End data queries - {0}, took {1}ms", type, stopwatch.ElapsedMilliseconds));
}
diff --git a/src/umbraco.cms/businesslogic/Packager/PackageActions/addDashboardSection.cs b/src/umbraco.cms/businesslogic/Packager/PackageActions/addDashboardSection.cs
index 6025123bc4..ceca7c21ff 100644
--- a/src/umbraco.cms/businesslogic/Packager/PackageActions/addDashboardSection.cs
+++ b/src/umbraco.cms/businesslogic/Packager/PackageActions/addDashboardSection.cs
@@ -43,23 +43,28 @@ namespace umbraco.cms.businesslogic.packager.standardPackageActions
if (xmlData.HasChildNodes)
{
- string sectionAlias = xmlData.Attributes["dashboardAlias"].Value;
- string dbConfig = SystemFiles.DashboardConfig;
+ string sectionAlias = xmlData.Attributes["dashboardAlias"].Value;
+ string dbConfig = SystemFiles.DashboardConfig;
- XmlNode section = xmlData.SelectSingleNode("./section");
- XmlDocument dashboardFile = XmlHelper.OpenAsXmlDocument(dbConfig);
+ XmlNode section = xmlData.SelectSingleNode("./section");
+ XmlDocument dashboardFile = XmlHelper.OpenAsXmlDocument(dbConfig);
- XmlNode importedSection = dashboardFile.ImportNode(section, true);
+ //don't continue if it already exists
+ var found = dashboardFile.SelectNodes("//section[@alias='" + sectionAlias + "']");
+ if (found == null || found.Count <= 0)
+ {
+ XmlNode importedSection = dashboardFile.ImportNode(section, true);
- XmlAttribute alias = XmlHelper.AddAttribute(dashboardFile, "alias", sectionAlias);
- importedSection.Attributes.Append(alias);
+ XmlAttribute alias = XmlHelper.AddAttribute(dashboardFile, "alias", sectionAlias);
+ importedSection.Attributes.Append(alias);
- dashboardFile.DocumentElement.AppendChild(importedSection);
+ dashboardFile.DocumentElement.AppendChild(importedSection);
- dashboardFile.Save(IOHelper.MapPath(dbConfig));
+ dashboardFile.Save(IOHelper.MapPath(dbConfig));
+ }
- return true;
- }
+ return true;
+ }
return false;
}