Compare commits

...

45 Commits

Author SHA1 Message Date
Shannon Deminick 218f523022 Merge pull request #1843 from umbraco/temp-U4-9691
Fixes the Examine mgmt dashboard to look better and to detect if an i…
2017-04-03 16:28:36 +10:00
Shannon Deminick 50c6fb036a Merge pull request #1839 from umbraco/temp-uaasscrum-827
uaasscrum-827 - more robust umbraco.config
2017-04-03 16:19:27 +10:00
Shannon Deminick bc2115ff0a Merge pull request #1847 from umbraco/temp-u4-9683
Upgrade to ModelsBuilder 3.0.6
2017-04-03 16:03:13 +10:00
Shannon Deminick 9eee5c2bc0 Merge pull request #1840 from umbraco/temp-U4-9689
U4-9689 Content type description isn't always saved the same way
2017-04-03 15:53:30 +10:00
Mads Rasmussen ed3096642d Merge pull request #1844 from ryanology/temp-U4-9697
U4-9697 - Listview create new node ordering
2017-03-30 10:31:51 +02:00
Stephan 95508c4fb7 Upgrade nuspec accordingly 2017-03-30 09:32:22 +02:00
Stephan 4677faff38 Upgrade to ModelsBuilder 3.0.6 2017-03-30 08:54:01 +02:00
Shannon 725b3c5eca Merge branch 'dev-v7' into temp-U4-9691 2017-03-30 16:37:24 +11:00
Shannon 25f5179b29 updates nuspec 2017-03-30 16:36:54 +11:00
Shannon bf6d084f82 Merge branch 'dev-v7' into temp-U4-9691 2017-03-30 15:50:16 +11:00
Shannon 1a03bd9624 Logs an error if the index is rebuilding due to being corrupt 2017-03-30 15:49:45 +11:00
Shannon 6a1d60c5a7 U4-9692 Update to Examine 0.1.82 2017-03-30 15:43:06 +11:00
Shannon 4fef17190f adds notes 2017-03-30 11:03:07 +11:00
rrueckl 08ca75bb35 U4-9697 - Listview create new node ordering 2017-03-29 13:59:23 -04:00
Shannon 0512eaa7fd Fixes the Examine mgmt dashboard to look better and to detect if an index is unreadable in which case it allows you to rebuild it. 2017-03-29 21:43:00 +11:00
Claus e8df5f9eb4 U4-9689 Content type description isn't always saved the same way
also fixed for member types (and added test for media types also using the ContentTypeService)
2017-03-29 11:08:57 +02:00
Stephan c46678c766 uaasscrum-827 - more robust umbraco.config 2017-03-29 10:03:02 +02:00
Shannon 7cdb48b6c9 bumps version 2017-03-29 16:35:37 +11:00
Shannon Deminick 4ffa6bb41b Merge pull request #1824 from umbraco/temp-u4-9617
U4-9617 - perf for published date
2017-03-29 16:29:31 +11:00
Shannon 77af16db55 Merge branch 'dev-v7' into temp-u4-9617
# Conflicts:
#	src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs
2017-03-29 16:29:18 +11:00
Stephan 85d85fa587 Merge pull request #1819 from umbraco/temp-u4-9623
U4-9323 - fix DataTypeDefinitionRepository prevalues cache
2017-03-28 17:37:04 +02:00
Claus 7ade64f855 Merge pull request #1802 from umbraco/temp-U4-9637
U4-9637 addDashboardSection package action shouldn't add the dashboar…
2017-03-28 13:12:26 +02:00
Shannon Deminick 346e8dcaf0 Merge pull request #1820 from umbraco/temp-u4-9615
U4-9615 - implement way to find listviews in path fast
2017-03-28 16:05:25 +11:00
Shannon ddfd07bf4a Fixes count query 2017-03-28 16:04:06 +11:00
Shannon a9fe46da0c makes HasContainerInPath public 2017-03-28 15:55:45 +11:00
Shannon aca1f0d186 Adds comments 2017-03-28 15:46:33 +11:00
Shannon 9eb415d398 U4-9682 Repository's have a double nested DeepCloneRuntimeCacheProvider set which means all entities are double deep cloned in and out of the cache and ensures that PreValueCollections are not also manually deep cloned. 2017-03-28 15:41:55 +11:00
Shannon 8f6b728534 Moves paging value to a constant 2017-03-28 13:37:10 +11:00
Shannon Deminick 2e0c09ab39 Merge pull request #1827 from umbraco/temp-u4-9598
U4-9598 - fix paging in UmbracoContentIndexer
2017-03-28 13:31:37 +11:00
Shannon Deminick f211344786 Merge pull request #1825 from umbraco/temp-u4-9604
U4-9604 - fix current HttpContext in ManyObjectsResolverBase
2017-03-28 13:11:09 +11:00
Stephan 68702b98f5 U4-9604 - add nullcheck 2017-03-27 08:52:10 +02:00
Stephan f93caf277b Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into temp-u4-9604 2017-03-27 08:47:40 +02:00
Shannon Deminick e0a7698780 Merge pull request #1821 from andyneil/dev-v7-lang-fixes
Dev v7 lang fixes
2017-03-27 14:20:41 +11:00
Shannon Deminick 783c74d3ba Merge pull request #1829 from abryukhov/patch-6
Adding missing keys before v7.6
2017-03-27 14:12:08 +11:00
Alexander Bryukhov 21963c03a2 Adding missing keys before v7.6 2017-03-24 21:59:02 +07:00
Stephan 879a132077 U4-9598 - fix paging in UmbracoContentIndexer 2017-03-24 13:05:06 +01:00
Stephan 606ebcae92 U4-9604 - fix current HttpContext in ManyObjectsResolverBase 2017-03-24 11:07:15 +01:00
Stephan af10ae9e34 U4-9617 - fix 2017-03-23 18:00:58 +01:00
Stephan a23c150738 U4-9617 - fix 2017-03-23 17:51:30 +01:00
Stephan 085a678266 U4-9617 - perf for published date 2017-03-23 17:44:07 +01:00
andyneil cf7cafeb4c Update wording to be more grammatically correct 2017-03-23 13:41:48 +00:00
andyneil 870657affa Update wording to be more grammatically correct 2017-03-23 13:41:23 +00:00
Stephan fe11d4770d U4-9615 - implement way to find listviews in path fast 2017-03-23 14:07:45 +01:00
Stephan c8fe9030c7 U4-9323 - fix DataTypeDefinitionRepository prevalues cache 2017-03-23 10:39:28 +01:00
Shannon 4093fd9b79 U4-9637 addDashboardSection package action shouldn't add the dashboard if it already exists 2017-03-18 16:52:30 +11:00
56 changed files with 719 additions and 538 deletions
+1 -1
View File
@@ -32,7 +32,7 @@
<!-- 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.81, 1.0.0)" />
<dependency id="Examine" version="[0.1.82, 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="semver" version="[1.1.2, 2.0.0)" />
+2 -2
View File
@@ -17,8 +17,8 @@
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="Newtonsoft.Json" version="[6.0.8, 10.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[3.0.5, 4.0.0)" />
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[3.0.6, 4.0.0)" />
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
</dependencies>
</metadata>
<files>
+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.11
7.5.12
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.5.11")]
[assembly: AssemblyInformationalVersion("7.5.11")]
[assembly: AssemblyFileVersion("7.5.12")]
[assembly: AssemblyInformationalVersion("7.5.12")]
@@ -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);
}
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.5.11");
private static readonly Version Version = new Version("7.5.12");
/// <summary>
/// Gets the current version of Umbraco.
+3
View File
@@ -274,6 +274,9 @@ namespace Umbraco.Core.Models
/// </summary>
public bool HasPublishedVersion { get { return PublishedVersionGuid != default(Guid); } }
[IgnoreDataMember]
internal DateTime PublishedDate { get; set; }
/// <summary>
/// Changes the Trashed state of the content object
/// </summary>
@@ -19,5 +19,8 @@ namespace Umbraco.Core.Models.Rdbms
[Column("newest")]
public bool Newest { get; set; }
[Column("updateDate")]
public DateTime VersionDate { get; set; }
}
}
@@ -22,6 +22,7 @@ namespace Umbraco.Core.ObjectResolution
private readonly string _httpContextKey;
private readonly List<Type> _instanceTypes = new List<Type>();
private IEnumerable<TResolved> _sortedValues;
private readonly Func<HttpContextBase> _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<Type>();
InitializeAppInstances();
@@ -160,7 +156,16 @@ namespace Umbraco.Core.ObjectResolution
/// Gets or sets the <see cref="HttpContextBase"/> used to initialize this object, if any.
/// </summary>
/// <remarks>If not null, then <c>LifetimeScope</c> will be <c>ObjectLifetimeScope.HttpRequest</c>.</remarks>
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;
}
}
/// <summary>
/// Returns the service provider used to instantiate objects
@@ -196,7 +201,7 @@ namespace Umbraco.Core.ObjectResolution
/// <summary>
/// Gets or sets the default type weight.
/// </summary>
/// <remarks>Determines the weight of types that do not have a <c>WeightAttribute</c> set on
/// <remarks>Determines the weight of types that do not have a <c>WeightAttribute</c> set on
/// them, when calling <c>GetSortedValues</c>.</remarks>
protected virtual int DefaultPluginWeight
{
@@ -276,7 +281,7 @@ namespace Umbraco.Core.ObjectResolution
/// Removes a type.
/// </summary>
/// <param name="value">The type to remove.</param>
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
/// the type is not a valid type for the resolver.</exception>
public virtual void RemoveType(Type value)
{
@@ -296,7 +301,7 @@ namespace Umbraco.Core.ObjectResolution
/// Removes a type.
/// </summary>
/// <typeparam name="T">The type to remove.</typeparam>
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
/// <exception cref="InvalidOperationException">the resolver does not support removing types, or
/// the type is not a valid type for the resolver.</exception>
public void RemoveType<T>()
where T : TResolved
@@ -309,7 +314,7 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <param name="types">The types to add.</param>
/// <remarks>The types are appended at the end of the list.</remarks>
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
/// <exception cref="InvalidOperationException">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.</exception>
protected void AddTypes(IEnumerable<Type> types)
{
@@ -336,7 +341,7 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <param name="value">The type to add.</param>
/// <remarks>The type is appended at the end of the list.</remarks>
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
/// <exception cref="InvalidOperationException">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.</exception>
public virtual void AddType(Type value)
{
@@ -362,7 +367,7 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <typeparam name="T">The type to add.</typeparam>
/// <remarks>The type is appended at the end of the list.</remarks>
/// <exception cref="InvalidOperationException">the resolver does not support adding types, or
/// <exception cref="InvalidOperationException">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.</exception>
public void AddType<T>()
where T : TResolved
@@ -404,7 +409,7 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <param name="index">The zero-based index at which the type should be inserted.</param>
/// <param name="value">The type to insert.</param>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// <exception cref="InvalidOperationException">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.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="index"/> is out of range.</exception>
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.
/// </summary>
/// <param name="value">The type to insert.</param>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// <exception cref="InvalidOperationException">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.</exception>
public virtual void InsertType(Type value)
{
@@ -464,7 +469,7 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <param name="existingType">The existing type before which to insert.</param>
/// <param name="value">The type to insert.</param>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// <exception cref="InvalidOperationException">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.</exception>
public virtual void InsertTypeBefore(Type existingType, Type value)
@@ -498,7 +503,7 @@ namespace Umbraco.Core.ObjectResolution
/// </summary>
/// <typeparam name="TExisting">The existing type before which to insert.</typeparam>
/// <typeparam name="T">The type to insert.</typeparam>
/// <exception cref="InvalidOperationException">the resolver does not support inserting types, or
/// <exception cref="InvalidOperationException">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.</exception>
public void InsertTypeBefore<TExisting, T>()
@@ -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
@@ -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();
@@ -687,22 +689,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();
@@ -974,7 +980,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 + @")
@@ -1250,5 +1250,19 @@ WHERE cmsContentType." + aliasColumn + @" LIKE @pattern",
while (aliases.Contains(test = alias + i)) i++;
return test;
}
/// <summary>
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
/// </summary>
/// <param name="contentPath"></param>
/// <returns></returns>
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<int>(sql) > 0;
}
}
}
@@ -34,7 +34,7 @@ namespace Umbraco.Core.Persistence.Repositories
: base(work, cache, logger, sqlSyntax)
{
_contentTypeRepository = contentTypeRepository;
_preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax);
_preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, sqlSyntax);
}
#region Overrides of RepositoryBase<int,DataTypeDefinition>
@@ -276,47 +276,33 @@ AND umbracoNode.id <> @id",
public PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId)
{
var cached = RuntimeCache.GetCacheItemsByKeySearch<PreValueCollection>(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;
}
/// <summary>
/// Gets a specific PreValue by its Id
/// </summary>
/// <param name="preValueId">Id of the PreValue to retrieve the value from</param>
/// <returns>PreValue as a string</returns>
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<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + "_");
var cached = RuntimeCache.GetCacheItemsByKeyExpression<PreValueCollection>(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<DataTypePreValueDto>("WHERE id = @preValueId", new { preValueId = preValueId });
var dto = Database.FirstOrDefault<DataTypePreValueDto>("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<string, PreValue> 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<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { Id = dataTypeId });
var list = dtos.Select(x => new Tuple<PreValue, string, int>(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
RuntimeCache.InsertCacheItem(key, () => collection,
//30 mins
new TimeSpan(0, 0, 30),
//sliding is true
true);
return collection;
var key = GetPrefixedCacheKey(datetypeId);
return RuntimeCache.GetCacheItem<PreValueCollection>(key, () =>
{
var dtos = Database.Fetch<DataTypePreValueDto>("WHERE datatypeNodeId = @Id", new { Id = datetypeId });
var list = dtos.Select(x => new Tuple<PreValue, string, int>(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("*")
@@ -576,7 +550,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<string, PreValue> dictionary being passed to this repository and a dictionary
// must have unique aliases by definition, so there is no need for this additional check
@@ -596,10 +570,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<string, PreValue> dictionary being passed to this repository and a dictionary
// must have unique aliases by definition, so there is no need for this additional check
@@ -614,7 +588,7 @@ AND umbracoNode.id <> @id",
Database.Update(dto);
}
}
internal static class PreValueConverter
@@ -8,6 +8,13 @@ namespace Umbraco.Core.Persistence.Repositories
{
public interface IContentTypeRepository : IContentTypeCompositionRepository<IContentType>
{
/// <summary>
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
/// </summary>
/// <param name="contentPath"></param>
/// <returns></returns>
bool HasContainerInPath(string contentPath);
/// <summary>
/// Gets all entities of the specified <see cref="PropertyType"/> query
/// </summary>
@@ -48,7 +48,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);
};
}
+60 -58
View File
@@ -1,22 +1,15 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Threading;
using AutoMapper;
using Umbraco.Core.Auditing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -26,14 +19,15 @@ namespace Umbraco.Core.Services
/// </summary>
public class ContentTypeService : ContentTypeServiceBase, IContentTypeService
{
private readonly IContentService _contentService;
private readonly IContentService _contentService;
private readonly IMediaService _mediaService;
//Support recursive locks because some of the methods that require locking call other methods that require locking.
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
public ContentTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IContentService contentService, IMediaService mediaService)
public ContentTypeService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory, IContentService contentService,
IMediaService mediaService)
: base(provider, repositoryFactory, logger, eventMessagesFactory)
{
if (contentService == null) throw new ArgumentNullException("contentService");
@@ -154,8 +148,8 @@ namespace Umbraco.Core.Services
}
if (savingEvent.IsRaisedEventCancelled(
new SaveEventArgs<EntityContainer>(container, evtMsgs),
this))
new SaveEventArgs<EntityContainer>(container, evtMsgs),
this))
{
return OperationStatus.Cancelled(evtMsgs);
}
@@ -214,7 +208,7 @@ namespace Umbraco.Core.Services
public IEnumerable<EntityContainer> GetMediaTypeContainers(IMediaType mediaType)
{
var ancestorIds = mediaType.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
var ancestorIds = mediaType.Path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
.Select(x =>
{
var asInt = x.TryConvertTo<int>();
@@ -290,8 +284,8 @@ namespace Umbraco.Core.Services
if (container == null) return OperationStatus.NoOperation(evtMsgs);
if (DeletingContentTypeContainer.IsRaisedEventCancelled(
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
this))
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
this))
{
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
}
@@ -316,8 +310,8 @@ namespace Umbraco.Core.Services
if (container == null) return OperationStatus.NoOperation(evtMsgs);
if (DeletingMediaTypeContainer.IsRaisedEventCancelled(
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
this))
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
this))
{
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
}
@@ -421,7 +415,7 @@ namespace Umbraco.Core.Services
clone.Name = name;
var compositionAliases = clone.CompositionAliases().Except(new[] { alias }).ToList();
var compositionAliases = clone.CompositionAliases().Except(new[] {alias}).ToList();
//remove all composition that is not it's current alias
foreach (var a in compositionAliases)
{
@@ -680,7 +674,7 @@ namespace Umbraco.Core.Services
var comparer = new DelegateEqualityComparer<IContentTypeComposition>((x, y) => x.Id == y.Id, x => x.Id);
var dependencies = new HashSet<IContentTypeComposition>(compositions, comparer);
var stack = new Stack<IContentTypeComposition>();
indirectReferences.ForEach(stack.Push);//Push indirect references to a stack, so we can add recursively
indirectReferences.ForEach(stack.Push); //Push indirect references to a stack, so we can add recursively
while (stack.Count > 0)
{
var indirectReference = stack.Pop();
@@ -734,6 +728,8 @@ namespace Umbraco.Core.Services
{
ValidateLocked(contentType); // throws if invalid
contentType.CreatorId = userId;
if (contentType.Description == string.Empty)
contentType.Description = null;
repository.AddOrUpdate(contentType);
uow.Commit();
@@ -742,7 +738,7 @@ namespace Umbraco.Core.Services
UpdateContentXmlStructure(contentType);
}
SavedContentType.RaiseEvent(new SaveEventArgs<IContentType>(contentType, false), this);
Audit(AuditType.Save, string.Format("Save ContentType performed by user"), userId, contentType.Id);
Audit(AuditType.Save, string.Format("Save ContentType performed by user"), userId, contentType.Id);
}
/// <summary>
@@ -755,7 +751,7 @@ namespace Umbraco.Core.Services
var asArray = contentTypes.ToArray();
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(asArray), this))
return;
return;
using (new WriteLock(Locker))
{
@@ -770,6 +766,8 @@ namespace Umbraco.Core.Services
foreach (var contentType in asArray)
{
contentType.CreatorId = userId;
if (contentType.Description == string.Empty)
contentType.Description = null;
repository.AddOrUpdate(contentType);
}
@@ -780,7 +778,7 @@ namespace Umbraco.Core.Services
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
}
SavedContentType.RaiseEvent(new SaveEventArgs<IContentType>(asArray, false), this);
Audit(AuditType.Save, string.Format("Save ContentTypes performed by user"), userId, -1);
Audit(AuditType.Save, string.Format("Save ContentTypes performed by user"), userId, -1);
}
/// <summary>
@@ -791,8 +789,8 @@ namespace Umbraco.Core.Services
/// <remarks>Deleting a <see cref="IContentType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IContentType"/></remarks>
public void Delete(IContentType contentType, int userId = 0)
{
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
return;
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
return;
using (new WriteLock(Locker))
{
@@ -836,7 +834,7 @@ namespace Umbraco.Core.Services
var asArray = contentTypes.ToArray();
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(asArray), this))
return;
return;
using (new WriteLock(Locker))
{
@@ -1004,8 +1002,8 @@ namespace Umbraco.Core.Services
var evtMsgs = EventMessagesFactory.Get();
if (MovingMediaType.IsRaisedEventCancelled(
new MoveEventArgs<IMediaType>(evtMsgs, new MoveEventInfo<IMediaType>(toMove, toMove.Path, containerId)),
this))
new MoveEventArgs<IMediaType>(evtMsgs, new MoveEventInfo<IMediaType>(toMove, toMove.Path, containerId)),
this))
{
return Attempt.Fail(
new OperationStatus<MoveOperationStatusType>(
@@ -1047,8 +1045,8 @@ namespace Umbraco.Core.Services
var evtMsgs = EventMessagesFactory.Get();
if (MovingContentType.IsRaisedEventCancelled(
new MoveEventArgs<IContentType>(evtMsgs, new MoveEventInfo<IContentType>(toMove, toMove.Path, containerId)),
this))
new MoveEventArgs<IContentType>(evtMsgs, new MoveEventInfo<IContentType>(toMove, toMove.Path, containerId)),
this))
{
return Attempt.Fail(
new OperationStatus<MoveOperationStatusType>(
@@ -1178,8 +1176,8 @@ namespace Umbraco.Core.Services
/// <param name="userId">Optional Id of the user saving the MediaType</param>
public void Save(IMediaType mediaType, int userId = 0)
{
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
return;
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
return;
using (new WriteLock(Locker))
{
@@ -1188,6 +1186,8 @@ namespace Umbraco.Core.Services
{
ValidateLocked(mediaType); // throws if invalid
mediaType.CreatorId = userId;
if (mediaType.Description == string.Empty)
mediaType.Description = null;
repository.AddOrUpdate(mediaType);
uow.Commit();
@@ -1197,7 +1197,7 @@ namespace Umbraco.Core.Services
}
SavedMediaType.RaiseEvent(new SaveEventArgs<IMediaType>(mediaType, false), this);
Audit(AuditType.Save, string.Format("Save MediaType performed by user"), userId, mediaType.Id);
Audit(AuditType.Save, string.Format("Save MediaType performed by user"), userId, mediaType.Id);
}
/// <summary>
@@ -1210,7 +1210,7 @@ namespace Umbraco.Core.Services
var asArray = mediaTypes.ToArray();
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(asArray), this))
return;
return;
using (new WriteLock(Locker))
{
@@ -1225,6 +1225,8 @@ namespace Umbraco.Core.Services
foreach (var mediaType in asArray)
{
mediaType.CreatorId = userId;
if (mediaType.Description == string.Empty)
mediaType.Description = null;
repository.AddOrUpdate(mediaType);
}
@@ -1236,7 +1238,7 @@ namespace Umbraco.Core.Services
}
SavedMediaType.RaiseEvent(new SaveEventArgs<IMediaType>(asArray, false), this);
Audit(AuditType.Save, string.Format("Save MediaTypes performed by user"), userId, -1);
Audit(AuditType.Save, string.Format("Save MediaTypes performed by user"), userId, -1);
}
/// <summary>
@@ -1247,8 +1249,8 @@ namespace Umbraco.Core.Services
/// <remarks>Deleting a <see cref="IMediaType"/> will delete all the <see cref="IMedia"/> objects based on this <see cref="IMediaType"/></remarks>
public void Delete(IMediaType mediaType, int userId = 0)
{
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
return;
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
return;
using (new WriteLock(Locker))
{
_mediaService.DeleteMediaOfType(mediaType.Id, userId);
@@ -1280,7 +1282,7 @@ namespace Umbraco.Core.Services
var asArray = mediaTypes.ToArray();
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(asArray), this))
return;
return;
using (new WriteLock(Locker))
{
foreach (var mediaType in asArray)
@@ -1390,40 +1392,40 @@ namespace Umbraco.Core.Services
/// </summary>
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletingContentType;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletedContentType;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletedContentType;
/// <summary>
/// Occurs before Delete
/// </summary>
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletingMediaType;
/// <summary>
/// Occurs before Delete
/// </summary>
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletingMediaType;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletedMediaType;
/// <summary>
/// Occurs after Delete
/// </summary>
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletedMediaType;
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavingContentType;
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavingContentType;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavedContentType;
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IContentType>> SavedContentType;
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavingMediaType;
/// <summary>
/// Occurs before Save
/// </summary>
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavingMediaType;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavedMediaType;
/// <summary>
/// Occurs after Save
/// </summary>
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<IMediaType>> SavedMediaType;
/// <summary>
/// Occurs before Move
@@ -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
@@ -70,5 +71,20 @@ namespace Umbraco.Core.Services
return toUpdate;
}
/// <summary>
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
/// </summary>
/// <param name="contentPath"></param>
/// <returns></returns>
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);
}
}
}
}
@@ -11,6 +11,13 @@ namespace Umbraco.Core.Services
/// </summary>
public interface IContentTypeService : IService
{
/// <summary>
/// Given the path of a content item, this will return true if the content item exists underneath a list view content item
/// </summary>
/// <param name="contentPath"></param>
/// <returns></returns>
bool HasContainerInPath(string contentPath);
int CountContentTypes();
int CountMediaTypes();
@@ -2,12 +2,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Umbraco.Core.Auditing;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Services
@@ -89,6 +87,8 @@ namespace Umbraco.Core.Services
using (var repository = RepositoryFactory.CreateMemberTypeRepository(uow))
{
memberType.CreatorId = userId;
if (memberType.Description == string.Empty)
memberType.Description = null;
repository.AddOrUpdate(memberType);
uow.Commit();
@@ -114,6 +114,8 @@ namespace Umbraco.Core.Services
foreach (var memberType in asArray)
{
memberType.CreatorId = userId;
if (memberType.Description == string.Empty)
memberType.Description = null;
repository.AddOrUpdate(memberType);
}
@@ -46,23 +46,6 @@ namespace Umbraco.Tests.Persistence.Repositories
return new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Mock.Of<ILogger>(), 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<IDataTypeDefinition>().Result
.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
.GetCacheItemsByKeySearch<PreValueCollection>(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<IDataTypeDefinition>().Result
.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + dtd.Id + "-");
.GetCacheItemsByKeySearch<PreValueCollection>(CacheKeys.DataTypePreValuesCacheKey + "_" + dtd.Id);
Assert.IsNotNull(cached);
Assert.AreEqual(1, cached.Count());
@@ -1,4 +1,3 @@
using System.Runtime.Remoting;
using NUnit.Framework;
using System;
using System.Collections.Generic;
@@ -8,7 +7,6 @@ using Umbraco.Core.Exceptions;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Services;
using Umbraco.Tests.CodeFirst.TestModels.Composition;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -1420,6 +1418,38 @@ namespace Umbraco.Tests.Services
Assert.That(descriptionPropertyTypeReloaded.PropertyGroupId.IsValueCreated, Is.False);
}
[Test]
public void Empty_Description_Is_Always_Null_After_Saving_Content_Type()
{
var service = ServiceContext.ContentTypeService;
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.Description = null;
service.Save(contentType);
var contentType2 = MockedContentTypes.CreateBasicContentType("basePage2", "Base Page 2");
contentType2.Description = string.Empty;
service.Save(contentType2);
Assert.IsNull(contentType.Description);
Assert.IsNull(contentType2.Description);
}
[Test]
public void Empty_Description_Is_Always_Null_After_Saving_Media_Type()
{
var service = ServiceContext.ContentTypeService;
var mediaType = MockedContentTypes.CreateSimpleMediaType("mediaType", "Media Type");
mediaType.Description = null;
service.Save(mediaType);
var mediaType2 = MockedContentTypes.CreateSimpleMediaType("mediaType2", "Media Type 2");
mediaType2.Description = string.Empty;
service.Save(mediaType2);
Assert.IsNull(mediaType.Description);
Assert.IsNull(mediaType2.Description);
}
private ContentType CreateComponent()
{
var component = new ContentType(-1)
@@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using umbraco.cms.presentation.create.controls;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
@@ -183,6 +181,22 @@ namespace Umbraco.Tests.Services
Assert.Throws<ArgumentException>(() => ServiceContext.MemberTypeService.Save(memberType));
}
[Test]
public void Empty_Description_Is_Always_Null_After_Saving_Member_Type()
{
var service = ServiceContext.MemberTypeService;
var memberType = MockedContentTypes.CreateSimpleMemberType();
memberType.Description = null;
service.Save(memberType);
var memberType2 = MockedContentTypes.CreateSimpleMemberType("memberType2", "Member Type 2");
memberType2.Description = string.Empty;
service.Save(memberType2);
Assert.IsNull(memberType.Description);
Assert.IsNull(memberType2.Description);
}
//[Test]
//public void Can_Save_MemberType_Structure_And_Create_A_Member_Based_On_It()
//{
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
+2 -2
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.82.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.82\lib\net45\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>
+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.82" 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" />
@@ -3,232 +3,285 @@
<h3>Examine Management</h3>
<div ng-show="loading">
Loading...
<div class="umb-healthcheck-group__details-status-overlay"></div>
<umb-load-indicator></umb-load-indicator>
</div>
<h4>Indexers</h4>
<div ng-hide="loading" class="umb-healthcheck-group__details">
<ul ng-hide="loading">
<li class="provider" ng-repeat="indexer in indexerDetails">
<div class="umb-healthcheck-group__details-group-title">
<div class="umb-healthcheck-group__details-group-name">Indexers</div>
</div>
<a class="btn-link -underline" href="" ng-click="toggle(indexer, 'showProperties')">
{{indexer.name}}
</a>
<div class="umb-healthcheck-group__details-checks">
<div class="umb-healthcheck-group__details-check">
<div class="umb-healthcheck-group__details-check-title">
<div class="umb-healthcheck-group__details-check-name">Manage Examine's indexes</div>
<div class="umb-healthcheck-group__details-check-description">Allows you to view the details of each index and provides some tools for managing the indexes</div>
</div>
<ul ng-show="indexer.showProperties">
<div class="umb-healthcheck-group__details-status" ng-repeat="indexer in indexerDetails">
<li>
<div class="umb-healthcheck-group__details-status-icon-container">
<i class="umb-healthcheck-status-icon" ng-class="{'icon-check color-green' : indexer.isHealthy, 'icon-delete color-red' : !indexer.isHealthy}"></i>
</div>
<a href="" ng-click="toggle(indexer, 'showTools')">Index info & tools</a>
<div ng-show="indexer.showTools && indexer.isLuceneIndex">
<div>
<br />
<div ng-show="!indexer.isProcessing && (!indexer.processingAttempts || indexer.processingAttempts < 100)" class="btn-group">
<button type="button" class="btn btn-warning" ng-click="rebuildIndex(indexer)">Rebuild index</button>
<button type="button" class="btn btn-warning" ng-click="optimizeIndex(indexer)" ng-show="indexer.documentCount > 0">Optimize index</button>
<div class="umb-healthcheck-group__details-status-content">
<div class="umb-healthcheck-group__details-status-text">
<div ng-show="!indexer.isHealthy">
{{indexer.name}}
</div>
<div ng-show="indexer.isProcessing" class="umb-loader-wrapper" ng-show="actionInProgress">
<div class="umb-loader"></div>
</div>
<div class="error" ng-show="indexer.processingAttempts >= 100">
The process is taking longer than expected, check the umbraco log to see if there have been any errors during this operation
<a class="btn-link -underline" href="" ng-click="toggle(indexer, 'showProperties')" ng-show="indexer.isHealthy">
{{indexer.name}}
</a>
<div ng-if="!indexer.isHealthy" class="text-error">
The index cannot be read and will need to be rebuilt
</div>
</div>
<table class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<tr>
<th>Documents in index</th>
<td>{{indexer.documentCount}}</td>
</tr>
<tr>
<th>Fields in index</th>
<td>{{indexer.fieldCount}}</td>
</tr>
<tr>
<th>Has deletions?</th>
<td>
<span>{{indexer.deletionCount > 0}}</span>
(<span>{{indexer.deletionCount}}</span>)
</td>
</tr>
<tr>
<th>Optimized?</th>
<td>
<span>{{indexer.isOptimized}}</span>
</td>
</tr>
</table>
</div>
</li>
<li ng-show="indexer.indexCriteria.IncludeNodeTypes.length > 0 || indexer.indexCriteria.ExcludeNodeTypes.length > 0 || indexer.indexCriteria.ParentNodeId">
<a href="" ng-click="toggle(indexer, 'showNodeTypes')">Node types</a>
<table ng-show="indexer.showNodeTypes" class="table table-bordered table-condensed">
<tr ng-show="indexer.indexCriteria.IncludeNodeTypes.length > 0">
<th>Include node types</th>
<td>{{indexer.indexCriteria.IncludeNodeTypes | json}}</td>
</tr>
<tr ng-show="indexer.indexCriteria.ExcludeNodeTypes.length > 0">
<th>Exclude node types</th>
<td>{{indexer.indexCriteria.ExcludeNodeTypes | json}}</td>
</tr>
<tr ng-show="indexer.indexCriteria.ParentNodeId">
<th>Parent node id</th>
<td>{{indexer.indexCriteria.ParentNodeId}}</td>
</tr>
</table>
</li>
<li ng-show="indexer.indexCriteria.StandardFields.length > 0">
<a href="" ng-click="toggle(indexer, 'showSystemFields')">System fields</a>
<table ng-show="indexer.showSystemFields" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<thead>
<tr>
<th>Name</th>
<th>Enable sorting</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="field in indexer.indexCriteria.StandardFields">
<th>{{field.Name}}</th>
<td>{{field.EnableSorting}}</td>
<td>{{field.Type}}</td>
</tr>
</tbody>
</table>
</li>
<li ng-show="indexer.indexCriteria.UserFields.length > 0">
<a href="" ng-click="toggle(indexer, 'showUserFields')">User fields</a>
<table ng-show="indexer.showUserFields" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<thead>
<tr>
<th>Name</th>
<th>Enable sorting</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="field in indexer.indexCriteria.UserFields">
<th>{{field.Name}}</th>
<td>{{field.EnableSorting}}</td>
<td>{{field.Type}}</td>
</tr>
</tbody>
</table>
</li>
<li>
<a href="" ng-click="toggle(indexer, 'showProviderProperties')">Provider properties</a>
<table ng-show="indexer.showProviderProperties" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<tr ng-repeat="(key, val) in indexer.providerProperties track by $index">
<th>{{key}}</th>
<td>{{val}}</td>
</tr>
</table>
</li>
</ul>
</li>
</ul>
<h4>Searchers</h4>
<ul ng-hide="loading">
<li class="provider" ng-repeat="searcher in searcherDetails">
<a class="btn-link -underline" href="" ng-click="toggle(searcher, 'showProperties')">
{{searcher.name}}
</a>
<ul ng-show="searcher.showProperties">
<li class="search-tools">
<a href="" ng-click="toggle(searcher, 'showTools')">Search tools</a>
<div ng-show="searcher.showTools">
<a class="hide" href="" ng-click="closeSearch(searcher)" ng-show="searcher.isSearching">Hide search results</a>
<br />
<form>
<div class="row form-search">
<div class="span8 input-append">
<input type="text" class="search-query" ng-model="searcher.searchText" no-dirty-check />
<button type="button" class="btn btn-info" ng-click="search(searcher)" ng-disabled="searcher.isProcessing">Search</button>
</div>
</div>
<div class="row">
<label for="{{searcher.name}}-textSearch" class="radio inline">
<input type="radio" name="searchType" id="{{searcher.name}}-textSearch" value="text" ng-model="searcher.searchType" no-dirty-check />
Text Search
</label>
<label for="{{searcher.name}}-luceneSearch" class="radio inline">
<input type="radio" name="searchType" id="{{searcher.name}}-luceneSearch" value="lucene" ng-model="searcher.searchType" no-dirty-check />
Lucene Search
</label>
<div class="umb-healthcheck-group__details-status-actions" ng-if="!indexer.isHealthy">
<div class="umb-healthcheck-group__details-status-action">
<button type="button" class="umb-era-button -blue"
ng-show="!indexer.isProcessing && (!indexer.processingAttempts || indexer.processingAttempts < 100)"
ng-click="rebuildIndex(indexer)">
Rebuild index
</button>
</div>
</div>
<div class="umb-healthcheck-group__details-status-actions" ng-show="indexer.isHealthy && indexer.showProperties">
<ul>
<li>
<a href="" ng-click="toggle(indexer, 'showTools')">Index info & tools</a>
</form>
<div ng-show="indexer.showTools && indexer.isLuceneIndex">
<div>
<br />
<div class="search-results" ng-show="searcher.isSearching">
<div ng-show="!indexer.isProcessing && (!indexer.processingAttempts || indexer.processingAttempts < 100)"
class="umb-healthcheck-group__details-status-action">
<button type="button" class="umb-era-button -blue" ng-click="rebuildIndex(indexer)">Rebuild index</button>
</div>
<div ng-show="indexer.isProcessing" class="umb-loader-wrapper" ng-show="indexer.isProcessing">
<div class="umb-loader"></div>
</div>
<div ng-show="indexer.processingAttempts >= 100">
The process is taking longer than expected, check the umbraco log to see if there have been any errors during this operation
</div>
</div>
<table class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<tr>
<th>Documents in index</th>
<td>{{indexer.documentCount}}</td>
</tr>
<tr>
<th>Fields in index</th>
<td>{{indexer.fieldCount}}</td>
</tr>
<tr>
<th>Has deletions?</th>
<td>
<span>{{indexer.deletionCount > 0}}</span>
(<span>{{indexer.deletionCount}}</span>)
</td>
</tr>
<tr>
<th>Optimized?</th>
<td>
<span>{{indexer.isOptimized}}</span>
</td>
</tr>
<table ng-hide="searcher.isProcessing" class="table table-bordered table-condensed">
<thead>
<tr>
<th class="score">Score</th>
<th class="id">Id</th>
<th>Values</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="result in searcher.searchResults">
<td>{{result.Score}}</td>
<td>{{result.Id}}</td>
<td>
<span ng-repeat="(key,val) in result.Fields track by $index">
<span class=""><em>{{key}}</em>:</span>
<span class="text-info">{{val}}</span>
</span>
</td>
</tr>
</tbody>
</table>
</table>
</div>
</li>
<li ng-show="indexer.indexCriteria.IncludeNodeTypes.length > 0 || indexer.indexCriteria.ExcludeNodeTypes.length > 0 || indexer.indexCriteria.ParentNodeId">
<a href="" ng-click="toggle(indexer, 'showNodeTypes')">Node types</a>
<table ng-show="indexer.showNodeTypes" class="table table-bordered table-condensed">
<tr ng-show="indexer.indexCriteria.IncludeNodeTypes.length > 0">
<th>Include node types</th>
<td>{{indexer.indexCriteria.IncludeNodeTypes | json}}</td>
</tr>
<tr ng-show="indexer.indexCriteria.ExcludeNodeTypes.length > 0">
<th>Exclude node types</th>
<td>{{indexer.indexCriteria.ExcludeNodeTypes | json}}</td>
</tr>
<tr ng-show="indexer.indexCriteria.ParentNodeId">
<th>Parent node id</th>
<td>{{indexer.indexCriteria.ParentNodeId}}</td>
</tr>
</table>
</li>
<li ng-show="indexer.indexCriteria.StandardFields.length > 0">
<a href="" ng-click="toggle(indexer, 'showSystemFields')">System fields</a>
<table ng-show="indexer.showSystemFields" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<thead>
<tr>
<th>Name</th>
<th>Enable sorting</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="field in indexer.indexCriteria.StandardFields">
<th>{{field.Name}}</th>
<td>{{field.EnableSorting}}</td>
<td>{{field.Type}}</td>
</tr>
</tbody>
</table>
</li>
<li ng-show="indexer.indexCriteria.UserFields.length > 0">
<a href="" ng-click="toggle(indexer, 'showUserFields')">User fields</a>
<table ng-show="indexer.showUserFields" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<thead>
<tr>
<th>Name</th>
<th>Enable sorting</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="field in indexer.indexCriteria.UserFields">
<th>{{field.Name}}</th>
<td>{{field.EnableSorting}}</td>
<td>{{field.Type}}</td>
</tr>
</tbody>
</table>
</li>
<li>
<a href="" ng-click="toggle(indexer, 'showProviderProperties')">Provider properties</a>
<table ng-show="indexer.showProviderProperties" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<tr ng-repeat="(key, val) in indexer.providerProperties track by $index">
<th>{{key}}</th>
<td>{{val}}</td>
</tr>
</table>
</li>
</ul>
</div>
</div>
</li>
<li>
<a href="" ng-click="toggle(searcher, 'showProviderProperties')">Provider properties</a>
<table ng-show="searcher.showProviderProperties" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<tr ng-repeat="(key, val) in searcher.providerProperties track by $index">
<th>{{key}}</th>
<td>{{val}}</td>
</tr>
</table>
</li>
<div ng-show="indexer.isProcessing">
<div class="umb-healthcheck-group__details-status-overlay"></div>
<umb-load-indicator></umb-load-indicator>
</div>
</div>
</div>
</div>
<br />
<div class="umb-healthcheck-group__details-group-title">
<div class="umb-healthcheck-group__details-group-name">Searchers</div>
</div>
<div class="umb-healthcheck-group__details-checks">
<div class="umb-healthcheck-group__details-check">
<div class="umb-healthcheck-group__details-check-title">
<div class="umb-healthcheck-group__details-check-name">Search indexes</div>
<div class="umb-healthcheck-group__details-check-description">Allows you to search the indexes and view the searcher properties</div>
</div>
<div class="umb-healthcheck-group__details-status" ng-repeat="searcher in searcherDetails">
<div class="umb-healthcheck-group__details-status-icon-container">
<i class="umb-healthcheck-status-icon icon-info"></i>
</div>
<div class="umb-healthcheck-group__details-status-content">
<div class="umb-healthcheck-group__details-status-text">
<a class="btn-link -underline" href="" ng-click="toggle(searcher, 'showProperties')">
{{searcher.name}}
</a>
</div>
<div class="umb-healthcheck-group__details-status-actions" ng-show="searcher.showProperties">
<ul>
<li class="search-tools">
<a href="" ng-click="toggle(searcher, 'showTools')">Search tools</a>
<div ng-show="searcher.showTools">
<a class="hide" href="" ng-click="closeSearch(searcher)" ng-show="searcher.isSearching">Hide search results</a>
<br />
<form>
<div class="row form-search">
<div class="span8 input-append">
<input type="text" class="search-query" ng-model="searcher.searchText" no-dirty-check />
<button type="button" class="btn btn-info" ng-click="search(searcher)" ng-disabled="searcher.isProcessing">Search</button>
</div>
</div>
<div class="row">
<label for="{{searcher.name}}-textSearch" class="radio inline">
<input type="radio" name="searchType" id="{{searcher.name}}-textSearch" value="text" ng-model="searcher.searchType" no-dirty-check />
Text Search
</label>
<label for="{{searcher.name}}-luceneSearch" class="radio inline">
<input type="radio" name="searchType" id="{{searcher.name}}-luceneSearch" value="lucene" ng-model="searcher.searchType" no-dirty-check />
Lucene Search
</label>
</div>
</form>
<div class="search-results" ng-show="searcher.isSearching">
<div ng-show="indexer.isProcessing" class="umb-loader-wrapper" ng-show="indexer.isProcessing">
<div class="umb-loader"></div>
</div>
<table ng-hide="searcher.isProcessing" class="table table-bordered table-condensed">
<thead>
<tr>
<th class="score">Score</th>
<th class="id">Id</th>
<th>Values</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="result in searcher.searchResults">
<td>{{result.Score}}</td>
<td>{{result.Id}}</td>
<td>
<span ng-repeat="(key,val) in result.Fields track by $index">
<span class=""><em>{{key}}</em>:</span>
<span class="text-info">{{val}}</span>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</li>
<li>
<a href="" ng-click="toggle(searcher, 'showProviderProperties')">Provider properties</a>
<table ng-show="searcher.showProviderProperties" class="table table-bordered table-condensed">
<caption>&nbsp;</caption>
<tr ng-repeat="(key, val) in searcher.providerProperties track by $index">
<th>{{key}}</th>
<td>{{val}}</td>
</tr>
</table>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</ul>
</li>
</ul>
</div>
@@ -17,7 +17,7 @@
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li ng-repeat="contentType in listViewAllowedTypes">
<li ng-repeat="contentType in listViewAllowedTypes | orderBy:'name':false">
<a href="#/{{entityType}}/{{entityType}}/edit/{{contentId}}?doctype={{contentType.alias}}&create=true">
<i class="icon-{{contentType.cssClass}}"></i>
{{contentType.name}}
+6 -6
View File
@@ -127,8 +127,8 @@
<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.82.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.82\lib\net45\Examine.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -350,8 +350,8 @@
<Name>umbraco.providers</Name>
</ProjectReference>
<Reference Include="System.Xml.Linq" />
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.5.96, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.5\lib\Umbraco.ModelsBuilder.dll</HintPath>
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.6.97, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.6\lib\Umbraco.ModelsBuilder.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="UrlRewritingNet.UrlRewriter, Version=2.0.7.0, Culture=neutral, processorArchitecture=MSIL">
@@ -2423,9 +2423,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7511</DevelopmentServerPort>
<DevelopmentServerPort>7512</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7511</IISUrl>
<IISUrl>http://localhost:7512</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
+2 -2
View File
@@ -4,7 +4,7 @@
<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="Examine" version="0.1.82" targetFramework="net45" />
<package id="ImageProcessor" version="2.5.2" targetFramework="net45" />
<package id="ImageProcessor.Web" version="4.8.2" targetFramework="net45" />
<package id="ImageProcessor.Web.Config" version="2.3.0" targetFramework="net45" />
@@ -37,6 +37,6 @@
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
<package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
<package id="System.Reflection.Metadata" version="1.0.21" targetFramework="net45" />
<package id="Umbraco.ModelsBuilder" version="3.0.5" targetFramework="net45" />
<package id="Umbraco.ModelsBuilder" version="3.0.6" targetFramework="net45" />
<package id="UrlRewritingNet.UrlRewriter" version="2.0.7" targetFramework="net45" />
</packages>
@@ -972,7 +972,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="dictionaryItemSaved">Dictionary item saved</key>
<key alias="editContentPublishedFailedByParent">Publishing failed because the parent page isn't published</key>
<key alias="editContentPublishedHeader">Content published</key>
<key alias="editContentPublishedText">and visible at the website</key>
<key alias="editContentPublishedText">and visible on the website</key>
<key alias="editContentSavedHeader">Content saved</key>
<key alias="editContentSavedText">Remember to publish to make changes visible</key>
<key alias="editContentSendToPublish">Sent For Approval</key>
@@ -972,7 +972,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="dictionaryItemSaved">Dictionary item saved</key>
<key alias="editContentPublishedFailedByParent">Publishing failed because the parent page isn't published</key>
<key alias="editContentPublishedHeader">Content published</key>
<key alias="editContentPublishedText">and visible at the website</key>
<key alias="editContentPublishedText">and visible on the website</key>
<key alias="editContentSavedHeader">Content saved</key>
<key alias="editContentSavedText">Remember to publish to make changes visible</key>
<key alias="editContentSendToPublish">Sent For Approval</key>
+15 -2
View File
@@ -123,7 +123,6 @@
<key alias="saveListView">Сохранить список</key>
<key alias="select">Выбрать</key>
<key alias="selectCurrentFolder">Выбрать текущую папку</key>
<key alias="selected">выбранные</key>
<key alias="showPage">Предварительный просмотр</key>
<key alias="showPageDisabled">Предварительный просмотр запрещен, так как документу не сопоставлен шаблон</key>
<key alias="somethingElse">Другие действия</key>
@@ -993,6 +992,7 @@
<key alias="installStateInstalling">Установка...</key>
<key alias="installStateRestarting">Перезапуск, подождите, пожалуйста...</key>
<key alias="installStateComplete">Все готово, сейчас браузер перезагрузит страницу, подождите, пожалуйста...</key>
<key alias="installStateCompleted">Пожалуйста, нажмите кнопку 'finish' для завершения установки и перезагрузки страницы.</key>
</area>
<area alias="paste">
<key alias="doNothing">Вставить, полностью сохранив форматирование (не рекомендуется)</key>
@@ -1119,9 +1119,9 @@
<key alias="statistics">Статистика</key>
<key alias="translation">Перевод</key>
<key alias="users">Пользователи</key>
<key alias="addIcon">Добавить значок</key>
</area>
<area alias="settings">
<key alias="addIcon">Добавить значок</key>
<key alias="asAContentMasterType">в качестве родительского типа. Вкладки родительского типа не показаны и могут быть изменены непосредственно в родительском типе</key>
<key alias="contentTypeEnabled">Родительский тип контента разрешен</key>
<key alias="contentTypeUses">Данный тип контента использует</key>
@@ -1178,6 +1178,7 @@
<key alias="contentTypeTabDeletedText">Вкладка с идентификатором (id): %0% удалена</key>
<key alias="contentUnpublished">Документ скрыт (публикация отменена)</key>
<key alias="cssErrorHeader">Стиль CSS не сохранен</key>
<key alias="cssErrorText">При сохранении файла произошла ошибка.</key>
<key alias="cssSavedHeader">Стиль CSS сохранен</key>
<key alias="cssSavedText">Стиль CSS сохранен без ошибок</key>
<key alias="dataTypeSaved">Тип данных сохранен</key>
@@ -1202,9 +1203,13 @@
<key alias="fileErrorText">Файл не может быть сохранен. Пожалуйста, проверьте установки файловых разрешений</key>
<key alias="fileSavedHeader">Файл сохранен</key>
<key alias="fileSavedText">Файл сохранен без ошибок</key>
<key alias="invalidUserPermissionsText">У текущего пользователя недостаточно прав, невозможно завершить операцию</key>
<key alias="languageSaved">Язык сохранен</key>
<key alias="mediaTypeSavedHeader">Тип медиа сохранен</key>
<key alias="memberTypeSavedHeader">Тип участника сохранен</key>
<key alias="operationCancelledHeader">Отменено</key>
<key alias="operationCancelledText">Операция отменена установленным сторонним расширением или блоком кода</key>
<key alias="operationFailedHeader">Ошибка</key>
<key alias="partialViewErrorHeader">Представление не сохранено</key>
<key alias="partialViewErrorText">Произошла ошибка при сохранении файла</key>
<key alias="partialViewSavedHeader">Представление сохранено</key>
@@ -1213,10 +1218,16 @@
<key alias="pythonErrorText">Cкрипт Python не может быть сохранен в связи с ошибками</key>
<key alias="pythonSavedHeader">Cкрипт Python сохранен</key>
<key alias="pythonSavedText">Cкрипт Python сохранен без ошибок</key>
<key alias="scriptErrorHeader">Скрипт не сохранен</key>
<key alias="scriptErrorText">При сохранении файла скрипта произошла ошибка</key>
<key alias="scriptSavedHeader">Скрипт сохранен</key>
<key alias="scriptSavedText">Файл скрипта сохранен без ошибок</key>
<key alias="templateErrorHeader">Шаблон не сохранен</key>
<key alias="templateErrorText">Пожалуйста, проверьте, что нет двух шаблонов с одним и тем же алиасом (названием)</key>
<key alias="templateSavedHeader">Шаблон сохранен</key>
<key alias="templateSavedText">Шаблон сохранен без ошибок</key>
<key alias="validationFailedHeader">Проверка значений</key>
<key alias="validationFailedMessage">Ошибки, найденные при проверке значений, должны быть исправлены, чтобы было возможно сохранить документ</key>
<key alias="xsltErrorHeader">XSLT-документ не сохранен</key>
<key alias="xsltErrorText">XSLT-документ содержит одну или несколько ошибок</key>
<key alias="xsltPermissionErrorText">XSLT-документ не может быть сохранен, проверьте установки файловых разрешений</key>
@@ -1343,6 +1354,7 @@
<key alias="packager">Пакеты дополнений</key>
<key alias="packages">Пакеты дополнений</key>
<key alias="python">Скрипты Python</key>
<key alias="relationTypes">Типы связей</key>
<key alias="repositories">Установить из репозитория</key>
<key alias="runway">Установить Runway</key>
<key alias="runwayModules">Модули Runway </key>
@@ -1361,6 +1373,7 @@
<area alias="user">
<key alias="administrators">Администратор</key>
<key alias="categoryField">Поле категории</key>
<key alias="change">Изменить</key>
<key alias="changePassword">Изменить пароль</key>
<key alias="changePasswordDescription">Вы можете сменить свой пароль для доступа к административной панели Umbraco, заполнив нижеследующие поля и нажав на кнопку 'Изменить пароль'</key>
<key alias="confirmNewPassword">Подтверждение нового пароля</key>
@@ -101,13 +101,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<IDataTypeDefinition>();
payloads.ForEach(payload =>
{
//clears the prevalue cache
var dataTypeCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache<IDataTypeDefinition>();
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);
});
@@ -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";
@@ -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";
@@ -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<HealthCheckController>("Running health check: " + check.Name);
return check.GetStatus();
}
catch (Exception e)
{
Core.Logging.LogHelper.Error<HealthCheckController>("Exception in health check: " + check.Name, e);
throw;
}
}
[HttpPost]
@@ -19,7 +19,7 @@ namespace Umbraco.Web.HealthCheck
/// </remarks>
internal class HealthCheckResolver : LazyManyObjectsResolverBase<HealthCheckResolver, HealthCheck>, IHealthCheckResolver
{
public HealthCheckResolver(ILogger logger, Func<IEnumerable<Type>> lazyTypeList)
public HealthCheckResolver(ILogger logger, Func<IEnumerable<Type>> 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);
}
@@ -36,7 +36,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,
@@ -75,6 +75,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;
}
/// <summary>
/// Maps the generic tab with custom properties for content
/// </summary>
@@ -86,31 +92,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)
@@ -223,26 +207,7 @@ namespace Umbraco.Web.Models.Mapping
}
/// <summary>
/// Gets the published date value for the IContent object
/// </summary>
/// <param name="content"></param>
/// <param name="applicationContext"></param>
/// <returns></returns>
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;
}
/// <summary>
//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'
/// </summary>
private class ActionButtonsResolver : ValueResolver<IContent, IEnumerable<char>>
@@ -41,7 +41,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<ContentPropertyBasic, IMedia>
config.CreateMap<IMedia, ContentItemBasic<ContentPropertyBasic, IMedia>>()
@@ -64,34 +64,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;
}
}
// Adapted from ContentModelMapper
//map the IsChildOfListView (this is actually if it is a descendant of a list view!)
var parent = media.Parent();
display.IsChildOfListView = parent != null && (parent.ContentType.IsContainer || contentTypeService.HasContainerInPath(parent.Path));
//map the tree node url
if (HttpContext.Current != null)
+1
View File
@@ -175,6 +175,7 @@ namespace Umbraco.Web.Mvc
public IModelBinder GetBinder(Type modelType)
{
// can bind to RenderModel (exact type match)
// You might be tempted to change this to IRenderModel but do not change this: http://issues.umbraco.org/issue/U4-8216
if (modelType == typeof(RenderModel)) return this;
// can bind to RenderModel<TContent> (exact generic type match)
@@ -8,6 +8,7 @@ namespace Umbraco.Web.Search
[DataContract(Name = "indexer", Namespace = "")]
public class ExamineIndexerModel : ExamineSearcherModel
{
[DataMember(Name = "indexCriteria")]
public IIndexCriteria IndexCriteria { get; set; }
@@ -14,6 +14,18 @@ namespace Umbraco.Web.Search
ProviderProperties = new Dictionary<string, string>();
}
/// <summary>
/// If the index is not healthy this represents the index error state
/// </summary>
[DataMember(Name = "error")]
public string Error { get; set; }
/// <summary>
/// If the index can be open/read
/// </summary>
[DataMember(Name = "isHealthy")]
public bool IsHealthy { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
@@ -15,6 +15,28 @@ namespace Umbraco.Web.Search
/// </summary>
internal static class ExamineExtensions
{
/// <summary>
/// Checks if the index can be read/opened
/// </summary>
/// <param name="indexer"></param>
/// <param name="ex">The exception returned if there was an error</param>
/// <returns></returns>
public static bool IsHealthy(this LuceneIndexer indexer, out Exception ex)
{
try
{
using (indexer.GetIndexWriter().GetReader())
{
ex = null;
return true;
}
}
catch (Exception e)
{
ex = e;
return false;
}
}
/// <summary>
/// Return the number of indexed documents in Lucene
+2 -2
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.82.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.82\lib\net45\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>
+6 -1
View File
@@ -1389,10 +1389,15 @@ namespace Umbraco.Web
return test ? new HtmlString(valueIfTrue) : new HtmlString(string.Empty);
}
#endregion
#endregion
#region Prevalues
/// <summary>
/// Gets a specific PreValue by its Id
/// </summary>
/// <param name="id">Id of the PreValue to retrieve the value from</param>
/// <returns>PreValue as a string</returns>
public string GetPreValueAsString(int id)
{
return DataTypeService.GetPreValueAsString(id);
+9
View File
@@ -579,6 +579,15 @@ namespace Umbraco.Web
// is complete and cancel this current event so the rebuild process doesn't start right now.
args.Cancel = true;
IndexesToRebuild.Add((BaseIndexProvider)args.Indexer);
//check if the index is rebuilding due to an error and log it
if (args.IsHealthy == false)
{
var baseIndex = args.Indexer as BaseIndexProvider;
var name = baseIndex != null ? baseIndex.Name : "[UKNOWN]";
ProfilingLogger.Logger.Error<WebBootManager>(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException);
}
}
}
}
@@ -86,7 +86,7 @@ namespace Umbraco.Web.WebServices
var model = new List<ExamineSearcherModel>(
ExamineManager.Instance.SearchProviderCollection.Cast<BaseSearchProvider>().Select(searcher =>
{
var indexerModel = new ExamineIndexerModel()
var indexerModel = new ExamineSearcherModel()
{
Name = searcher.Name
};
@@ -260,6 +260,7 @@ namespace Umbraco.Web.WebServices
IndexCriteria = indexer.IndexerData,
Name = indexer.Name
};
var props = TypeHelper.CachedDiscoverableProperties(indexer.GetType(), mustWrite: false)
//ignore these properties
.Where(x => new[] {"IndexerData", "Description", "WorkingFolder"}.InvariantContains(x.Name) == false)
@@ -281,11 +282,21 @@ namespace Umbraco.Web.WebServices
var luceneIndexer = indexer as LuceneIndexer;
if (luceneIndexer != null)
{
{
indexerModel.IsLuceneIndex = true;
if (luceneIndexer.IndexExists())
{
Exception indexError;
indexerModel.IsHealthy = luceneIndexer.IsHealthy(out indexError);
if (indexerModel.IsHealthy == false)
{
//we cannot continue at this point
indexerModel.Error = indexError.ToString();
return indexerModel;
}
indexerModel.DocumentCount = luceneIndexer.GetIndexDocumentCount();
indexerModel.FieldCount = luceneIndexer.GetIndexFieldCount();
indexerModel.IsOptimized = luceneIndexer.IsIndexOptimized();
+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.82" 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" />
@@ -431,7 +431,7 @@ namespace umbraco
{
XmlNode x;
//Hack: this is here purely for backwards compat if someone for some reason is using the
//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)
{
@@ -870,8 +870,15 @@ namespace umbraco
catch (Exception e)
{
// if something goes wrong remove the file
DeleteXmlFile();
try
{
DeleteXmlFile();
}
catch
{
// don't make it worse: could be that we failed to write because we cannot
// access the file, in which case we won't be able to delete it either
}
LogHelper.Error<content>("Failed to save Xml to file.", e);
}
}
@@ -933,7 +940,15 @@ namespace umbraco
catch (Exception e)
{
LogHelper.Error<content>("Failed to load Xml from file.", e);
DeleteXmlFile();
try
{
DeleteXmlFile();
}
catch
{
// don't make it worse: could be that we failed to read because we cannot
// access the file, in which case we won't be able to delete it either
}
return null;
}
}
+27 -27
View File
@@ -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
@@ -407,8 +408,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));
@@ -444,6 +444,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
@@ -479,7 +480,7 @@ namespace UmbracoExamine
filtered.Add(xml);
}
return new Tuple<long, XElement[]>(totalContent, filtered.ToArray());
return Tuple.Create(filtered.ToArray(), more);
},
i => _contentService.GetById(i));
}
@@ -497,13 +498,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
@@ -527,7 +528,7 @@ namespace UmbracoExamine
content, notPublished).WhereNotNull(), type);
pageIndex++;
} while (currentPageSize == pageSize);
} while (currentPageSize == PageSize);
}
break;
@@ -545,7 +546,8 @@ namespace UmbracoExamine
{
long totalMedia;
var result = _mediaService.GetPagedXmlEntries(path, pIndex, pSize, out totalMedia).ToArray();
return new Tuple<long, XElement[]>(totalMedia, result);
var more = result.Length == pSize;
return Tuple.Create(result, more);
},
i => _mediaService.GetById(i));
@@ -573,39 +575,37 @@ namespace UmbracoExamine
string type,
int parentId,
Func<TContentType[]> getContentTypes,
Func<string, int, int, Tuple<long, XElement[]>> getPagedXmlEntries,
Func<string, int, int, Tuple<XElement[], bool>> getPagedXmlEntries,
Func<int, IContentBase> 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
@@ -626,7 +626,7 @@ namespace UmbracoExamine
AddNodesToIndex(xElements, type);
pageIndex++;
} while (xElements.Length == pageSize);
} while (more);
}
internal static IEnumerable<XElement> GetSerializedContent(
+2 -2
View File
@@ -82,8 +82,8 @@
<AssemblyOriginatorKeyFile>..\Solution Items\TheFARM-Public.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<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.82.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.82\lib\net45\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>
+5 -4
View File
@@ -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<long, XElement[]>(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));
}
@@ -247,7 +248,7 @@ namespace UmbracoExamine
fields.Add("__key", valuesForIndexing);
}
}
return fields;
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Examine" version="0.1.81" targetFramework="net45" />
<package id="Examine" version="0.1.82" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
</packages>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Examine" version="0.1.81" targetFramework="net45" />
<package id="Examine" version="0.1.82" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
@@ -45,8 +45,8 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<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.82.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.82\lib\net45\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>
@@ -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;
}