Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f2c7c1e2c6 | |||
| 9f2c428a7c | |||
| a958f946ef | |||
| 688652fb91 | |||
| d6bc0934ff | |||
| 759c6dfef2 | |||
| 218f523022 | |||
| 50c6fb036a | |||
| bc2115ff0a | |||
| 9eee5c2bc0 | |||
| ed3096642d | |||
| 95508c4fb7 | |||
| 4677faff38 | |||
| 725b3c5eca | |||
| bf6d084f82 | |||
| 08ca75bb35 | |||
| 0512eaa7fd | |||
| e8df5f9eb4 | |||
| c46678c766 |
@@ -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.7, 4.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.0, 3.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.5.12
|
||||
7.5.13
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.5.12")]
|
||||
[assembly: AssemblyInformationalVersion("7.5.12")]
|
||||
[assembly: AssemblyFileVersion("7.5.13")]
|
||||
[assembly: AssemblyInformationalVersion("7.5.13")]
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.5.12");
|
||||
private static readonly Version Version = new Version("7.5.13");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,14 +25,14 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
SiteDomainHelper.AddSite("site1", "domain1.com", "domain1.net", "domain1.org");
|
||||
SiteDomainHelper.AddSite("site2", "domain2.com", "domain2.net", "domain2.org");
|
||||
|
||||
|
||||
var sites = SiteDomainHelper.Sites;
|
||||
|
||||
Assert.AreEqual(2, sites.Count);
|
||||
|
||||
Assert.Contains("site1", sites.Keys);
|
||||
Assert.Contains("site2", sites.Keys);
|
||||
|
||||
|
||||
var domains = sites["site1"];
|
||||
Assert.AreEqual(3, domains.Count());
|
||||
Assert.Contains("domain1.com", domains);
|
||||
@@ -84,7 +84,7 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
Assert.Contains("site2", sites.Keys);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void AddSiteAgain()
|
||||
{
|
||||
@@ -175,15 +175,15 @@ namespace Umbraco.Tests.Routing
|
||||
|
||||
// map methods are not static because we can override them
|
||||
var helper = new SiteDomainHelper();
|
||||
|
||||
|
||||
// current is a site1 uri, domains contain current
|
||||
// so we'll get current
|
||||
//
|
||||
var current = new Uri("http://domain1.com/foo/bar");
|
||||
var output = helper.MapDomain(current, new[]
|
||||
{
|
||||
new DomainAndUri(new UmbracoDomain("domain1.com"), Uri.UriSchemeHttp),
|
||||
new DomainAndUri(new UmbracoDomain("domain2.com"), Uri.UriSchemeHttp),
|
||||
new DomainAndUri(new UmbracoDomain("domain1.com"), Uri.UriSchemeHttp),
|
||||
new DomainAndUri(new UmbracoDomain("domain2.com"), Uri.UriSchemeHttp),
|
||||
}).Uri.ToString();
|
||||
Assert.AreEqual("http://domain1.com/", output);
|
||||
|
||||
@@ -193,7 +193,7 @@ namespace Umbraco.Tests.Routing
|
||||
current = new Uri("http://domain1.com/foo/bar");
|
||||
output = helper.MapDomain(current, new[]
|
||||
{
|
||||
new DomainAndUri(new UmbracoDomain("domain1.net"), Uri.UriSchemeHttp),
|
||||
new DomainAndUri(new UmbracoDomain("domain1.net"), Uri.UriSchemeHttp),
|
||||
new DomainAndUri(new UmbracoDomain("domain2.net"), Uri.UriSchemeHttp)
|
||||
}).Uri.ToString();
|
||||
Assert.AreEqual("http://domain1.net/", output);
|
||||
@@ -205,12 +205,73 @@ namespace Umbraco.Tests.Routing
|
||||
current = new Uri("http://domain1.com/foo/bar");
|
||||
output = helper.MapDomain(current, new[]
|
||||
{
|
||||
new DomainAndUri(new UmbracoDomain("domain2.net"), Uri.UriSchemeHttp),
|
||||
new DomainAndUri(new UmbracoDomain("domain2.net"), Uri.UriSchemeHttp),
|
||||
new DomainAndUri(new UmbracoDomain("domain1.net"), Uri.UriSchemeHttp)
|
||||
}).Uri.ToString();
|
||||
Assert.AreEqual("http://domain1.net/", output);
|
||||
}
|
||||
|
||||
private DomainAndUri[] DomainAndUris(Uri current, IDomain[] domains)
|
||||
{
|
||||
var scheme = current == null ? Uri.UriSchemeHttp : current.Scheme;
|
||||
return domains
|
||||
.Where(d => d.IsWildcard == false)
|
||||
.Select(d => new DomainAndUri(d, scheme))
|
||||
.OrderByDescending(d => d.Uri.ToString())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MapDomainWithScheme()
|
||||
{
|
||||
SiteDomainHelper.AddSite("site1", "domain1.com", "domain1.net", "domain1.org");
|
||||
SiteDomainHelper.AddSite("site2", "domain2.com", "domain2.net", "domain2.org");
|
||||
SiteDomainHelper.AddSite("site3", "domain3.com", "domain3.net", "domain3.org");
|
||||
SiteDomainHelper.AddSite("site4", "https://domain4.com", "https://domain4.net", "https://domain4.org");
|
||||
|
||||
// map methods are not static because we can override them
|
||||
var helper = new SiteDomainHelper();
|
||||
|
||||
// this works, but it's purely by chance / arbitrary
|
||||
// don't use the www in tests here!
|
||||
var current = new Uri("https://www.domain1.com/foo/bar");
|
||||
var domainAndUris = DomainAndUris(current, new []
|
||||
{
|
||||
new UmbracoDomain("domain2.com"),
|
||||
new UmbracoDomain("domain1.com"),
|
||||
});
|
||||
var output = helper.MapDomain(current, domainAndUris).Uri.ToString();
|
||||
Assert.AreEqual("https://domain1.com/", output);
|
||||
|
||||
// will pick it all right
|
||||
current = new Uri("https://domain1.com/foo/bar");
|
||||
domainAndUris = DomainAndUris(current, new[]
|
||||
{
|
||||
new UmbracoDomain("https://domain1.com"),
|
||||
new UmbracoDomain("https://domain2.com")
|
||||
});
|
||||
output = helper.MapDomain(current, domainAndUris).Uri.ToString();
|
||||
Assert.AreEqual("https://domain1.com/", output);
|
||||
|
||||
current = new Uri("https://domain1.com/foo/bar");
|
||||
domainAndUris = DomainAndUris(current, new[]
|
||||
{
|
||||
new UmbracoDomain("https://domain1.com"),
|
||||
new UmbracoDomain("https://domain4.com")
|
||||
});
|
||||
output = helper.MapDomain(current, domainAndUris).Uri.ToString();
|
||||
Assert.AreEqual("https://domain1.com/", output);
|
||||
|
||||
current = new Uri("https://domain4.com/foo/bar");
|
||||
domainAndUris = DomainAndUris(current, new[]
|
||||
{
|
||||
new UmbracoDomain("https://domain1.com"),
|
||||
new UmbracoDomain("https://domain4.com")
|
||||
});
|
||||
output = helper.MapDomain(current, domainAndUris).Uri.ToString();
|
||||
Assert.AreEqual("https://domain4.com/", output);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MapDomains()
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ body {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
width: ~"(calc(~'100%' - ~'80px'))"; // 80px is the fixed left menu for toggling the different browser sizes
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
@@ -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> </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> </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> </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> </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> </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> </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> </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> </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> </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> </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}}
|
||||
|
||||
@@ -350,9 +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>
|
||||
<Private>True</Private>
|
||||
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.7.99, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.7\lib\Umbraco.ModelsBuilder.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UrlRewritingNet.UrlRewriter, Version=2.0.7.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\UrlRewritingNet.UrlRewriter.2.0.7\lib\UrlRewritingNet.UrlRewriter.dll</HintPath>
|
||||
@@ -2423,9 +2422,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7512</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7513</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7512</IISUrl>
|
||||
<IISUrl>http://localhost:7513</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -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.7" targetFramework="net45" />
|
||||
<package id="UrlRewritingNet.UrlRewriter" version="2.0.7" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace UmbracoExamine
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentTypeService _contentTypeService;
|
||||
private readonly EntityXmlSerializer _serializer = new EntityXmlSerializer();
|
||||
private const int PageSize = 2;
|
||||
private const int PageSize = 10000;
|
||||
|
||||
#region Constructors
|
||||
|
||||
|
||||
Reference in New Issue
Block a user