Compare commits
113 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3e8fb11abd | |||
| 5181988a41 | |||
| 5169310258 | |||
| f987640462 | |||
| 55e97dad74 | |||
| d2f3e162f1 | |||
| 7404e20a19 | |||
| 744ff0cf33 | |||
| afd0018dd6 | |||
| c36aec624b | |||
| 1ba86f361a | |||
| e5a21625ea | |||
| efd3d6937a | |||
| 6d46c2204d | |||
| 27b9385df5 | |||
| ea6d81f7ac | |||
| f56bd731b7 | |||
| bee0642417 | |||
| 43abb08e59 | |||
| 17db5709f1 | |||
| 2fc6d9b7df | |||
| e4561851a4 | |||
| c6daf2e111 | |||
| 883366f741 | |||
| cac331adbc | |||
| 18318ecabf | |||
| 6b9ef6df7a | |||
| fcaf78ef29 | |||
| 833b4c552c | |||
| c678b7f6d9 | |||
| e320840a29 | |||
| b664fc5e94 | |||
| b87346bee5 | |||
| 6029306fe9 | |||
| f979792290 | |||
| 5f82fc6e20 | |||
| b1a0ca98ea | |||
| f4f99c2922 | |||
| c1b3da869d | |||
| e39158d5e5 | |||
| ddd9c8ef7d | |||
| 44db4e7a48 | |||
| f44b158c15 | |||
| 1ff66d0c3a | |||
| aba2c2a79e | |||
| 9f62dfc087 | |||
| a21912dc41 | |||
| 733b4a770f | |||
| 2e097b7e46 | |||
| e1b6997ef7 | |||
| b6b7b9f433 | |||
| 8181f88cb0 | |||
| 3a4865ef7d | |||
| 37f6dbfa6b | |||
| 131fea3ba4 | |||
| b0661218a0 | |||
| fb99b101d8 | |||
| 0ce7efc978 | |||
| 3b8a2d7d65 | |||
| 61b9ab5c7b | |||
| cfda04b6ed | |||
| 11bdfbba19 | |||
| 9694831638 | |||
| a20844b55b | |||
| 158e40d7f6 | |||
| 1c4e1db054 | |||
| 3c98d9d2e1 | |||
| 8d14a3ef2c | |||
| 2f3d9c9509 | |||
| 6e8f3b6e13 | |||
| b9cbdbd9a7 | |||
| ebf35356a8 | |||
| f3ba1fa7ed | |||
| 7eca99e249 | |||
| 837bb83d48 | |||
| 054ac78970 | |||
| 5982a868ea | |||
| 69a42e26a9 | |||
| d9ed420ed4 | |||
| 2b3397120f | |||
| 1f41aa7d81 | |||
| dad77fc506 | |||
| 350f5c88c7 | |||
| 928c0dc535 | |||
| cc7a28db65 | |||
| 065e764957 | |||
| 000ba73887 | |||
| 08b81d991b | |||
| 4937f87c0d | |||
| dc67d82671 | |||
| c7d9683fc4 | |||
| ed7675bdcd | |||
| 3c7c6b4ad7 | |||
| 838d7975c9 | |||
| 5af9712d51 | |||
| 579c572dd8 | |||
| bbf4c18825 | |||
| e72758e04a | |||
| 9d373c194d | |||
| 856e123ec2 | |||
| 0b2af6b48f | |||
| 360665c082 | |||
| ff98b5f321 | |||
| 92378095a2 | |||
| daa0741802 | |||
| eaa8ca5fdc | |||
| 73b2d31298 | |||
| 8676a99b3a | |||
| 0b2cfe956d | |||
| e0e9823a03 | |||
| 3a98d63bf1 | |||
| ac65af772a | |||
| a4f83e0125 |
@@ -33,13 +33,13 @@
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.85, 1.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.89, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.5.6, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.8.7, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 3.0.0)" />
|
||||
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
|
||||
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.7, 4.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.8, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web.Config" version="[2.3.1, 3.0.0)" />
|
||||
</dependencies>
|
||||
|
||||
@@ -49,11 +49,9 @@
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.7.4")]
|
||||
[assembly: AssemblyInformationalVersion("7.7.4")]
|
||||
[assembly: AssemblyFileVersion("7.7.8")]
|
||||
[assembly: AssemblyInformationalVersion("7.7.8")]
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -260,7 +261,7 @@ namespace Umbraco.Core
|
||||
/// - http://issues.umbraco.org/issue/U4-5728
|
||||
/// - http://issues.umbraco.org/issue/U4-5391
|
||||
/// </remarks>
|
||||
internal string UmbracoApplicationUrl
|
||||
public string UmbracoApplicationUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -268,9 +269,21 @@ namespace Umbraco.Core
|
||||
return _umbracoApplicationUrl;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the url.
|
||||
/// </summary>
|
||||
public void ResetUmbracoApplicationUrl()
|
||||
{
|
||||
_umbracoApplicationUrl = null;
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
internal string _umbracoApplicationUrl;
|
||||
internal string _umbracoApplicationUrl;
|
||||
|
||||
internal List<string> _umbracoApplicationDomains = new List<string>();
|
||||
|
||||
internal string _umbracoApplicationDeploymentId;
|
||||
|
||||
private Lazy<bool> _configured;
|
||||
internal MainDom MainDom { get; private set; }
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.7.4");
|
||||
private static readonly Version Version = new Version("7.7.8");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -76,260 +76,257 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
if (_events == null)
|
||||
return Enumerable.Empty<IEventDefinition>();
|
||||
|
||||
|
||||
IReadOnlyList<IEventDefinition> events;
|
||||
switch (filter)
|
||||
{
|
||||
case EventDefinitionFilter.All:
|
||||
return FilterSupersededAndUpdateToLatestEntity(_events);
|
||||
events = _events;
|
||||
break;
|
||||
case EventDefinitionFilter.FirstIn:
|
||||
var l1 = new OrderedHashSet<IEventDefinition>();
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l1.Add(e);
|
||||
}
|
||||
return FilterSupersededAndUpdateToLatestEntity(l1);
|
||||
events = l1;
|
||||
break;
|
||||
case EventDefinitionFilter.LastIn:
|
||||
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
|
||||
foreach (var e in _events)
|
||||
{
|
||||
l2.Add(e);
|
||||
}
|
||||
return FilterSupersededAndUpdateToLatestEntity(l2);
|
||||
events = l2;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("filter", filter, null);
|
||||
}
|
||||
|
||||
return FilterSupersededAndUpdateToLatestEntity(events);
|
||||
}
|
||||
|
||||
private class EventDefinitionTypeData
|
||||
|
||||
private class EventDefinitionInfos
|
||||
{
|
||||
public IEventDefinition EventDefinition { get; set; }
|
||||
public Type EventArgType { get; set; }
|
||||
public SupersedeEventAttribute[] SupersedeAttributes { get; set; }
|
||||
public Type[] SupersedeTypes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will iterate over the events (latest first) and filter out any events or entities in event args that are included
|
||||
/// in more recent events that Supersede previous ones. For example, If an Entity has been Saved and then Deleted, we don't want
|
||||
/// to raise the Saved event (well actually we just don't want to include it in the args for that saved event)
|
||||
/// </summary>
|
||||
/// <param name="events"></param>
|
||||
/// <returns></returns>
|
||||
private static IEnumerable<IEventDefinition> FilterSupersededAndUpdateToLatestEntity(IReadOnlyList<IEventDefinition> events)
|
||||
|
||||
// fixme
|
||||
// this is way too convoluted, the superceede attribute is used only on DeleteEventargs to specify
|
||||
// that it superceeds save, publish, move and copy - BUT - publish event args is also used for
|
||||
// unpublishing and should NOT be superceeded - so really it should not be managed at event args
|
||||
// level but at event level
|
||||
//
|
||||
// what we want is:
|
||||
// if an entity is deleted, then all Saved, Moved, Copied, Published events prior to this should
|
||||
// not trigger for the entity - and even though, does it make any sense? making a copy of an entity
|
||||
// should ... trigger?
|
||||
//
|
||||
// not going to refactor it all - we probably want to *always* trigger event but tell people that
|
||||
// due to scopes, they should not expected eg a saved entity to still be around - however, now,
|
||||
// going to write a ugly condition to deal with U4-10764
|
||||
|
||||
// iterates over the events (latest first) and filter out any events or entities in event args that are included
|
||||
// in more recent events that Supersede previous ones. For example, If an Entity has been Saved and then Deleted, we don't want
|
||||
// to raise the Saved event (well actually we just don't want to include it in the args for that saved event)
|
||||
internal static IEnumerable<IEventDefinition> FilterSupersededAndUpdateToLatestEntity(IReadOnlyList<IEventDefinition> events)
|
||||
{
|
||||
//used to keep the 'latest' entity and associated event definition data
|
||||
var allEntities = new List<Tuple<IEntity, EventDefinitionTypeData>>();
|
||||
|
||||
//tracks all CancellableObjectEventArgs instances in the events which is the only type of args we can work with
|
||||
var cancelableArgs = new List<CancellableObjectEventArgs>();
|
||||
// keeps the 'latest' entity and associated event data
|
||||
var entities = new List<Tuple<IEntity, EventDefinitionInfos>>();
|
||||
|
||||
// collects the event definitions
|
||||
// collects the arguments in result, that require their entities to be updated
|
||||
var result = new List<IEventDefinition>();
|
||||
var resultArgs = new List<CancellableObjectEventArgs>();
|
||||
|
||||
//This will eagerly load all of the event arg types and their attributes so we don't have to continuously look this data up
|
||||
var allArgTypesWithAttributes = events.Select(x => x.Args.GetType())
|
||||
// eagerly fetch superceeded arg types for each arg type
|
||||
var argTypeSuperceeding = events.Select(x => x.Args.GetType())
|
||||
.Distinct()
|
||||
.ToDictionary(x => x, x => x.GetCustomAttributes<SupersedeEventAttribute>(false).ToArray());
|
||||
|
||||
//Iterate all events and collect the actual entities in them and relates them to their corresponding EventDefinitionTypeData
|
||||
//we'll process the list in reverse because events are added in the order they are raised and we want to filter out
|
||||
//any entities from event args that are not longer relevant
|
||||
//(i.e. if an item is Deleted after it's Saved, we won't include the item in the Saved args)
|
||||
.ToDictionary(x => x, x => x.GetCustomAttributes<SupersedeEventAttribute>(false).Select(y => y.SupersededEventArgsType).ToArray());
|
||||
|
||||
// iterate over all events and filter
|
||||
//
|
||||
// process the list in reverse, because events are added in the order they are raised and we want to keep
|
||||
// the latest (most recent) entities and filter out what is not relevant anymore (too old), eg if an entity
|
||||
// is Deleted after being Saved, we want to filter out the Saved event
|
||||
for (var index = events.Count - 1; index >= 0; index--)
|
||||
{
|
||||
var eventDefinition = events[index];
|
||||
var def = events[index];
|
||||
|
||||
var argType = eventDefinition.Args.GetType();
|
||||
var attributes = allArgTypesWithAttributes[eventDefinition.Args.GetType()];
|
||||
|
||||
var meta = new EventDefinitionTypeData
|
||||
var infos = new EventDefinitionInfos
|
||||
{
|
||||
EventDefinition = eventDefinition,
|
||||
EventArgType = argType,
|
||||
SupersedeAttributes = attributes
|
||||
EventDefinition = def,
|
||||
SupersedeTypes = argTypeSuperceeding[def.Args.GetType()]
|
||||
};
|
||||
|
||||
var args = eventDefinition.Args as CancellableObjectEventArgs;
|
||||
if (args != null)
|
||||
var args = def.Args as CancellableObjectEventArgs;
|
||||
if (args == null)
|
||||
{
|
||||
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
|
||||
|
||||
if (list == null)
|
||||
// not a cancellable event arg, include event definition in result
|
||||
result.Add(def);
|
||||
}
|
||||
else
|
||||
{
|
||||
// event object can either be a single object or an enumerable of objects
|
||||
// try to get as an enumerable, get null if it's not
|
||||
var eventObjects = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
|
||||
if (eventObjects == null)
|
||||
{
|
||||
//extract the event object
|
||||
var obj = args.EventObject as IEntity;
|
||||
if (obj != null)
|
||||
// single object, cast as an IEntity
|
||||
// if cannot cast, cannot filter, nothing - just include event definition in result
|
||||
var eventEntity = args.EventObject as IEntity;
|
||||
if (eventEntity == null)
|
||||
{
|
||||
//Now check if this entity already exists in other event args that supersede this current event arg type
|
||||
if (IsFiltered(obj, meta, allEntities) == false)
|
||||
{
|
||||
//if it's not filtered we can adde these args to the response
|
||||
cancelableArgs.Add(args);
|
||||
result.Add(eventDefinition);
|
||||
//track the entity
|
||||
allEntities.Add(Tuple.Create(obj, meta));
|
||||
}
|
||||
result.Add(def);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
// look for this entity in superceding event args
|
||||
// found = must be removed (ie not added), else track
|
||||
if (IsSuperceeded(eventEntity, infos, entities) == false)
|
||||
{
|
||||
//Can't retrieve the entity so cant' filter or inspect, just add to the output
|
||||
result.Add(eventDefinition);
|
||||
// track
|
||||
entities.Add(Tuple.Create(eventEntity, infos));
|
||||
|
||||
// track result arguments
|
||||
// include event definition in result
|
||||
resultArgs.Add(args);
|
||||
result.Add(def);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// enumerable of objects
|
||||
var toRemove = new List<IEntity>();
|
||||
foreach (var entity in list)
|
||||
foreach (var eventObject in eventObjects)
|
||||
{
|
||||
//extract the event object
|
||||
var obj = entity as IEntity;
|
||||
if (obj != null)
|
||||
{
|
||||
//Now check if this entity already exists in other event args that supersede this current event arg type
|
||||
if (IsFiltered(obj, meta, allEntities))
|
||||
{
|
||||
//track it to be removed
|
||||
toRemove.Add(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
//track the entity, it's not filtered
|
||||
allEntities.Add(Tuple.Create(obj, meta));
|
||||
}
|
||||
}
|
||||
// extract the event object, cast as an IEntity
|
||||
// if cannot cast, cannot filter, nothing to do - just leave it in the list & continue
|
||||
var eventEntity = eventObject as IEntity;
|
||||
if (eventEntity == null)
|
||||
continue;
|
||||
|
||||
// look for this entity in superceding event args
|
||||
// found = must be removed, else track
|
||||
if (IsSuperceeded(eventEntity, infos, entities))
|
||||
toRemove.Add(eventEntity);
|
||||
else
|
||||
{
|
||||
//we don't need to do anything here, we can't cast to IEntity so we cannot filter, so it will just remain in the list
|
||||
}
|
||||
entities.Add(Tuple.Create(eventEntity, infos));
|
||||
}
|
||||
|
||||
//remove anything that has been filtered
|
||||
// remove superceded entities
|
||||
foreach (var entity in toRemove)
|
||||
{
|
||||
list.Remove(entity);
|
||||
}
|
||||
eventObjects.Remove(entity);
|
||||
|
||||
//track the event and include in the response if there's still entities remaining in the list
|
||||
if (list.Count > 0)
|
||||
// if there are still entities in the list, keep the event definition
|
||||
if (eventObjects.Count > 0)
|
||||
{
|
||||
if (toRemove.Count > 0)
|
||||
{
|
||||
//re-assign if the items have changed
|
||||
args.EventObject = list;
|
||||
// re-assign if changed
|
||||
args.EventObject = eventObjects;
|
||||
}
|
||||
cancelableArgs.Add(args);
|
||||
result.Add(eventDefinition);
|
||||
|
||||
// track result arguments
|
||||
// include event definition in result
|
||||
resultArgs.Add(args);
|
||||
result.Add(def);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//it's not a cancelable event arg so we just include it in the result
|
||||
result.Add(eventDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
|
||||
UpdateToLatestEntities(allEntities, cancelableArgs);
|
||||
// go over all args in result, and update them with the latest instanceof each entity
|
||||
UpdateToLatestEntities(entities, resultArgs);
|
||||
|
||||
//we need to reverse the result since we've been adding by latest added events first!
|
||||
// reverse, since we processed the list in reverse
|
||||
result.Reverse();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void UpdateToLatestEntities(IEnumerable<Tuple<IEntity, EventDefinitionTypeData>> allEntities, IEnumerable<CancellableObjectEventArgs> cancelableArgs)
|
||||
// edits event args to use the latest instance of each entity
|
||||
private static void UpdateToLatestEntities(IEnumerable<Tuple<IEntity, EventDefinitionInfos>> entities, IEnumerable<CancellableObjectEventArgs> args)
|
||||
{
|
||||
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
|
||||
|
||||
// get the latest entities
|
||||
// ordered hash set + keepOldest will keep the latest inserted entity (in case of duplicates)
|
||||
var latestEntities = new OrderedHashSet<IEntity>(keepOldest: true);
|
||||
foreach (var entity in allEntities.OrderByDescending(entity => entity.Item1.UpdateDate))
|
||||
{
|
||||
foreach (var entity in entities.OrderByDescending(entity => entity.Item1.UpdateDate))
|
||||
latestEntities.Add(entity.Item1);
|
||||
}
|
||||
|
||||
foreach (var args in cancelableArgs)
|
||||
foreach (var arg in args)
|
||||
{
|
||||
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
|
||||
if (list == null)
|
||||
// event object can either be a single object or an enumerable of objects
|
||||
// try to get as an enumerable, get null if it's not
|
||||
var eventObjects = TypeHelper.CreateGenericEnumerableFromObject(arg.EventObject);
|
||||
if (eventObjects == null)
|
||||
{
|
||||
//try to find the args entity in the latest entity - based on the equality operators, this will
|
||||
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
|
||||
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, args.EventObject));
|
||||
// single object
|
||||
// look for a more recent entity for that object, and replace if any
|
||||
// works by "equalling" entities ie the more recent one "equals" this one (though different object)
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, arg.EventObject));
|
||||
if (foundEntity != null)
|
||||
{
|
||||
args.EventObject = foundEntity;
|
||||
}
|
||||
arg.EventObject = foundEntity;
|
||||
}
|
||||
else
|
||||
{
|
||||
// enumerable of objects
|
||||
// same as above but for each object
|
||||
var updated = false;
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
for (var i = 0; i < eventObjects.Count; i++)
|
||||
{
|
||||
//try to find the args entity in the latest entity - based on the equality operators, this will
|
||||
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
|
||||
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, list[i]));
|
||||
if (foundEntity != null)
|
||||
{
|
||||
list[i] = foundEntity;
|
||||
updated = true;
|
||||
}
|
||||
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, eventObjects[i]));
|
||||
if (foundEntity == null) continue;
|
||||
eventObjects[i] = foundEntity;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
args.EventObject = list;
|
||||
}
|
||||
arg.EventObject = eventObjects;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will check against all of the processed entity/events (allEntities) to see if this entity already exists in
|
||||
/// event args that supersede the event args being passed in and if so returns true.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="eventDef"></param>
|
||||
/// <param name="allEntities"></param>
|
||||
/// <returns></returns>
|
||||
private static bool IsFiltered(
|
||||
IEntity entity,
|
||||
EventDefinitionTypeData eventDef,
|
||||
List<Tuple<IEntity, EventDefinitionTypeData>> allEntities)
|
||||
// determines if a given entity, appearing in a given event definition, should be filtered out,
|
||||
// considering the entities that have already been visited - an entity is filtered out if it
|
||||
// appears in another even definition, which superceedes this event definition.
|
||||
private static bool IsSuperceeded(IEntity entity, EventDefinitionInfos infos, List<Tuple<IEntity, EventDefinitionInfos>> entities)
|
||||
{
|
||||
var argType = eventDef.EventDefinition.Args.GetType();
|
||||
//var argType = meta.EventArgsType;
|
||||
var argType = infos.EventDefinition.Args.GetType();
|
||||
|
||||
//check if the entity is found in any processed event data that could possible supersede this one
|
||||
var foundByEntity = allEntities
|
||||
.Where(x => x.Item2.SupersedeAttributes.Length > 0
|
||||
//if it's the same arg type than it cannot supersede
|
||||
&& x.Item2.EventArgType != argType
|
||||
&& Equals(x.Item1, entity))
|
||||
// look for other instances of the same entity, coming from an event args that supercedes other event args,
|
||||
// ie is marked with the attribute, and is not this event args (cannot supersede itself)
|
||||
var superceeding = entities
|
||||
.Where(x => x.Item2.SupersedeTypes.Length > 0 // has the attribute
|
||||
&& x.Item2.EventDefinition.Args.GetType() != argType // is not the same
|
||||
&& Equals(x.Item1, entity)) // same entity
|
||||
.ToArray();
|
||||
|
||||
//no args have been processed with this entity so it should not be filtered
|
||||
if (foundByEntity.Length == 0)
|
||||
// first time we see this entity = not filtered
|
||||
if (superceeding.Length == 0)
|
||||
return false;
|
||||
|
||||
// fixme see notes above
|
||||
// delete event args does NOT superceedes 'unpublished' event
|
||||
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "UnPublished")
|
||||
return false;
|
||||
|
||||
// found occurences, need to determine if this event args is superceded
|
||||
if (argType.IsGenericType)
|
||||
{
|
||||
var supercededBy = foundByEntity
|
||||
.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeAttributes.Any(y =>
|
||||
//if the attribute type is a generic type def then compare with the generic type def of the event arg
|
||||
(y.SupersededEventArgsType.IsGenericTypeDefinition && y.SupersededEventArgsType == argType.GetGenericTypeDefinition())
|
||||
//if the attribute type is not a generic type def then compare with the normal type of the event arg
|
||||
|| (y.SupersededEventArgsType.IsGenericTypeDefinition == false && y.SupersededEventArgsType == argType)));
|
||||
// generic, must compare type arguments
|
||||
var supercededBy = superceeding.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeTypes.Any(y =>
|
||||
// superceeding a generic type which has the same generic type definition
|
||||
// fixme no matter the generic type parameters? could be different?
|
||||
y.IsGenericTypeDefinition && y == argType.GetGenericTypeDefinition()
|
||||
// or superceeding a non-generic type which is ... fixme how is this ever possible? argType *is* generic?
|
||||
|| y.IsGenericTypeDefinition == false && y == argType));
|
||||
return supercededBy != null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var supercededBy = foundByEntity
|
||||
.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeAttributes.Any(y =>
|
||||
//since the event arg type is not a generic type, then we just compare type 1:1
|
||||
y.SupersededEventArgsType == argType));
|
||||
// non-generic, can compare types 1:1
|
||||
var supercededBy = superceeding.FirstOrDefault(x =>
|
||||
x.Item2.SupersedeTypes.Any(y => y == argType));
|
||||
return supercededBy != null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using log4net.Appender;
|
||||
using log4net.Util;
|
||||
|
||||
namespace Umbraco.Core.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// This class will do the exact same thing as the RollingFileAppender that comes from log4net
|
||||
/// With the extension, that it is able to do automatic cleanup of the logfiles in the directory where logging happens
|
||||
///
|
||||
/// By specifying the properties MaxLogFileDays and BaseFilePattern, the files will automaticly get deleted when
|
||||
/// the logger is configured(typically when the app starts). To utilize this appender swap out the type of the rollingFile appender
|
||||
/// that ships with Umbraco, to be Umbraco.Core.Logging.RollingFileCleanupAppender, and add the maxLogFileDays and baseFilePattern elements
|
||||
/// to the configuration i.e.:
|
||||
///
|
||||
/// <example>
|
||||
/// <appender name="rollingFile" type="Log4netAwesomeness.CustomRollingFileAppender, Log4netAwesomeness">
|
||||
/// <file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
|
||||
/// <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
|
||||
/// <appendToFile value="true" />
|
||||
/// <rollingStyle value="Date" />
|
||||
/// <maximumFileSize value="5MB" />
|
||||
/// <maxLogFileDays value="5"/>
|
||||
/// <basefilePattern value="UmbracoTraceLog.*.txt.*"/>
|
||||
/// <layout type="log4net.Layout.PatternLayout">
|
||||
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
|
||||
/// </layout>
|
||||
/// <layout type="log4net.Layout.PatternLayout">
|
||||
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
|
||||
/// </layout>
|
||||
/// <encoding value="utf-8" />
|
||||
/// </appender>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
public class RollingFileCleanupAppender : RollingFileAppender
|
||||
{
|
||||
public int MaxLogFileDays { get; set; }
|
||||
public string BaseFilePattern { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This override will delete logs older than the specified amount of days
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="append"></param>
|
||||
protected override void OpenFile(string fileName, bool append)
|
||||
{
|
||||
bool cleanup = true;
|
||||
// Validate settings and input
|
||||
if (MaxLogFileDays <= 0)
|
||||
{
|
||||
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'MaxLogFileDays' needs to be a positive integer, aborting cleanup");
|
||||
cleanup = false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(BaseFilePattern))
|
||||
{
|
||||
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'BaseFilePattern' is empty, aborting cleanup");
|
||||
cleanup = false;
|
||||
}
|
||||
// grab the directory we are logging to, as this is were we will search for older logfiles
|
||||
var logFolder = Path.GetDirectoryName(fileName);
|
||||
if (Directory.Exists(logFolder) == false)
|
||||
{
|
||||
LogLog.Warn(typeof(RollingFileCleanupAppender), string.Format("Directory '{0}' for logfiles does not exist, aborting cleanup", logFolder));
|
||||
cleanup = false;
|
||||
}
|
||||
// If everything is validated, we can do the actual cleanup
|
||||
if (cleanup)
|
||||
{
|
||||
Cleanup(logFolder);
|
||||
}
|
||||
|
||||
base.OpenFile(fileName, append);
|
||||
}
|
||||
|
||||
private void Cleanup(string directoryPath)
|
||||
{
|
||||
// only take files that matches the pattern we are using i.e. UmbracoTraceLog.*.txt.*
|
||||
string[] logFiles = Directory.GetFiles(directoryPath, BaseFilePattern);
|
||||
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Found {0} files that matches the baseFilePattern: '{1}'", logFiles.Length, BaseFilePattern));
|
||||
|
||||
foreach (var logFile in logFiles)
|
||||
{
|
||||
DateTime lastAccessTime = System.IO.File.GetLastWriteTimeUtc(logFile);
|
||||
// take the value from the config file
|
||||
if (lastAccessTime < DateTime.Now.AddDays(-MaxLogFileDays))
|
||||
{
|
||||
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Deleting file {0} as its lastAccessTime is older than {1} days speficied by MaxLogFileDays", logFile, MaxLogFileDays));
|
||||
base.DeleteFile(logFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,7 +188,7 @@ namespace Umbraco.Core.Models
|
||||
Language,
|
||||
|
||||
/// <summary>
|
||||
/// Document
|
||||
/// Document Blueprint
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DocumentBlueprint, typeof(IContent))]
|
||||
[FriendlyName("DocumentBlueprint")]
|
||||
|
||||
@@ -183,17 +183,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
public IEnumerable<IMemberGroup> GetMemberGroupsForMember(string username)
|
||||
{
|
||||
var sql = new Sql()
|
||||
{
|
||||
var sql = new Sql()
|
||||
.Select("un.*")
|
||||
.From("umbracoNode AS un")
|
||||
.InnerJoin("cmsMember2MemberGroup")
|
||||
.On("un.id = cmsMember2MemberGroup.MemberGroup")
|
||||
.LeftJoin("(SELECT umbracoNode.id, cmsMember.LoginName FROM umbracoNode INNER JOIN cmsMember ON umbracoNode.id = cmsMember.nodeId) AS member")
|
||||
.On("member.id = cmsMember2MemberGroup.Member")
|
||||
.Where("un.nodeObjectType=@objectType", new {objectType = NodeObjectTypeId })
|
||||
.Where("member.LoginName=@loginName", new {loginName = username});
|
||||
|
||||
.On("cmsMember2MemberGroup.MemberGroup = un.id")
|
||||
.InnerJoin("cmsMember")
|
||||
.On("cmsMember.nodeId = cmsMember2MemberGroup.Member")
|
||||
.Where("un.nodeObjectType=@objectType", new { objectType = NodeObjectTypeId })
|
||||
.Where("cmsMember.LoginName=@loginName", new { loginName = username });
|
||||
|
||||
return Database.Fetch<NodeDto>(sql)
|
||||
.DistinctBy(dto => dto.NodeId)
|
||||
.Select(x => _modelFactory.BuildEntity(x));
|
||||
|
||||
@@ -191,11 +191,11 @@ ORDER BY colName";
|
||||
|
||||
return new Dictionary<UserState, int>
|
||||
{
|
||||
{UserState.All, result[0].num},
|
||||
{UserState.Active, result[1].num},
|
||||
{UserState.Disabled, result[2].num},
|
||||
{UserState.LockedOut, result[3].num},
|
||||
{UserState.Invited, result[4].num}
|
||||
{UserState.All, (int)result[0].num},
|
||||
{UserState.Active, (int)result[1].num},
|
||||
{UserState.Disabled, (int)result[2].num},
|
||||
{UserState.LockedOut, (int)result[3].num},
|
||||
{UserState.Invited, (int)result[4].num}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -993,8 +993,7 @@ namespace Umbraco.Core.Services
|
||||
FROM umbracoNode
|
||||
JOIN cmsDocument ON umbracoNode.id=cmsDocument.nodeId AND cmsDocument.published=@0
|
||||
WHERE umbracoNode.trashed=@1 AND umbracoNode.id IN (@2)",
|
||||
true, false, ids);
|
||||
Console.WriteLine(sql.SQL);
|
||||
true, false, ids);
|
||||
var x = uow.Database.Fetch<int>(sql);
|
||||
return ids.Length == x.Count;
|
||||
}
|
||||
@@ -2009,6 +2008,96 @@ namespace Umbraco.Core.Services
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sorts a collection of <see cref="IContent"/> objects by updating the SortOrder according
|
||||
/// to the ordering of node Ids passed in.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Using this method will ensure that the Published-state is maintained upon sorting
|
||||
/// so the cache is updated accordingly - as needed.
|
||||
/// </remarks>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="raiseEvents"></param>
|
||||
/// <returns>True if sorting succeeded, otherwise False</returns>
|
||||
public bool Sort(int[] ids, int userId = 0, bool raiseEvents = true)
|
||||
{
|
||||
var shouldBePublished = new List<IContent>();
|
||||
var shouldBeSaved = new List<IContent>();
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x);
|
||||
var items = ids.Select(x => allContent[x]);
|
||||
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var asArray = items.ToArray();
|
||||
var saveEventArgs = new SaveEventArgs<IContent>(asArray);
|
||||
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
|
||||
{
|
||||
uow.Commit();
|
||||
return false;
|
||||
}
|
||||
|
||||
var repository = RepositoryFactory.CreateContentRepository(uow);
|
||||
|
||||
var i = 0;
|
||||
foreach (var content in asArray)
|
||||
{
|
||||
//If the current sort order equals that of the content
|
||||
//we don't need to update it, so just increment the sort order
|
||||
//and continue.
|
||||
if (content.SortOrder == i)
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
content.SortOrder = i;
|
||||
content.WriterId = userId;
|
||||
i++;
|
||||
|
||||
if (content.Published)
|
||||
{
|
||||
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
|
||||
var published = _publishingStrategy.Publish(uow, content, userId).Success;
|
||||
shouldBePublished.Add(content);
|
||||
}
|
||||
else
|
||||
shouldBeSaved.Add(content);
|
||||
|
||||
repository.AddOrUpdate(content);
|
||||
//add or update a preview
|
||||
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
|
||||
}
|
||||
|
||||
foreach (var content in shouldBePublished)
|
||||
{
|
||||
//Create and Save ContentXml DTO
|
||||
repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
|
||||
}
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
saveEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
|
||||
}
|
||||
|
||||
if (shouldBePublished.Any())
|
||||
{
|
||||
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
|
||||
_publishingStrategy.PublishingFinalized(uow, shouldBePublished, false);
|
||||
}
|
||||
|
||||
Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0);
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public IEnumerable<IContent> GetBlueprintsForContentTypes(params int[] documentTypeIds)
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
|
||||
@@ -2749,4 +2838,4 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ namespace Umbraco.Core.Services
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
deleteEventArgs.CanCancel = false;
|
||||
uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs);
|
||||
uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs, "DeletedMediaTypeContainer");
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
@@ -642,7 +642,21 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="raiseEvents"></param>
|
||||
/// <returns>True if sorting succeeded, otherwise False</returns>
|
||||
bool Sort(IEnumerable<IContent> items, int userId = 0, bool raiseEvents = true);
|
||||
bool Sort(IEnumerable<IContent> items, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Sorts a collection of <see cref="IContent"/> objects by updating the SortOrder according
|
||||
/// to the ordering of node Ids passed in.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Using this method will ensure that the Published-state is maintained upon sorting
|
||||
/// so the cache is updated accordingly - as needed.
|
||||
/// </remarks>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="raiseEvents"></param>
|
||||
/// <returns>True if sorting succeeded, otherwise False</returns>
|
||||
bool Sort(int[] ids, int userId = 0, bool raiseEvents = true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent of the current content as an <see cref="IContent"/> item.
|
||||
|
||||
@@ -986,7 +986,11 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="raiseEvents">Optional parameter to raise events.
|
||||
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
|
||||
public void Save(IMember entity, bool raiseEvents = true)
|
||||
{
|
||||
{
|
||||
//trimming username and email to make sure we have no trailing space
|
||||
entity.Username = entity.Username.Trim();
|
||||
entity.Email = entity.Email.Trim();
|
||||
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(entity);
|
||||
|
||||
@@ -228,9 +228,9 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an <see cref="IUser"/>
|
||||
/// Disables an <see cref="IUser"/>
|
||||
/// </summary>
|
||||
/// <param name="membershipUser"><see cref="IUser"/> to Delete</param>
|
||||
/// <param name="membershipUser"><see cref="IUser"/> to disable</param>
|
||||
public void Delete(IUser membershipUser)
|
||||
{
|
||||
//disable
|
||||
@@ -712,7 +712,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="id">Id of the User to retrieve</param>
|
||||
/// <returns><see cref="IProfile"/></returns>
|
||||
public IProfile GetProfileById(int id)
|
||||
{
|
||||
{
|
||||
//This is called a TON. Go get the full user from cache which should already be IProfile
|
||||
var fullUser = GetUserById(id);
|
||||
var asProfile = fullUser as IProfile;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Web;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
|
||||
namespace Umbraco.Core.Sync
|
||||
@@ -46,8 +47,20 @@ namespace Umbraco.Core.Sync
|
||||
// settings: for unit tests only
|
||||
internal static void EnsureApplicationUrl(ApplicationContext appContext, HttpRequestBase request = null, IUmbracoSettingsSection settings = null)
|
||||
{
|
||||
bool newApplicationUrl = false;
|
||||
if (request != null)
|
||||
{
|
||||
var applicationUrl = GetApplicationUrlFromRequest(request);
|
||||
newApplicationUrl = !appContext._umbracoApplicationDomains.Contains(applicationUrl);
|
||||
if (newApplicationUrl)
|
||||
{
|
||||
appContext._umbracoApplicationDomains.Add(applicationUrl);
|
||||
LogHelper.Info(typeof(ApplicationUrlHelper), $"New ApplicationUrl detected: {applicationUrl}");
|
||||
}
|
||||
}
|
||||
|
||||
// if initialized, return
|
||||
if (appContext._umbracoApplicationUrl != null) return;
|
||||
if (appContext._umbracoApplicationUrl != null && !newApplicationUrl) return;
|
||||
|
||||
var logger = appContext.ProfilingLogger.Logger;
|
||||
|
||||
@@ -132,6 +145,12 @@ namespace Umbraco.Core.Sync
|
||||
{
|
||||
var logger = appContext.ProfilingLogger.Logger;
|
||||
|
||||
appContext._umbracoApplicationUrl = GetApplicationUrlFromRequest(request);
|
||||
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + appContext.UmbracoApplicationUrl + " (UmbracoModule request)");
|
||||
}
|
||||
|
||||
private static string GetApplicationUrlFromRequest(HttpRequestBase request)
|
||||
{
|
||||
// if (HTTP and SSL not required) or (HTTPS and SSL required),
|
||||
// use ports from request
|
||||
// otherwise,
|
||||
@@ -147,8 +166,7 @@ namespace Umbraco.Core.Sync
|
||||
var ssl = useSsl ? "s" : ""; // force, whatever the first request
|
||||
var url = "http" + ssl + "://" + request.ServerVariables["SERVER_NAME"] + port + IOHelper.ResolveUrl(SystemDirectories.Umbraco);
|
||||
|
||||
appContext._umbracoApplicationUrl = url.TrimEnd('/');
|
||||
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + appContext.UmbracoApplicationUrl + " (UmbracoModule request)");
|
||||
return url.TrimEnd('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
case UmbracoObjectTypes.Document:
|
||||
return Document;
|
||||
case UmbracoObjectTypes.DocumentBlueprint:
|
||||
return DocumentBluePrint;
|
||||
case UmbracoObjectTypes.Media:
|
||||
return Media;
|
||||
case UmbracoObjectTypes.Member:
|
||||
@@ -161,6 +163,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
case Document:
|
||||
return UmbracoObjectTypes.Document;
|
||||
case DocumentBluePrint:
|
||||
return UmbracoObjectTypes.DocumentBlueprint;
|
||||
case Media:
|
||||
return UmbracoObjectTypes.Media;
|
||||
case Member:
|
||||
|
||||
@@ -39,22 +39,18 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor, Version=2.5.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll</HintPath>
|
||||
@@ -67,11 +63,9 @@
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Owin, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll</HintPath>
|
||||
@@ -87,17 +81,16 @@
|
||||
</Reference>
|
||||
<Reference Include="MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Semver, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\semver.1.1.2\lib\net45\Semver.dll</HintPath>
|
||||
@@ -109,11 +102,9 @@
|
||||
<Reference Include="System.Data.Entity" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.DirectoryServices.AccountManagement" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -366,6 +357,7 @@
|
||||
<Compile Include="HashGenerator.cs" />
|
||||
<Compile Include="IEmailSender.cs" />
|
||||
<Compile Include="IHttpContextAccessor.cs" />
|
||||
<Compile Include="Logging\RollingFileCleanupAppender.cs" />
|
||||
<Compile Include="Models\EntityBase\EntityPath.cs" />
|
||||
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
|
||||
<Compile Include="Models\IUserControl.cs" />
|
||||
|
||||
@@ -40,34 +40,27 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="BenchmarkDotNet, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.0.9.9\lib\net45\BenchmarkDotNet.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Core, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Core.0.9.9\lib\net45\BenchmarkDotNet.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Diagnostics.Windows, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Diagnostics.Windows.0.9.9\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="BenchmarkDotNet.Toolchains.Roslyn, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=1.0.41.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Moq, Version=4.1.1309.919, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll</HintPath>
|
||||
@@ -75,27 +68,22 @@
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Numerics" />
|
||||
<Reference Include="System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
@@ -116,6 +104,7 @@
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="_TraceEventProgrammersGuide.docx" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
|
||||
@@ -132,8 +121,8 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
|
||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
|
||||
<Content Include="TraceEvent.ReadMe.txt" />
|
||||
<Content Include="TraceEvent.ReleaseNotes.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -3,10 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using umbraco.cms.businesslogic;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
|
||||
@@ -99,7 +102,7 @@ namespace Umbraco.Tests.Scoping
|
||||
DoDeleteForContent += OnDoThingFail;
|
||||
DoForTestArgs += OnDoThingFail;
|
||||
DoForTestArgs2 += OnDoThingFail;
|
||||
|
||||
|
||||
var contentType = MockedContentTypes.CreateBasicContentType();
|
||||
|
||||
var content1 = MockedContent.CreateBasicContent(contentType);
|
||||
@@ -114,10 +117,10 @@ namespace Umbraco.Tests.Scoping
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
|
||||
{
|
||||
|
||||
|
||||
//content1 will be filtered from the args
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(new[]{ content1 , content3}));
|
||||
scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs<IContent>(content1));
|
||||
scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs<IContent>(content1), "DoDeleteForContent");
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
|
||||
//this entire event will be filtered
|
||||
scope.Events.Dispatch(DoForTestArgs, this, new TestEventArgs(content1));
|
||||
@@ -141,15 +144,36 @@ namespace Umbraco.Tests.Scoping
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SupersededEvents2()
|
||||
{
|
||||
var contentService = Mock.Of<IContentService>();
|
||||
var content = Mock.Of<IContent>();
|
||||
var l1 = new List<IEventDefinition>
|
||||
{
|
||||
new EventDefinition<IContentService, PublishEventArgs<IContent>>(Test_UnPublished, contentService, new PublishEventArgs<IContent>(new [] { content }), "UnPublished"),
|
||||
new EventDefinition<IContentService, DeleteEventArgs<IContent>>(Test_Deleted, contentService, new DeleteEventArgs<IContent>(new [] { content }), "Deleted")
|
||||
};
|
||||
|
||||
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
|
||||
foreach (var e in l1)
|
||||
l2.Add(e);
|
||||
|
||||
var l3 = ScopeEventDispatcherBase.FilterSupersededAndUpdateToLatestEntity(l2);
|
||||
|
||||
// see U4-10764
|
||||
Assert.AreEqual(2, l3.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will test that when we track events that before we Get the events we normalize all of the
|
||||
/// event entities to be the latest one (most current) found amongst the event so that there is
|
||||
/// event entities to be the latest one (most current) found amongst the event so that there is
|
||||
/// no 'stale' entities in any of the args
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void LatestEntities()
|
||||
{
|
||||
DoSaveForContent += OnDoThingFail;
|
||||
DoSaveForContent += OnDoThingFail;
|
||||
|
||||
var now = DateTime.Now;
|
||||
var contentType = MockedContentTypes.CreateBasicContentType();
|
||||
@@ -165,7 +189,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
|
||||
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
|
||||
{
|
||||
{
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content1));
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
|
||||
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content3));
|
||||
@@ -173,7 +197,7 @@ namespace Umbraco.Tests.Scoping
|
||||
// events have been queued
|
||||
var events = scope.Events.GetEvents(EventDefinitionFilter.All).ToArray();
|
||||
Assert.AreEqual(3, events.Length);
|
||||
|
||||
|
||||
foreach (var t in events)
|
||||
{
|
||||
var args = (SaveEventArgs<IContent>)t.Args;
|
||||
@@ -212,7 +236,7 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
// events have been queued
|
||||
var events = scope.Events.GetEvents(EventDefinitionFilter.FirstIn).ToArray();
|
||||
Assert.AreEqual(1, events.Length);
|
||||
Assert.AreEqual(1, events.Length);
|
||||
Assert.AreEqual(content1, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First());
|
||||
Assert.IsTrue(object.ReferenceEquals(content1, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First()));
|
||||
Assert.AreEqual(content1.UpdateDate, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First().UpdateDate);
|
||||
@@ -350,6 +374,9 @@ namespace Umbraco.Tests.Scoping
|
||||
|
||||
public static event TypedEventHandler<ScopeEventDispatcherTests, SaveEventArgs<decimal>> DoThing3;
|
||||
|
||||
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Test_UnPublished;
|
||||
public static event TypedEventHandler<IContentService, DeleteEventArgs<IContent>> Test_Deleted;
|
||||
|
||||
public class TestEventArgs : CancellableObjectEventArgs
|
||||
{
|
||||
public TestEventArgs(object eventObject) : base(eventObject)
|
||||
|
||||
@@ -62,8 +62,8 @@
|
||||
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.85.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.85\lib\net45\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.89\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>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<packages>
|
||||
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
|
||||
<package id="Castle.Core" version="4.0.0" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.85" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.89" targetFramework="net45" />
|
||||
<package id="log4net" version="2.0.8" targetFramework="net45" />
|
||||
<package id="Log4Net.Async" version="2.0.4" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
|
||||
@@ -31,15 +31,17 @@
|
||||
display: block;
|
||||
padding: 4px;
|
||||
line-height: @baseLineHeight;
|
||||
border: 1px solid #ddd;
|
||||
border: 1px solid @gray-8;
|
||||
.border-radius(@baseBorderRadius);
|
||||
.box-shadow(0 1px 3px rgba(0,0,0,.055));
|
||||
.transition(all .2s ease-in-out);
|
||||
}
|
||||
// Add a hover/focus state for linked versions only
|
||||
a.thumbnail:hover,
|
||||
a.thumbnail:focus {
|
||||
border-color: @linkColor;
|
||||
// Add a hover/focus state for linked versions only.
|
||||
a.thumbnail:hover,
|
||||
a.thumbnail:focus,
|
||||
a div.thumbnail:hover,
|
||||
a div.thumbnail:focus {
|
||||
border-color: @turquoise;
|
||||
.box-shadow(0 1px 4px rgba(0,105,214,.25));
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
"cssnano": "^3.7.6",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-connect": "^5.0.0",
|
||||
"gulp-connect": "5.0.0",
|
||||
"gulp-less": "^3.1.0",
|
||||
"gulp-ngdocs": "^0.3.0",
|
||||
"gulp-open": "^2.0.0",
|
||||
|
||||
@@ -366,6 +366,9 @@ angular.module("umbraco.directives")
|
||||
// element might still be there even after the modal has been hidden.
|
||||
scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
|
||||
tinyMceEditor.destroy()
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@
|
||||
|
||||
@param {string} icon (<code>binding</code>): The node icon.
|
||||
@param {string} name (<code>binding</code>): The node name.
|
||||
@param {boolean} published (<code>binding</code>): The node pusblished state.
|
||||
@param {boolean} published (<code>binding</code>): The node published state.
|
||||
@param {string} description (<code>binding</code>): A short description.
|
||||
@param {boolean} sortable (<code>binding</code>): Will add a move cursor on the node preview. Can used in combination with ui-sortable.
|
||||
@param {boolean} allowRemove (<code>binding</code>): Show/Hide the remove button.
|
||||
|
||||
+12
-1
@@ -1,4 +1,15 @@
|
||||
(function () {
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbPasswordToggle
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<strong>Added in Umbraco v. 7.7.4:</strong> Use this directive to render a password toggle.
|
||||
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// comes from https://codepen.io/jakob-e/pen/eNBQaP
|
||||
|
||||
@@ -1,3 +1,114 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbTable
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<strong>Added in Umbraco v. 7.4:</strong> Use this directive to render a data table.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.TableController as vm">
|
||||
|
||||
<umb-table
|
||||
ng-if="items"
|
||||
items="vm.items"
|
||||
item-properties="vm.options.includeProperties"
|
||||
allow-select-all="vm.allowSelectAll"
|
||||
on-select="vm.selectItem"
|
||||
on-click="vm.clickItem"
|
||||
on-select-all="vm.selectAll"
|
||||
on-selected-all="vm.isSelectedAll"
|
||||
on-sorting-direction="vm.isSortDirection"
|
||||
on-sort="vm.sort">
|
||||
</umb-table>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function Controller() {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.items = [
|
||||
{
|
||||
"icon": "icon-document",
|
||||
"name": "My node 1",
|
||||
"published": true,
|
||||
"description": "A short description of my node",
|
||||
"author": "Author 1"
|
||||
},
|
||||
{
|
||||
"icon": "icon-document",
|
||||
"name": "My node 2",
|
||||
"published": true,
|
||||
"description": "A short description of my node",
|
||||
"author": "Author 2"
|
||||
}
|
||||
];
|
||||
|
||||
vm.options = {
|
||||
includeProperties: [
|
||||
{ alias: "description", header: "Description" },
|
||||
{ alias: "author", header: "Author" }
|
||||
]
|
||||
};
|
||||
|
||||
vm.selectItem = selectItem;
|
||||
vm.clickItem = clickItem;
|
||||
vm.selectAll = selectAll;
|
||||
vm.isSelectedAll = isSelectedAll;
|
||||
vm.isSortDirection = isSortDirection;
|
||||
vm.sort = sort;
|
||||
|
||||
function selectAll($event) {
|
||||
alert("select all");
|
||||
}
|
||||
|
||||
function isSelectedAll() {
|
||||
|
||||
}
|
||||
|
||||
function clickItem(item) {
|
||||
alert("click node");
|
||||
}
|
||||
|
||||
function selectItem(selectedItem, $index, $event) {
|
||||
alert("select node");
|
||||
}
|
||||
|
||||
function isSortDirection(col, direction) {
|
||||
|
||||
}
|
||||
|
||||
function sort(field, allow, isSystem) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("My.TableController", Controller);
|
||||
|
||||
})();
|
||||
</pre>
|
||||
|
||||
@param {string} icon (<code>binding</code>): The node icon.
|
||||
@param {string} name (<code>binding</code>): The node name.
|
||||
@param {string} published (<code>binding</code>): The node published state.
|
||||
@param {function} onSelect (<code>expression</code>): Callback function when the row is selected.
|
||||
@param {function} onClick (<code>expression</code>): Callback function when the "Name" column link is clicked.
|
||||
@param {function} onSelectAll (<code>expression</code>): Callback function when selecting all items.
|
||||
@param {function} onSelectedAll (<code>expression</code>): Callback function when all items are selected.
|
||||
@param {function} onSortingDirection (<code>expression</code>): Callback function when sorting direction is changed.
|
||||
@param {function} onSort (<code>expression</code>): Callback function when sorting items.
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
@@ -242,8 +242,8 @@
|
||||
var propGroups = _.find(genericTab.properties, function (item) {
|
||||
return item.alias === "_umb_membergroup";
|
||||
});
|
||||
saveModel.email = propEmail.value;
|
||||
saveModel.username = propLogin.value;
|
||||
saveModel.email = propEmail.value.trim();
|
||||
saveModel.username = propLogin.value.trim();
|
||||
|
||||
saveModel.password = this.formatChangePasswordModel(propPass.value);
|
||||
|
||||
|
||||
@@ -535,7 +535,7 @@
|
||||
color: @gray-3;
|
||||
}
|
||||
|
||||
.umb-grid .umb-cell-rte textarea {
|
||||
.umb-grid .umb-cell-rte textarea.mceNoEditor {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
.umb-node-preview__content {
|
||||
flex: 1 1 auto;
|
||||
margin-right: 25px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.umb-node-preview__name {
|
||||
@@ -50,6 +51,13 @@
|
||||
color: @gray-3;
|
||||
}
|
||||
|
||||
.umb-node-preview__name,
|
||||
.umb-node-preview__description {
|
||||
/*text-overflow: ellipsis;
|
||||
overflow: hidden;*/
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.umb-node-preview__actions {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
|
||||
@@ -29,12 +29,12 @@
|
||||
padding: 15px 10px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
border: 2px solid transparent;
|
||||
border: 1px solid @gray-8;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.umb-healthcheck-group:hover {
|
||||
border: 2px solid @turquoise;
|
||||
border: 1px solid @turquoise;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +281,12 @@ ul.color-picker li a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__wrapper {
|
||||
width: 120px;
|
||||
height: 114px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__actions {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
@@ -308,6 +314,7 @@ ul.color-picker li a {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-left: 5px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-sortable-thumbnails .umb-sortable-thumbnails__action.-red {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<umb-control-group label="@general_url">
|
||||
<input id="url" class="umb-editor input-block-level" type="text" style="margin-bottom: 10px;" ng-model="model.embed.url" ng-keyup="$event.keyCode == 13 ? vm.showPreview() : null" required />
|
||||
<input type="button" ng-click="vm.showPreview()" class="btn" localize="value" value="@general_retrieve" />
|
||||
<input type="button" ng-click="vm.showPreview()" class="btn" value="@general_retrieve" localize="value" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group>
|
||||
@@ -12,15 +12,15 @@
|
||||
|
||||
<div ng-show="model.embed.supportsDimensions">
|
||||
<umb-control-group label="@general_width">
|
||||
<input type="text" ng-model="model.embed.width" on-blur="vm.changeSize('width')" />
|
||||
<input type="number" pattern="[0-9]*" min="0" ng-model="model.embed.width" on-blur="vm.changeSize('width')" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@general_height">
|
||||
<input type="text" ng-model="model.embed.height" on-blur="vm.changeSize('height')" />
|
||||
<input type="number" pattern="[0-9]*" min="0" ng-model="model.embed.height" on-blur="vm.changeSize('height')" />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@general_constrain">
|
||||
<input id="constrain" type="checkbox" ng-model="model.embed.constrain" />
|
||||
<input id="constrain" type="checkbox" ng-model="model.embed.constrain" />
|
||||
</umb-control-group>
|
||||
</div>
|
||||
|
||||
|
||||
+7
-9
@@ -1,5 +1,5 @@
|
||||
<h3>Hours of Umbraco training videos are only a click away</h3>
|
||||
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit <a class="btn-link -underline" href="http://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos</p>
|
||||
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco, then visit <a class="btn-link -underline" href="http://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos.</p>
|
||||
|
||||
<div class="row-fluid"
|
||||
ng-init="init('http://umbraco.tv/videos/developer/chapterrss?sort=no')"
|
||||
@@ -7,14 +7,12 @@
|
||||
|
||||
<ul class="thumbnails" >
|
||||
<li class="span2" ng-repeat="video in videos">
|
||||
<div class="thumbnail" style="margin-right: 20px; padding: 20px;">
|
||||
<a class="btn-link -underline" target="_blank" href="{{video.link}}" title="{{video.title}}">
|
||||
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
|
||||
</a>
|
||||
<a target="_blank" href="{{video.link}}" title="{{video.title}}">
|
||||
<div style="font-weight: bold; text-align: center; margin: 20px 0 0;">{{video.title}}</div>
|
||||
</a>
|
||||
</div>
|
||||
<a class="btn-link" target="_blank" href="{{video.link}}" title="{{video.title}}">
|
||||
<div class="thumbnail" style="margin-right: 20px; padding: 20px;">
|
||||
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
|
||||
<div style="font-weight: bold; text-align: center; margin: 20px 0 0;">{{video.title}}</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
<umb-overlay
|
||||
ng-if="vm.childNodeSelectorOverlay.show"
|
||||
model="vm.childNodeSelectorOverlay"
|
||||
position="center"
|
||||
position="target"
|
||||
view="vm.childNodeSelectorOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
function imageFilePickerController($scope) {
|
||||
|
||||
$scope.pick = function() {
|
||||
$scope.mediaPickerDialog = {};
|
||||
$scope.mediaPickerDialog.view = "mediapicker";
|
||||
$scope.mediaPickerDialog.show = true;
|
||||
|
||||
$scope.mediaPickerDialog.submit = function(model) {
|
||||
$scope.model.value = model.selectedImages[0].image;
|
||||
$scope.mediaPickerDialog.show = false;
|
||||
$scope.mediaPickerDialog = null;
|
||||
$scope.add = function() {
|
||||
$scope.mediaPickerOverlay = {
|
||||
view: "mediapicker",
|
||||
disableFolderSelect: true,
|
||||
onlyImages: true,
|
||||
show: true,
|
||||
submit: function (model) {
|
||||
$scope.model.value = model.selectedImages[0].image;
|
||||
$scope.mediaPickerOverlay.show = false;
|
||||
$scope.mediaPickerOverlay = null;
|
||||
},
|
||||
close: function () {
|
||||
$scope.mediaPickerOverlay.show = false;
|
||||
$scope.mediaPickerOverlay = null;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
$scope.mediaPickerDialog.close = function(oldModel) {
|
||||
$scope.mediaPickerDialog.show = false;
|
||||
$scope.mediaPickerDialog = null;
|
||||
};
|
||||
$scope.remove = function () {
|
||||
$scope.model.value = null;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
<div ng-controller="Umbraco.PrevalueEditors.ImageFilePickerController" class="umb-editor umb-mediapicker">
|
||||
<ul class="umb-sortable-thumbnails">
|
||||
<li>
|
||||
<img ng-src="{{model.value}}" alt="" ng-show="model.value">
|
||||
<a href class="picked-image" ng-click="model.value = null" ng-show="model.value"><i class="icon icon-delete"></i></a>
|
||||
|
||||
<ul class="umb-sortable-thumbnails" ng-if="model.value">
|
||||
<li class="umb-sortable-thumbnails__wrapper">
|
||||
<img ng-src="{{model.value}}" alt="">
|
||||
|
||||
<div class="umb-sortable-thumbnails__actions">
|
||||
<!--<a class="umb-sortable-thumbnails__action" href="" ng-click="goToItem(image)">
|
||||
<i class="icon icon-edit"></i>
|
||||
</a>-->
|
||||
<a class="umb-sortable-thumbnails__action -red" href="" ng-click="remove()">
|
||||
<i class="icon icon-delete"></i>
|
||||
</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<a href ng-click="pick()" class="umb-mediapicker add-link" ng-hide="model.value">
|
||||
<a href="#" class="add-link" ng-click="add()" ng-class="{'add-link-square': !model.value }" ng-hide="model.value" prevent-default>
|
||||
<i class="icon icon-add large"></i>
|
||||
</a>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="mediaPickerDialog.show"
|
||||
model="mediaPickerDialog"
|
||||
view="mediaPickerDialog.view"
|
||||
ng-if="mediaPickerOverlay.show"
|
||||
model="mediaPickerOverlay"
|
||||
view="mediaPickerOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
|
||||
@@ -640,16 +640,16 @@ angular.module("umbraco")
|
||||
var clear = true;
|
||||
|
||||
//settings indicator shortcut
|
||||
if ( ($scope.model.config.items.config && $scope.model.config.items.config.length > 0) || ($scope.model.config.items.styles && $scope.model.config.items.styles.length > 0)) {
|
||||
if (($scope.model.config.items.config && $scope.model.config.items.config.length > 0) || ($scope.model.config.items.styles && $scope.model.config.items.styles.length > 0)) {
|
||||
$scope.hasSettings = true;
|
||||
}
|
||||
|
||||
//ensure the grid has a column value set,
|
||||
//if nothing is found, set it to 12
|
||||
if ($scope.model.config.items.columns && angular.isString($scope.model.config.items.columns)) {
|
||||
$scope.model.config.items.columns = parseInt($scope.model.config.items.columns);
|
||||
} else {
|
||||
if (!$scope.model.config.items.columns){
|
||||
$scope.model.config.items.columns = 12;
|
||||
} else if (angular.isString($scope.model.config.items.columns)) {
|
||||
$scope.model.config.items.columns = parseInt($scope.model.config.items.columns);
|
||||
}
|
||||
|
||||
if ($scope.model.value && $scope.model.value.sections && $scope.model.value.sections.length > 0 && $scope.model.value.sections[0].rows && $scope.model.value.sections[0].rows.length > 0) {
|
||||
|
||||
@@ -299,7 +299,7 @@
|
||||
ng-if="editorOverlay.show"
|
||||
model="editorOverlay"
|
||||
view="editorOverlay.view"
|
||||
position="center">
|
||||
position="target">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
|
||||
+2
@@ -19,6 +19,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
$scope.images = [];
|
||||
$scope.ids = [];
|
||||
|
||||
$scope.isMultiPicker = multiPicker;
|
||||
|
||||
if ($scope.model.value) {
|
||||
var ids = $scope.model.value.split(',');
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
<p ng-if="(images|filter:{trashed:true}).length == 1"><localize key="mediaPicker_pickedTrashedItem"></localize></p>
|
||||
<p ng-if="(images|filter:{trashed:true}).length > 1"><localize key="mediaPicker_pickedTrashedItems"></localize></p>
|
||||
|
||||
|
||||
<div class="flex error">
|
||||
<ul ui-sortable="sortableOptions" ng-model="images" class="umb-sortable-thumbnails">
|
||||
<li style="width: 120px; height: 100px; overflow: hidden;" ng-repeat="image in images">
|
||||
<li class="umb-sortable-thumbnails__wrapper" ng-repeat="image in images track by $index">
|
||||
|
||||
<!-- IMAGE -->
|
||||
<img ng-class="{'trashed': image.trashed}" ng-src="{{image.thumbnail}}" alt="" ng-show="image.thumbnail" title="{{image.trashed ? 'Trashed: ' + image.name : image.name}}" />
|
||||
@@ -30,11 +30,12 @@
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
<li style="border: none;">
|
||||
<a href="#" class="add-link" ng-click="add()" ng-class="{'add-link-square': (images.length === 0 || isMultiPicker)}" ng-if="showAdd()" prevent-default>
|
||||
<i class="icon icon-add large"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a href="#" class="add-link" ng-click="add()" ng-class="{'add-link-square': images.length === 0}" ng-if="showAdd()" prevent-default>
|
||||
<i class="icon icon-add large"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<umb-overlay
|
||||
|
||||
@@ -374,6 +374,9 @@ angular.module("umbraco")
|
||||
// element might still be there even after the modal has been hidden.
|
||||
$scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
|
||||
tinyMceEditor.destroy()
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -127,11 +127,10 @@
|
||||
<Reference Include="dotless.Core, Version=1.5.2.0, Culture=neutral, PublicKeyToken=96b446c9e63eae34, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\dotless.1.5.2\lib\dotless.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.85.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.85\lib\net45\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ImageProcessor, Version=2.5.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
@@ -144,7 +143,6 @@
|
||||
<HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Core">
|
||||
@@ -335,8 +333,8 @@
|
||||
<Name>umbraco.providers</Name>
|
||||
</ProjectReference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<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 Include="Umbraco.ModelsBuilder, Version=3.0.8.100, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.8\lib\Umbraco.ModelsBuilder.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -1026,9 +1024,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7740</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7780</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7740</IISUrl>
|
||||
<IISUrl>http://localhost:7780</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -422,7 +422,7 @@
|
||||
<key alias="showPageOnSend">Hvilken side skal vises etter at skjemaet er sendt</key>
|
||||
<key alias="size">Størrelse</key>
|
||||
<key alias="sort">Sorter</key>
|
||||
<key alias="submit">Submit</key> <!-- TODO: Translate this -->
|
||||
<key alias="submit">Send</key>
|
||||
<key alias="type">Type</key>
|
||||
<key alias="typeToSearch">Søk...</key>
|
||||
<key alias="up">Opp</key>
|
||||
@@ -439,6 +439,17 @@
|
||||
<key alias="yes">Ja</key>
|
||||
<key alias="folder">Mappe</key>
|
||||
<key alias="searchResults">Søkeresultater</key>
|
||||
<key alias="reorder">Sorter</key>
|
||||
<key alias="reorderDone">Avslutt sortering</key>
|
||||
<key alias="preview">Eksempel</key>
|
||||
<key alias="changePassword">Bytt passord</key>
|
||||
<key alias="to">til</key>
|
||||
<key alias="listView">Listevisning</key>
|
||||
<key alias="saving">Lagrer...</key>
|
||||
<key alias="current">nåværende</key>
|
||||
<key alias="embed">Innbygging</key>
|
||||
<key alias="retrieve">Hent</key>
|
||||
<key alias="selected">valgt</key>
|
||||
</area>
|
||||
<area alias="graphicheadline">
|
||||
<key alias="backgroundcolor">Bakgrunnsfarge</key>
|
||||
|
||||
@@ -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.5.2" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.85" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.89" targetFramework="net45" />
|
||||
<package id="ImageProcessor" version="2.5.6" targetFramework="net45" />
|
||||
<package id="ImageProcessor.Web" version="4.8.7" targetFramework="net45" />
|
||||
<package id="ImageProcessor.Web.Config" version="2.3.1" targetFramework="net45" />
|
||||
@@ -37,5 +37,5 @@
|
||||
<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.7" targetFramework="net45" />
|
||||
<package id="Umbraco.ModelsBuilder" version="3.0.8" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -586,7 +586,6 @@
|
||||
<key alias="sort">Sortér</key>
|
||||
<key alias="status">Status</key>
|
||||
<key alias="submit">Indsend</key>
|
||||
<!-- TODO: Translate this -->
|
||||
<key alias="type">Type</key>
|
||||
<key alias="typeToSearch">Skriv for at søge...</key>
|
||||
<key alias="up">Op</key>
|
||||
@@ -612,6 +611,7 @@
|
||||
<key alias="saving">Gemmer...</key>
|
||||
<key alias="current">nuværende</key>
|
||||
<key alias="embed">Indlejring</key>
|
||||
<key alias="retrieve">Hent</key>
|
||||
<key alias="selected">valgt</key>
|
||||
</area>
|
||||
|
||||
|
||||
@@ -637,6 +637,7 @@
|
||||
<key alias="saving">Saving...</key>
|
||||
<key alias="current">current</key>
|
||||
<key alias="embed">Embed</key>
|
||||
<key alias="retrieve">Retrieve</key>
|
||||
<key alias="selected">selected</key>
|
||||
</area>
|
||||
|
||||
|
||||
@@ -637,6 +637,7 @@
|
||||
<key alias="saving">Saving...</key>
|
||||
<key alias="current">current</key>
|
||||
<key alias="embed">Embed</key>
|
||||
<key alias="retrieve">Retrieve</key>
|
||||
<key alias="selected">selected</key>
|
||||
</area>
|
||||
<area alias="colors">
|
||||
|
||||
@@ -32,11 +32,6 @@
|
||||
<key alias="sort">מיין</key>
|
||||
<key alias="translate">תרגם</key>
|
||||
<key alias="update">עדכן</key>
|
||||
<key alias="DeleteCMSImportAction">מחק</key>
|
||||
<key alias="ExecuteCMSImportWizardAction">בצע</key>
|
||||
<key alias="ScheduleCMSImportWizardAction">תזמן</key>
|
||||
<key alias="StartCMSImportWizardAction">ייבא נתונים</key>
|
||||
<key alias="StartCMSImportChildDefinitionAction">צור הגדרות ילדים</key>
|
||||
<key alias="LastRunInfoAction">יומן משימות מתוזמנות</key>
|
||||
</area>
|
||||
<area alias="assignDomain">
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
<key alias="email">Email</key>
|
||||
<key alias="error">Fout</key>
|
||||
<key alias="findDocument">Vind</key>
|
||||
<key alias="height">Hogte</key>
|
||||
<key alias="height">Hoogte</key>
|
||||
<key alias="help">Help</key>
|
||||
<key alias="icon">Icoon</key>
|
||||
<key alias="import">Import</key>
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
<key alias="copy">Kopiuj</key>
|
||||
<key alias="create">Utwórz</key>
|
||||
<key alias="createPackage">Stwórz zbiór</key>
|
||||
<key alias="createGroup">Stwórz grupę</key>
|
||||
<key alias="delete">Usuń</key>
|
||||
<key alias="disable">Deaktywuj</key>
|
||||
<key alias="emptyTrashcan">Opróżnij kosz</key>
|
||||
<key alias="enable">Aktywuj</key>
|
||||
<key alias="exportDocumentType">Eksportuj typ dokumentu</key>
|
||||
<key alias="importDocumentType">Importuj typ dokumentu</key>
|
||||
<key alias="importPackage">Importuj zbiór</key>
|
||||
@@ -27,16 +29,49 @@
|
||||
<key alias="unpublish">Cofnij publikację</key>
|
||||
<key alias="refreshNode">Odśwież węzeł</key>
|
||||
<key alias="republish">Opublikuj ponownie całą stronę</key>
|
||||
<key alias="rename" version="7.3.0">Zmień nazwę</key>
|
||||
<key alias="restore" version="7.3.0">Przywróć</key>
|
||||
<key alias="SetPermissionsForThePage">Ustaw uprawnienia dla strony %0%</key>
|
||||
<key alias="chooseWhereToMove">Wybierz dokąd przenieść</key>
|
||||
<key alias="toInTheTreeStructureBelow">W strukturze drzewa poniżej</key>
|
||||
<key alias="rights">Uprawnienia</key>
|
||||
<key alias="rollback">Cofnij</key>
|
||||
<key alias="sendtopublish">Wyślij do publikacji</key>
|
||||
<key alias="sendToTranslate">Wyślij do tłumaczenia</key>
|
||||
<key alias="setGroup">Ustaw grupę</key>
|
||||
<key alias="sort">Sortuj</key>
|
||||
<key alias="translate">Przetłumacz</key>
|
||||
<key alias="update">Aktualizuj</key>
|
||||
<key alias="setPermissions">Ustaw uprawnienia</key>
|
||||
<key alias="unlock">Odblokuj</key>
|
||||
<key alias="createblueprint">Stwórz Szablon Zawartości</key>
|
||||
</area>
|
||||
<area alias="actionCategories">
|
||||
<key alias="content">Zawartość</key>
|
||||
<key alias="administration">Administracja</key>
|
||||
<key alias="structure">Struktura</key>
|
||||
<key alias="other">Inne</key>
|
||||
</area>
|
||||
<area alias="actionDescriptions">
|
||||
<key alias="assignDomain">Zezwól na dostęp do przydzielenia języka i hostów</key>
|
||||
<key alias="auditTrail">Zezwól na dostęp do wglądu w historię logów węzła</key>
|
||||
<key alias="browse">Zezwól na dostęp do widoku węzła</key>
|
||||
<key alias="changeDocType">Zezwól na dostęp do zmiany typu dokumentu dla węzła</key>
|
||||
<key alias="copy">Zezwól na dostęp do skopiowania węzła</key>
|
||||
<key alias="create">Zezwól na dostęp do stworzenia węzłów</key>
|
||||
<key alias="delete">Zezwól na dostęp do usunięcia węzłóws</key>
|
||||
<key alias="move">Zezwól na dostęp do przeniesienia węzła</key>
|
||||
<key alias="protect">Zezwól na dostęp do ustawienia i zmiany publicznego dostępu węzła</key>
|
||||
<key alias="publish">Zezwól na dostęp do publikacji węzła</key>
|
||||
<key alias="rights">Zezwól na dostęp do zmiany uprawnień węzła</key>
|
||||
<key alias="rollback">Zezwól na dostęp do cofnięcia węzła do poprzedniego stanu</key>
|
||||
<key alias="sendtopublish">Zezwól na dostęp do wysłania węzła do akceptacji przed publikacją</key>
|
||||
<key alias="sendToTranslate">Zezwól na dostęp do wysłania węzła do tłumaczenia</key>
|
||||
<key alias="sort">Zezwól na dostęp do zmiany kolejności sortowania węzłów</key>
|
||||
<key alias="translate">Zezwól na dostęp do tłumaczenia węzła</key>
|
||||
<key alias="update">Zezwól na dostęp do zapisania węzła</key>
|
||||
<key alias="createblueprint">Zezwól na dostęp do utworzenia Szablonu Zawartości</key>
|
||||
</area>
|
||||
<area alias="assignDomain">
|
||||
<key alias="permissionDenied">Brak odpowiednich uprawnień</key>
|
||||
<key alias="addNew">Dodaj nową domenę</key>
|
||||
@@ -50,14 +85,18 @@
|
||||
<key alias="domainDeleted">Domena '%0%' została skasowana</key>
|
||||
<key alias="domainExists">Domena '%0%' jest aktualnie przypisana</key>
|
||||
<key alias="domainUpdated">Domena '%0%' została zaktualizowana</key>
|
||||
<key alias="domainHelp"><![CDATA[Poprawne domeny to: "example.com", "www.example.com", "example.com:8080" lub
|
||||
"https://www.example.com/". Wspierane są jednopoziomowe ścieżki domen, np. "example.com/en" jednakże powinno się ich unikać.
|
||||
Preferowane jest użycie powyższych ustawień języka.]]></key>
|
||||
<key alias="orEdit">Edycja aktualnych domen</key>
|
||||
<key alias="orEdit">Edytuj Aktualne Domeny</key>
|
||||
<key alias="domainHelp">
|
||||
<![CDATA[Poprawne domeny to: "example.com", "www.example.com", "example.com:8080" lub
|
||||
"https://www.example.com/". Wspierane są jednopoziomowe ścieżki domen, np. "example.com/en" jednakże powinno się ich unikać.
|
||||
Preferowane jest użycie powyższych ustawień języka.]]>
|
||||
</key>
|
||||
<key alias="inherit">Odziedziczona</key>
|
||||
<key alias="setLanguage">Język</key>
|
||||
<key alias="setLanguageHelp"><![CDATA[Wybierz język dla węzła,<br /> lub wybierz dziedziczenie języka z węzła rodzica. Zostanie to zastosowane<br />
|
||||
także do obecnego węzła, o ile poniższa domena również do niego należy.]]></key>
|
||||
<key alias="setLanguageHelp">
|
||||
<![CDATA[Wybierz język dla węzła,<br /> lub wybierz dziedziczenie języka z węzła rodzica. Zostanie to zastosowane<br />
|
||||
także do obecnego węzła, o ile poniższa domena również do niego należy.]]>
|
||||
</key>
|
||||
<key alias="setDomains">Domeny</key>
|
||||
</area>
|
||||
<area alias="auditTrails">
|
||||
@@ -96,6 +135,7 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="styleShow">Pokaż style</key>
|
||||
<key alias="tableInsert">Wstaw tabelę</key>
|
||||
<key alias="generateModels">Wygeneruj modele</key>
|
||||
<key alias="saveAndGenerateModels">Zapisz i wygeneruj modele</key>
|
||||
<key alias="undo">Cofnij</key>
|
||||
<key alias="redo">Powtórz</key>
|
||||
</area>
|
||||
@@ -139,6 +179,8 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="lastPublished">Opublikowane</key>
|
||||
<key alias="noItemsToShow">Nie ma żadnych elementów do wyświetlenia</key>
|
||||
<key alias="listViewNoItems" version="7.1.5">Nie ma żadnych elementów do wyświetlenia w liście.</key>
|
||||
<key alias="listViewNoContent">Nie dodano żadnej zawartości</key>
|
||||
<key alias="listViewNoMembers">Nie dodano żadnych członków</key>
|
||||
<key alias="mediatype">Typ mediów</key>
|
||||
<key alias="mediaLinks">Link do elementu(ów) mediów</key>
|
||||
<key alias="membergroup">Członek grupy</key>
|
||||
@@ -173,16 +215,30 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="target" version="7.0">Cel</key>
|
||||
<key alias="scheduledPublishServerTime">Oznacza to następującą godzinę na serwerze:</key>
|
||||
<key alias="scheduledPublishDocumentation"><![CDATA[<a href="https://our.umbraco.org/documentation/Getting-Started/Data/Scheduled-Publishing/#timezones" target="_blank">Co to oznacza?</a>]]></key>
|
||||
<key alias="nestedContentDeleteItem">Czy na pewno chcesz usunąć ten element?</key>
|
||||
<key alias="nestedContentEditorNotSupported">Właściwość %0% używa edytora %1%, który nie jest wspierany przez Nested Content.</key>
|
||||
<key alias="addTextBox">Dodaj kolejne pole tekstowe</key>
|
||||
<key alias="removeTextBox">Usuń te pole tekstowe</key>
|
||||
<key alias="contentRoot">Korzeń zawartości</key>
|
||||
</area>
|
||||
<area alias="blueprints">
|
||||
<key alias="createBlueprintFrom">Stwórz nowy Szablon Zawartości z '%0%'</key>
|
||||
<key alias="blankBlueprint">Pusty</key>
|
||||
<key alias="selectBlueprint">Wybierz Szablon Zawartości</key>
|
||||
<key alias="createdBlueprintHeading">Szablon Zawartości został stworzony</key>
|
||||
<key alias="createdBlueprintMessage">Szablon Zawartości został stworzony z '%0%'</key>
|
||||
<key alias="duplicateBlueprintMessage">Szablon Zawartości o tej samej nazwie już istnieje</key>
|
||||
<key alias="blueprintDescription">Szablon Zawartości to predefiniowana zawartość, którą edytor może wybrać, aby użyć jej jako podstawę do stworzenia nowej zawartości</key>
|
||||
</area>
|
||||
<area alias="media">
|
||||
<key alias="clickToUpload">Kliknij, aby załadować plik</key>
|
||||
<key alias="dropFilesHere">Przerzuć swoje pliki tutaj...</key>
|
||||
<key alias="urls">Link do mediów</key>
|
||||
<key alias="urls">Link do mediów</key>
|
||||
<key alias="orClickHereToUpload">lub kliknij tutaj, aby wybrać pliki</key>
|
||||
<key alias="onlyAllowedFiles">Jedyne dozwolone typy plików to</key>
|
||||
<key alias="disallowedFileType">Nie można załadować pliku, typ pliku nie jest akceptowany</key>
|
||||
<key alias="maxFileSize">Maksymalny rozmiar pliku to</key>
|
||||
<key alias="mediaRoot">Korzeń mediów</key>
|
||||
</area>
|
||||
<area alias="member">
|
||||
<key alias="createNewMember">Stwórz nowego członka</key>
|
||||
@@ -191,6 +247,7 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<area alias="create">
|
||||
<key alias="chooseNode">Gdzie chcesz stworzyć nowy %0%?</key>
|
||||
<key alias="createUnder">Utwórz w</key>
|
||||
<key alias="createContentBlueprint">Wybierz typ dokumentu, dla którego chcesz stworzyć szablon zawartości</key>
|
||||
<key alias="updateData">Wybierz rodzaj oraz tytuł</key>
|
||||
<key alias="noDocumentTypes" version="7.0"><![CDATA[Brak dostępnych dozwolonych typów dokumentów. Należy włączyć je w ustawieniach sekcji pod <strong>"typy dokumentów"</strong>.]]></key>
|
||||
<key alias="noMediaTypes" version="7.0"><![CDATA[Brak dostępnych dozwolonych typów mediów. Należy włączyć je w ustawieniach sekcji pod <strong>"typy mediów"</strong>.]]></key>
|
||||
@@ -249,6 +306,8 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="copiedItemOfItems">Skopiowano %0% z %1% elementów</key>
|
||||
</area>
|
||||
<area alias="defaultdialogs">
|
||||
<key alias="nodeNameLinkPicker">Tytuł linku</key>
|
||||
<key alias="urlLinkPicker">Link</key>
|
||||
<key alias="anchorInsert">Nazwa</key>
|
||||
<key alias="assignDomain">Zarządzaj nazwami hostów</key>
|
||||
<key alias="closeThisWindow">Zamknij to okno</key>
|
||||
@@ -276,6 +335,9 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="macroDoesNotHaveProperties">To makro nie posiada żadnych właściwości, które można edytować</key>
|
||||
<key alias="paste">Wklej</key>
|
||||
<key alias="permissionsEdit">Edytuj Uprawnienia dla</key>
|
||||
<key alias="permissionsSet">Ustaw uprawnienia dla</key>
|
||||
<key alias="permissionsSetForGroup">Ustaw uprawnienia dla %0% dla grupy użytkownika %1%</key>
|
||||
<key alias="permissionsHelp">Wybierz grupy użytkowników, dla których chcesz ustawić uprawnienia</key>
|
||||
<key alias="recycleBinDeleting">Zawartość kosza jest teraz usuwana. Proszę nie zamykać tego okna do momentu zakończenia procesu.</key>
|
||||
<key alias="recycleBinIsEmpty">Zawartość kosza została usunięta</key>
|
||||
<key alias="recycleBinWarning">Usunięcie elementów z kosza powoduje ich trwałe i nieodwracalne skasowanie</key>
|
||||
@@ -288,10 +350,14 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="siterepublishHelp">Cache strony zostanie odświeżone. Cała zawartość opublikowana będzie aktualna, lecz nieopublikowana zawartość pozostanie niewidoczna</key>
|
||||
<key alias="tableColumns">Liczba kolumn</key>
|
||||
<key alias="tableRows">Liczba wierszy</key>
|
||||
<key alias="templateContentAreaHelp"><![CDATA[<strong>Ustaw zastępczy ID</strong> Ustawiając ID na tym elemencie możesz później łączyć treść z podrzędnych szablonów,
|
||||
ustawiając dowiązanie do tego ID na elemencie <code><asp:treści /></code>]]></key>
|
||||
<key alias="templateContentPlaceHolderHelp"><![CDATA[<strong>Wybierz zastępczy ID</strong> z poniższej listy. Możesz wybierać tylko
|
||||
spośród ID na szablonie nadrzędnym tego formularza.]]></key>
|
||||
<key alias="templateContentAreaHelp">
|
||||
<![CDATA[<strong>Ustaw zastępczy ID</strong> Ustawiając ID na tym elemencie możesz później łączyć treść z podrzędnych szablonów,
|
||||
ustawiając dowiązanie do tego ID na elemencie <code><asp:treści /></code>]]>
|
||||
</key>
|
||||
<key alias="templateContentPlaceHolderHelp">
|
||||
<![CDATA[<strong>Wybierz zastępczy ID</strong> z poniższej listy. Możesz wybierać tylko
|
||||
spośród ID na szablonie nadrzędnym tego formularza.]]>
|
||||
</key>
|
||||
<key alias="thumbnailimageclickfororiginal">Kliknij na obrazie, aby zobaczyć go w pełnym rozmiarze</key>
|
||||
<key alias="treepicker">Wybierz element</key>
|
||||
<key alias="viewCacheItem">Podgląd elementów Cache</key>
|
||||
@@ -303,14 +369,19 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="openInNewWindow">Otwórz zlinkowany dokument w nowym oknie lub zakładce</key>
|
||||
<key alias="linkToMedia">Link do mediów</key>
|
||||
<key alias="linkToFile">Link do plików</key>
|
||||
<key alias="selectContentStartNode">Wybierz węzeł początkowy zawartości</key>
|
||||
<key alias="selectMedia">Wybierz media</key>
|
||||
<key alias="selectIcon">Wybierz ikonę</key>
|
||||
<key alias="selectItem">Wybierz element</key>
|
||||
<key alias="selectLink">Wybierz link</key>
|
||||
<key alias="selectMacro">Wybierz makro</key>
|
||||
<key alias="selectContent">Wybierz zawartość</key>
|
||||
<key alias="selectMediaStartNode">Wybierz węzeł początkowy mediów</key>
|
||||
<key alias="selectMember">Wybierz członka</key>
|
||||
<key alias="selectMemberGroup">Wybierz członka grupy</key>
|
||||
<key alias="selectNode">Wybierz węzeł</key>
|
||||
<key alias="selectSections">Wybierz sekcje</key>
|
||||
<key alias="selectUsers">Wybierz użytkowników</key>
|
||||
<key alias="noIconsFound">Nie znaleziono ikon</key>
|
||||
<key alias="noMacroParams">Te makro nie ma żadnych właściwości</key>
|
||||
<key alias="noMacros">Brak dostępnych makro do wstawienia</key>
|
||||
@@ -325,9 +396,11 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
|
||||
<key alias="selectSnippet">Wybierz snippet</key>
|
||||
</area>
|
||||
<area alias="dictionaryItem">
|
||||
<key alias="description"><![CDATA[
|
||||
Edytuj różne wersje językowe dla elementu słownika '<em>%0%</em>' poniżej.<br/>
|
||||
Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]></key>
|
||||
<key alias="description">
|
||||
<![CDATA[
|
||||
Edytuj różne wersje językowe dla elementu słownika '<em>%0%</em>' poniżej.<br/>
|
||||
Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]>
|
||||
</key>
|
||||
<key alias="displayName">Nazwa języka</key>
|
||||
<key alias="changeKey">Edytuj klucz elementu słownika.</key>
|
||||
<key alias="changeKeyError">
|
||||
@@ -342,12 +415,15 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]></key>
|
||||
<key alias="confirmPassword">Potwierdź hasło</key>
|
||||
<key alias="nameentity">Nazwij %0%...</key>
|
||||
<key alias="entername">Wpisz nazwę...</key>
|
||||
<key alias="enteremail">Wpisz adres e-mail...</key>
|
||||
<key alias="enterusername">Wpisz nazwę użytkownika...</key>
|
||||
<key alias="label">Etykieta...</key>
|
||||
<key alias="enterDescription">Wpisz opis...</key>
|
||||
<key alias="search">Wpisz, aby wyszukać...</key>
|
||||
<key alias="filter">Wpisz, aby filtrować...</key>
|
||||
<key alias="enterTags">Wpisz, aby dodać tagi (naciśnij enter po każdym tagu)...</key>
|
||||
<key alias="email">Wpisz adres e-mail</key>
|
||||
<key alias="enterMessage">Wpisz wiadomość...</key>
|
||||
<key alias="usernameHint">Twoja nazwa użytkownika to przeważnie Twój adres e-mail</key>
|
||||
</area>
|
||||
<area alias="editcontenttype">
|
||||
|
||||
@@ -153,6 +153,7 @@
|
||||
<key alias="listNumeric">Нумерованный список</key>
|
||||
<key alias="macroInsert">Вставить макрос</key>
|
||||
<key alias="pictureInsert">Вставить изображение</key>
|
||||
<key alias="redo">Повторить</key>
|
||||
<key alias="relations">Править связи</key>
|
||||
<key alias="returnToList">Вернуться к списку</key>
|
||||
<key alias="save">Сохранить</key>
|
||||
@@ -168,6 +169,7 @@
|
||||
<key alias="styleChoose">Выбрать стиль</key>
|
||||
<key alias="styleShow">Показать стили</key>
|
||||
<key alias="tableInsert">Вставить таблицу</key>
|
||||
<key alias="undo">Отменить</key>
|
||||
</area>
|
||||
<area alias="changeDocType">
|
||||
<key alias="changeDocTypeInstruction">Чтобы сменить тип документа для выбранного узла, сначала выберите тип из списка разрешенных для данного расположения.</key>
|
||||
@@ -375,6 +377,7 @@
|
||||
<key alias="macroContainerSettings">Свойства макроса</key>
|
||||
<key alias="macroDoesNotHaveProperties">Этот макрос не имеет редактируемых свойств</key>
|
||||
<key alias="nodeNameLinkPicker">Заголовок ссылки</key>
|
||||
<key alias="noIconsFound">Ни одной пиктограммы не найдено</key>
|
||||
<key alias="paste">Вставить</key>
|
||||
<key alias="permissionsEdit">Изменить разрешения для</key>
|
||||
<key alias="permissionsSet">Установить разрешения для</key>
|
||||
@@ -596,6 +599,7 @@
|
||||
<key alias="new">Новый</key>
|
||||
<key alias="next">След</key>
|
||||
<key alias="no">Нет</key>
|
||||
<key alias="noItemsInList">Здесь пока нет элементов</key>
|
||||
<key alias="of">из</key>
|
||||
<key alias="off">Выкл</key>
|
||||
<key alias="ok">Ok</key>
|
||||
@@ -696,6 +700,8 @@
|
||||
<key alias="chooseExtra">Выбрать дополнительно</key>
|
||||
<key alias="chooseDefault">Выбрать по-умолчанию</key>
|
||||
<key alias="areAdded">добавлены</key>
|
||||
<key alias="maxItemsDescription">Оставьте пустым или задайте 0 для снятия лимита</key>
|
||||
<key alias="maxItems">Максимальное количество</key>
|
||||
</area>
|
||||
<area alias="headers">
|
||||
<key alias="page">Страница</key>
|
||||
@@ -1049,7 +1055,7 @@
|
||||
<area alias="packager">
|
||||
<key alias="chooseLocalPackageText"><![CDATA[
|
||||
Выберите файл пакета на своем компьютере, нажав на кнопку 'Обзор'<br />
|
||||
и указав на нужный файл. Пакеты Umbraco обычно являются архивами с расширением ".umb" или ".zip".
|
||||
и указав на нужный файл. Пакеты Umbraco обычно являются архивами с расширением '.zip'.
|
||||
]]></key>
|
||||
<key alias="dropHere">Перетащите сюда</key>
|
||||
<key alias="orClickHereToUpload">или нажмите здесь для выбора файла пакета</key>
|
||||
@@ -1215,12 +1221,12 @@
|
||||
</area>
|
||||
<area alias="relatedlinks">
|
||||
<key alias="caption">Заголовок</key>
|
||||
<key alias="captionPlaceholder">Укажите заголовок</key>
|
||||
<key alias="captionPlaceholder">Укажите заголовок ссылки</key>
|
||||
<key alias="chooseInternal">выбрать страницу сайта</key>
|
||||
<key alias="enterExternal">указать внешнюю ссылку</key>
|
||||
<key alias="externalLinkPlaceholder">Укажите ссылку</key>
|
||||
<key alias="link">Ссылка</key>
|
||||
<key alias="newWindow">В новом окне</key>
|
||||
<key alias="newWindow">Открыть в новом окне</key>
|
||||
</area>
|
||||
<area alias="renamecontainer">
|
||||
<key alias="renamed">Переименована</key>
|
||||
@@ -1393,8 +1399,6 @@
|
||||
<key alias="disableUserSuccess">'%0%' сейчас заблокирован</key>
|
||||
<key alias="disableUserError">При блокировке пользователя произошла ошибка</key>
|
||||
<key alias="setUserGroupOnUsersSuccess">Группы пользователей установлены</key>
|
||||
<key alias="deleteUserGroupsSuccess">Удалено %0% групп пользователей</key>
|
||||
<key alias="deleteUserGroupSuccess">'%0%' была удалена</key>
|
||||
<key alias="unlockUsersSuccess">Разблокировано %0% пользователей</key>
|
||||
<key alias="unlockUsersError">При разблокировке пользователей произошла ошибка</key>
|
||||
<key alias="unlockUserSuccess">'%0%' сейчас разблокирован</key>
|
||||
@@ -1517,8 +1521,8 @@
|
||||
<key alias="fallbackField">Поле замены</key>
|
||||
<key alias="addDefaultValue">Добавить значение по-умолчанию</key>
|
||||
<key alias="defaultValue">Значение по-умолчанию</key>
|
||||
<key alias="alternativeField">Альтернативное поле</key>
|
||||
<key alias="alternativeText">Текст по-умолчанию</key>
|
||||
<key alias="alternativeField">Поле замены</key>
|
||||
<key alias="alternativeText">Значение по-умолчанию</key>
|
||||
<key alias="casing">Регистр</key>
|
||||
<key alias="chooseField">Выбрать поле</key>
|
||||
<key alias="convertLineBreaks">Преобразовать переводы строк</key>
|
||||
@@ -1715,11 +1719,22 @@
|
||||
<key alias="profile">Профиль</key>
|
||||
<key alias="resetPassword">Сбросить пароль</key>
|
||||
<key alias="searchAllChildren">Поиск всех дочерних документов</key>
|
||||
<key alias="selectUserGroups">Выбрать группы пользователей</key>
|
||||
<key alias="sendInvite">Отправить приглашение</key>
|
||||
<key alias="sessionExpires" version="7.0">Сессия истекает через</key>
|
||||
<key alias="sectionsHelp">Разделы, доступные пользователю</key>
|
||||
<key alias="noStartNode">Начальный узел не задан</key>
|
||||
<key alias="noStartNodes">Начальные узлы не заданы</key>
|
||||
<key alias="sortNameAscending">Имя (А-Я)</key>
|
||||
<key alias="sortNameDescending">Имя (Я-А)</key>
|
||||
<key alias="sortCreateDateDescending">Сначала новые</key>
|
||||
<key alias="sortCreateDateAscending">Сначала старые</key>
|
||||
<key alias="sortLastLoginDateDescending">Недавно зашедшие</key>
|
||||
<key alias="stateActive">Активные</key>
|
||||
<key alias="stateAll">Все</key>
|
||||
<key alias="stateDisabled">Отключенные</key>
|
||||
<key alias="stateLockedOut">Заблокированные</key>
|
||||
<key alias="stateInvited">Приглашенные</key>
|
||||
<key alias="startnode">Начальный узел содержимого</key>
|
||||
<key alias="startnodehelp">Можно ограничить доступ к дереву содержимого (какой-либо его части), задав начальный узел</key>
|
||||
<key alias="startnodes">Начальные узлы содержимого</key>
|
||||
@@ -1736,6 +1751,7 @@
|
||||
<key alias="userInvitedSuccessHelp">Новому пользователю было отправлено приглашение, в котором содержатся инструкции для входа в панель Umbraco.</key>
|
||||
<key alias="userinviteWelcomeMessage">Здравствуйте и добро пожаловать в Umbraco! Все будет готово в течении пары минут, нам лишь нужно задать Ваш пароль для входа и добавить аватар.</key>
|
||||
<key alias="userinviteAvatarMessage">Загрузите изображение, это поможет другим пользователям идентифицировать Вас.</key>
|
||||
<key alias="userManagement">Управление пользователями</key>
|
||||
<key alias="userPermissions">Разрешения для пользователя</key>
|
||||
<key alias="writer">Автор</key>
|
||||
<key alias="yourHistory" version="7.0">Ваша недавняя история</key>
|
||||
|
||||
@@ -411,7 +411,7 @@
|
||||
<key alias="showPageOnSend">Vilken sida skall visas när formuläret är skickat</key>
|
||||
<key alias="size">Storlek</key>
|
||||
<key alias="sort">Sortera</key>
|
||||
<key alias="submit">Submit</key> <!-- TODO: Translate this -->
|
||||
<key alias="submit">Skicka</key>
|
||||
<key alias="type">Skriv</key>
|
||||
<key alias="typeToSearch">Skriv för att söka...</key>
|
||||
<key alias="up">Upp</key>
|
||||
@@ -426,8 +426,17 @@
|
||||
<key alias="width">Bredd</key>
|
||||
<key alias="view">Titta på</key>
|
||||
<key alias="yes">Ja</key>
|
||||
<key alias="reorder">Reorder</key>
|
||||
<key alias="reorderDone">I am done reordering</key>
|
||||
<key alias="reorder">Sortera</key>
|
||||
<key alias="reorderDone">Avsluta sortering</key>
|
||||
<key alias="preview">Förhandsvisning</key>
|
||||
<key alias="changePassword">Ändra lösenord</key>
|
||||
<key alias="to">till</key>
|
||||
<key alias="listView">Listvy</key>
|
||||
<key alias="saving">Sparar...</key>
|
||||
<key alias="current">nuvarande</key>
|
||||
<key alias="embed">Inbäddning</key>
|
||||
<key alias="retrieve">Hämta</key>
|
||||
<key alias="selected">valgt</key>
|
||||
</area>
|
||||
<area alias="graphicheadline">
|
||||
<key alias="backgroundcolor">Bakgrundsfärg</key>
|
||||
|
||||
@@ -805,13 +805,13 @@ namespace Umbraco.Web.Cache
|
||||
/// <summary>
|
||||
/// Used to cache all found event handlers
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<IEventDefinition, MethodInfo> FoundHandlers = new ConcurrentDictionary<IEventDefinition, MethodInfo>();
|
||||
private static readonly ConcurrentDictionary<string, MethodInfo> FoundHandlers = new ConcurrentDictionary<string, MethodInfo>();
|
||||
|
||||
internal static MethodInfo FindHandler(IEventDefinition eventDefinition)
|
||||
{
|
||||
var name = eventDefinition.Sender.GetType().Name + "_" + eventDefinition.EventName;
|
||||
|
||||
return FoundHandlers.GetOrAdd(eventDefinition, _ => CandidateHandlers.Value.FirstOrDefault(x => x.Name == name));
|
||||
return FoundHandlers.GetOrAdd(name, n => CandidateHandlers.Value.FirstOrDefault(x => x.Name == n));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,6 +532,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
[FileUploadCleanupFilter]
|
||||
[ContentPostValidate]
|
||||
[OutgoingEditorModelEvent]
|
||||
public ContentItemDisplay PostSave(
|
||||
[ModelBinder(typeof(ContentItemBinder))]
|
||||
ContentItemSave contentItem)
|
||||
@@ -792,11 +793,8 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
var contentService = Services.ContentService;
|
||||
|
||||
// content service GetByIds does order the content items based on the order of Ids passed in
|
||||
var content = contentService.GetByIds(sorted.IdSortOrder);
|
||||
|
||||
// Save content with new sort order and update content xml in db accordingly
|
||||
if (contentService.Sort(content) == false)
|
||||
if (contentService.Sort(sorted.IdSortOrder) == false)
|
||||
{
|
||||
LogHelper.Warn<ContentController>("Content sorting failed, this was probably caused by an event being cancelled");
|
||||
return Request.CreateValidationErrorResponse("Content sorting failed, this was probably caused by an event being cancelled");
|
||||
@@ -850,6 +848,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[EnsureUserPermissionForContent("id", 'U')]
|
||||
[OutgoingEditorModelEvent]
|
||||
public ContentItemDisplay PostUnPublish(int id)
|
||||
{
|
||||
var foundContent = GetObjectFromRequest(() => Services.ContentService.GetById(id));
|
||||
|
||||
@@ -464,6 +464,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
[FileUploadCleanupFilter]
|
||||
[MediaPostValidate]
|
||||
[OutgoingEditorModelEvent]
|
||||
public MediaItemDisplay PostSave(
|
||||
[ModelBinder(typeof(MediaItemBinder))]
|
||||
MediaItemSave contentItem)
|
||||
|
||||
@@ -256,6 +256,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[FileUploadCleanupFilter]
|
||||
[OutgoingEditorModelEvent]
|
||||
public MemberDisplay PostSave(
|
||||
[ModelBinder(typeof(MemberBinder))]
|
||||
MemberSave contentItem)
|
||||
@@ -393,7 +394,7 @@ namespace Umbraco.Web.Editors
|
||||
UpdateName(contentItem);
|
||||
|
||||
//map the custom properties - this will already be set for new entities in our member binder
|
||||
contentItem.PersistedContent.Email = contentItem.Email;
|
||||
contentItem.PersistedContent.Email = contentItem.Email;
|
||||
contentItem.PersistedContent.Username = contentItem.Username;
|
||||
|
||||
//use the base method to map the rest of the properties
|
||||
@@ -555,7 +556,7 @@ namespace Umbraco.Web.Editors
|
||||
var builtInAliases = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray();
|
||||
foreach (var p in contentItem.PersistedContent.Properties)
|
||||
{
|
||||
var valueMapped = currProps.SingleOrDefault(x => x.Alias == p.Alias);
|
||||
var valueMapped = currProps.FirstOrDefault(x => x.Alias == p.Alias);
|
||||
if (builtInAliases.Contains(p.Alias) == false && valueMapped != null)
|
||||
{
|
||||
p.Value = valueMapped.Value;
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Examine;
|
||||
using Examine.Config;
|
||||
using Examine.LuceneEngine;
|
||||
using Examine.LuceneEngine.Providers;
|
||||
using Examine.Providers;
|
||||
using Lucene.Net.Index;
|
||||
using Lucene.Net.Store;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using UmbracoExamine;
|
||||
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to configure Examine during startup for the web application
|
||||
/// </summary>
|
||||
internal class ExamineStartup
|
||||
{
|
||||
private readonly List<BaseIndexProvider> _indexesToRebuild = new List<BaseIndexProvider>();
|
||||
private readonly ApplicationContext _appCtx;
|
||||
private readonly ProfilingLogger _profilingLogger;
|
||||
private static bool _isConfigured = false;
|
||||
|
||||
//this is used if we are not the MainDom, in which case we need to ensure that if indexes need rebuilding that this
|
||||
//doesn't occur since that should only occur when we are MainDom
|
||||
private bool _disableExamineIndexing = false;
|
||||
|
||||
public ExamineStartup(ApplicationContext appCtx)
|
||||
{
|
||||
_appCtx = appCtx;
|
||||
_profilingLogger = appCtx.ProfilingLogger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called during the initialize operation of the boot manager process
|
||||
/// </summary>
|
||||
public void Initialize()
|
||||
{
|
||||
//We want to manage Examine's appdomain shutdown sequence ourselves so first we'll disable Examine's default behavior
|
||||
//and then we'll use MainDom to control Examine's shutdown
|
||||
ExamineManager.DisableDefaultHostingEnvironmentRegistration();
|
||||
|
||||
//we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain
|
||||
//terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock
|
||||
//which simply checks the existence of the lock file
|
||||
DirectoryTracker.DefaultLockFactory = d =>
|
||||
{
|
||||
var simpleFsLockFactory = new NoPrefixSimpleFsLockFactory(d);
|
||||
return simpleFsLockFactory;
|
||||
};
|
||||
|
||||
//This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976
|
||||
// when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's
|
||||
// event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build
|
||||
// it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the
|
||||
// boot process has completed. It's a hack but it works.
|
||||
ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup;
|
||||
|
||||
//let's deal with shutting down Examine with MainDom
|
||||
var examineShutdownRegistered = _appCtx.MainDom.Register(() =>
|
||||
{
|
||||
using (_profilingLogger.TraceDuration<ExamineStartup>("Examine shutting down"))
|
||||
{
|
||||
//Due to the way Examine's own IRegisteredObject works, we'll first run it with immediate=false and then true so that
|
||||
//it's correct subroutines are executed (otherwise we'd have to run this logic manually ourselves)
|
||||
ExamineManager.Instance.Stop(false);
|
||||
ExamineManager.Instance.Stop(true);
|
||||
}
|
||||
});
|
||||
if (examineShutdownRegistered)
|
||||
{
|
||||
_profilingLogger.Logger.Debug<ExamineStartup>("Examine shutdown registered with MainDom");
|
||||
}
|
||||
else
|
||||
{
|
||||
_profilingLogger.Logger.Debug<ExamineStartup>("Examine shutdown not registered, this appdomain is not the MainDom");
|
||||
|
||||
//if we could not register the shutdown examine ourselves, it means we are not maindom! in this case all of examine should be disabled
|
||||
//from indexing anything on startup!!
|
||||
_disableExamineIndexing = true;
|
||||
Suspendable.ExamineEvents.SuspendIndexers();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called during the Complete operation of the boot manager process
|
||||
/// </summary>
|
||||
public void Complete()
|
||||
{
|
||||
EnsureUnlockedAndConfigured();
|
||||
|
||||
//Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them
|
||||
// (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually
|
||||
// initialize during startup, in which case we want it to rebuild the indexes itself.
|
||||
ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup;
|
||||
|
||||
//don't do anything if we have disabled this
|
||||
if (_disableExamineIndexing == false)
|
||||
{
|
||||
foreach (var indexer in _indexesToRebuild)
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to perform the rebuilding indexes on startup if the indexes don't exist
|
||||
/// </summary>
|
||||
public void RebuildIndexes()
|
||||
{
|
||||
//don't do anything if we have disabled this
|
||||
if (_disableExamineIndexing) return;
|
||||
|
||||
EnsureUnlockedAndConfigured();
|
||||
|
||||
//If the developer has explicitly opted out of rebuilding indexes on startup then we
|
||||
// should adhere to that and not do it, this means that if they are load balancing things will be
|
||||
// out of sync if they are auto-scaling but there's not much we can do about that.
|
||||
if (ExamineSettings.Instance.RebuildOnAppStart == false) return;
|
||||
|
||||
foreach (var indexer in GetIndexesForColdBoot())
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The method used to create indexes on a cold boot
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and
|
||||
/// will rebuild it's own caches itself.
|
||||
/// </remarks>
|
||||
public IEnumerable<BaseIndexProvider> GetIndexesForColdBoot()
|
||||
{
|
||||
// NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed
|
||||
// on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty.
|
||||
// This callback is used above for the DatabaseServerMessenger startup options.
|
||||
|
||||
// all indexes
|
||||
IEnumerable<BaseIndexProvider> indexes = ExamineManager.Instance.IndexProviderCollection;
|
||||
|
||||
// except those that are already flagged
|
||||
// and are processed in Complete()
|
||||
if (_indexesToRebuild.Any())
|
||||
indexes = indexes.Except(_indexesToRebuild);
|
||||
|
||||
// return
|
||||
foreach (var index in indexes)
|
||||
yield return index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Must be called to configure each index and ensure it's unlocked before any indexing occurs
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Indexing rebuilding can occur on a normal boot if the indexes are empty or on a cold boot by the database server messenger. Before
|
||||
/// either of these happens, we need to configure the indexes.
|
||||
/// </remarks>
|
||||
private void EnsureUnlockedAndConfigured()
|
||||
{
|
||||
if (_isConfigured) return;
|
||||
|
||||
_isConfigured = true;
|
||||
|
||||
foreach (var luceneIndexer in ExamineManager.Instance.IndexProviderCollection.OfType<LuceneIndexer>())
|
||||
{
|
||||
//We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending
|
||||
//indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because
|
||||
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
|
||||
luceneIndexer.WaitForIndexQueueOnShutdown = false;
|
||||
|
||||
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
|
||||
//the indexes are not operational unless MainDom is true so if _disableExamineIndexing is false then we should be in charge
|
||||
if (_disableExamineIndexing == false)
|
||||
{
|
||||
var dir = luceneIndexer.GetLuceneDirectory();
|
||||
if (IndexWriter.IsLocked(dir))
|
||||
{
|
||||
_profilingLogger.Logger.Info<ExamineStartup>("Forcing index " + luceneIndexer.IndexSetName + " to be unlocked since it was left in a locked state");
|
||||
IndexWriter.Unlock(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args)
|
||||
{
|
||||
//store the indexer that needs rebuilding because it's empty for when the boot process
|
||||
// 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<ExamineStartup>(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(display => display.Alias, expression => expression.Ignore())
|
||||
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
|
||||
.ForMember(display => display.AllowedActions, expression => expression.ResolveUsing(
|
||||
new ActionButtonsResolver(new Lazy<IUserService>(() => applicationContext.Services.UserService))))
|
||||
new ActionButtonsResolver(new Lazy<IUserService>(() => applicationContext.Services.UserService), new Lazy<IContentService>(() => applicationContext.Services.ContentService))))
|
||||
.AfterMap((content, display) => AfterMap(content, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService,
|
||||
applicationContext.Services.ContentTypeService));
|
||||
|
||||
@@ -219,10 +219,14 @@ namespace Umbraco.Web.Models.Mapping
|
||||
private class ActionButtonsResolver : ValueResolver<IContent, IEnumerable<string>>
|
||||
{
|
||||
private readonly Lazy<IUserService> _userService;
|
||||
private readonly Lazy<IContentService> _contentService;
|
||||
|
||||
public ActionButtonsResolver(Lazy<IUserService> userService)
|
||||
public ActionButtonsResolver(Lazy<IUserService> userService, Lazy<IContentService> contentService)
|
||||
{
|
||||
if (userService == null) throw new ArgumentNullException("userService");
|
||||
if (contentService == null) throw new ArgumentNullException("contentService");
|
||||
_userService = userService;
|
||||
_contentService = contentService;
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> ResolveCore(IContent source)
|
||||
@@ -234,14 +238,21 @@ namespace Umbraco.Web.Models.Mapping
|
||||
}
|
||||
var svc = _userService.Value;
|
||||
|
||||
var permissions = svc.GetPermissions(
|
||||
string path;
|
||||
if (source.HasIdentity)
|
||||
path = source.Path;
|
||||
else
|
||||
{
|
||||
var parent = _contentService.Value.GetById(source.ParentId);
|
||||
path = parent == null ? "-1" : parent.Path;
|
||||
}
|
||||
|
||||
var permissions = svc.GetPermissionsForPath(
|
||||
//TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is
|
||||
// with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null
|
||||
// refrence exception :(
|
||||
UmbracoContext.Current.Security.CurrentUser,
|
||||
// Here we need to do a special check since this could be new content, in which case we need to get the permissions
|
||||
// from the parent, not the existing one otherwise permissions would be coming from the root since Id is 0.
|
||||
source.HasIdentity ? source.Id : source.ParentId)
|
||||
path)
|
||||
.GetAllPermissions();
|
||||
|
||||
return permissions;
|
||||
|
||||
@@ -74,11 +74,47 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> GetAtRoot(UmbracoContext umbracoContext, bool preview)
|
||||
{
|
||||
//TODO: We should be able to look these ids first in Examine!
|
||||
var searchProvider = GetSearchProviderSafe();
|
||||
|
||||
if (searchProvider != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// first check in Examine for the cache values
|
||||
// +(+parentID:-1) +__IndexType:media
|
||||
|
||||
var criteria = searchProvider.CreateSearchCriteria("media");
|
||||
var filter = criteria.ParentId(-1).Not().Field(UmbracoContentIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
|
||||
|
||||
var result = searchProvider.Search(filter.Compile());
|
||||
if (result != null)
|
||||
return result.Select(x => CreateFromCacheValues(ConvertFromSearchResult(x)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex is FileNotFoundException)
|
||||
{
|
||||
//Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
|
||||
//See this thread: http://examine.cdodeplex.com/discussions/264341
|
||||
//Catch the exception here for the time being, and just fallback to GetMedia
|
||||
//TODO: Need to fix examine in LB scenarios!
|
||||
LogHelper.Error<PublishedMediaCache>("Could not load data from Examine index for media", ex);
|
||||
}
|
||||
else if (ex is AlreadyClosedException)
|
||||
{
|
||||
//If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
|
||||
//be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
|
||||
LogHelper.Error<PublishedMediaCache>("Could not load data from Examine index for media, the app domain is most likely in a shutdown state", ex);
|
||||
}
|
||||
else throw;
|
||||
}
|
||||
}
|
||||
|
||||
//something went wrong, fetch from the db
|
||||
|
||||
var rootMedia = _applicationContext.Services.MediaService.GetRootMedia();
|
||||
return rootMedia.Select(m => GetUmbracoMedia(m.Id));
|
||||
}
|
||||
return rootMedia.Select(m => CreateFromCacheValues(ConvertFromIMedia(m)));
|
||||
}
|
||||
|
||||
public virtual IPublishedContent GetSingleByXPath(UmbracoContext umbracoContext, bool preview, string xpath, XPathVariable[] vars)
|
||||
{
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Web
|
||||
{
|
||||
// todo: in v8, implement in a more efficient way
|
||||
var legacyXml = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema;
|
||||
var xpath = legacyXml ? "//node [@key=$guid]" : "//* [@isDoc and @key=$guid]";
|
||||
var xpath = legacyXml ? "//node [@key=$guid]" : "//* [@key=$guid]";
|
||||
var doc = cache.GetSingleByXPath(xpath, new XPathVariable("guid", id.ToString()));
|
||||
return doc;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,16 @@ namespace Umbraco.Web.Scheduling
|
||||
finally
|
||||
{
|
||||
if (tempContext != null)
|
||||
{
|
||||
// because we created an http context and assigned it to UmbracoContext,
|
||||
// the batched messenger does batch instructions, but since there is no
|
||||
// request, we need to explicitely tell it to flush the batch of instrs.
|
||||
var batchedMessenger = ServerMessengerResolver.Current.Messenger as BatchedDatabaseServerMessenger;
|
||||
if (batchedMessenger != null)
|
||||
batchedMessenger.FlushBatch();
|
||||
|
||||
tempContext.Dispose(); // nulls the ThreadStatic context
|
||||
}
|
||||
}
|
||||
|
||||
return true; // repeat
|
||||
|
||||
@@ -112,8 +112,8 @@
|
||||
<Reference Include="dotless.Core, Version=1.5.2.0, Culture=neutral, PublicKeyToken=96b446c9e63eae34, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\dotless.1.5.2\lib\dotless.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.85.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.85\lib\net45\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
@@ -121,11 +121,9 @@
|
||||
</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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="MarkdownSharp, Version=1.14.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Markdown.1.14.7\lib\net45\MarkdownSharp.dll</HintPath>
|
||||
@@ -333,6 +331,7 @@
|
||||
<Compile Include="Editors\UserGroupEditorAuthorizationHelper.cs" />
|
||||
<Compile Include="Editors\UserGroupsController.cs" />
|
||||
<Compile Include="Editors\UserGroupValidateAttribute.cs" />
|
||||
<Compile Include="ExamineStartup.cs" />
|
||||
<Compile Include="Extensions\UdiExtensions.cs" />
|
||||
<Compile Include="HealthCheck\Checks\Config\AbstractConfigCheck.cs" />
|
||||
<Compile Include="HealthCheck\Checks\Config\AcceptableConfiguration.cs" />
|
||||
|
||||
@@ -97,17 +97,8 @@ namespace Umbraco.Web.WebApi.Binders
|
||||
if (member == null)
|
||||
{
|
||||
throw new InvalidOperationException("Could not find member with key " + key);
|
||||
}
|
||||
}
|
||||
|
||||
var standardProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
|
||||
|
||||
//remove all membership properties, these values are set with the membership provider.
|
||||
var exclude = standardProps.Select(x => x.Value.Alias).ToArray();
|
||||
|
||||
foreach (var remove in exclude)
|
||||
{
|
||||
member.Properties.Remove(remove);
|
||||
}
|
||||
return member;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Http;
|
||||
@@ -11,10 +10,7 @@ using System.Web.Http.Dispatcher;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Routing;
|
||||
using ClientDependency.Core.Config;
|
||||
using Examine;
|
||||
using Examine.Config;
|
||||
using Examine.Providers;
|
||||
using umbraco;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
@@ -27,25 +23,18 @@ using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Dictionary;
|
||||
using Umbraco.Web.Install;
|
||||
using Umbraco.Web.Macros;
|
||||
using Umbraco.Web.Media;
|
||||
using Umbraco.Web.Media.ThumbnailProviders;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.PropertyEditors;
|
||||
using Umbraco.Web.PropertyEditors.ValueConverters;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Scheduling;
|
||||
using Umbraco.Web.UI.JavaScript;
|
||||
using Umbraco.Web.WebApi;
|
||||
using umbraco.BusinessLogic;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Editors;
|
||||
@@ -64,8 +53,9 @@ namespace Umbraco.Web
|
||||
public class WebBootManager : CoreBootManager
|
||||
{
|
||||
private readonly bool _isForTesting;
|
||||
//NOTE: see the Initialize method for what this is used for
|
||||
private static readonly List<BaseIndexProvider> IndexesToRebuild = new List<BaseIndexProvider>();
|
||||
|
||||
//needs to be static because we have the public static method GetIndexesForColdBoot
|
||||
private static ExamineStartup _examineStartup;
|
||||
|
||||
public WebBootManager(UmbracoApplicationBase umbracoApplication)
|
||||
: base(umbracoApplication)
|
||||
@@ -109,15 +99,11 @@ namespace Umbraco.Web
|
||||
/// <returns></returns>
|
||||
public override IBootManager Initialize()
|
||||
{
|
||||
//This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976
|
||||
// when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's
|
||||
// event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build
|
||||
// it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the
|
||||
// boot process has completed. It's a hack but it works.
|
||||
ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup;
|
||||
|
||||
base.Initialize();
|
||||
|
||||
_examineStartup = new ExamineStartup(ApplicationContext);
|
||||
_examineStartup.Initialize();
|
||||
|
||||
// Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK]
|
||||
ClientDependency.Core.CompositeFiles.Providers.XmlFileMapper.FileMapVirtualFolder = "~/App_Data/TEMP/ClientDependency";
|
||||
ClientDependency.Core.CompositeFiles.Providers.BaseCompositeFileProcessingProvider.UrlTypeDefault = ClientDependency.Core.CompositeFiles.Providers.CompositeUrlType.Base64QueryStrings;
|
||||
@@ -214,25 +200,15 @@ namespace Umbraco.Web
|
||||
//Now, startup all of our legacy startup handler
|
||||
ApplicationEventsResolver.Current.InstantiateLegacyStartupHandlers();
|
||||
|
||||
//Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them
|
||||
// (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually
|
||||
// initialize during startup, in which case we want it to rebuild the indexes itself.
|
||||
ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup;
|
||||
if (IndexesToRebuild.Any())
|
||||
{
|
||||
foreach (var indexer in IndexesToRebuild)
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
}
|
||||
}
|
||||
_examineStartup.Complete();
|
||||
|
||||
//Now ensure webapi is initialized after everything
|
||||
GlobalConfiguration.Configuration.EnsureInitialized();
|
||||
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
internal static void ConfigureGlobalFilters()
|
||||
{
|
||||
@@ -377,11 +353,11 @@ namespace Umbraco.Web
|
||||
{
|
||||
base.InitializeResolvers();
|
||||
|
||||
SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees());
|
||||
SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees());
|
||||
|
||||
XsltExtensionsResolver.Current = new XsltExtensionsResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveXsltExtensions());
|
||||
|
||||
EditorValidationResolver.Current= new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes<IEditorValidator>());
|
||||
EditorValidationResolver.Current = new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes<IEditorValidator>());
|
||||
|
||||
//set the default RenderMvcController
|
||||
DefaultRenderMvcControllerResolver.Current = new DefaultRenderMvcControllerResolver(typeof(RenderMvcController));
|
||||
@@ -421,23 +397,6 @@ namespace Umbraco.Web
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//We are using a custom action here so we can check the examine settings value first, we don't want to
|
||||
// put that check into the CreateIndexesOnColdBoot method because developers may choose to use this
|
||||
// method directly and they will be in charge of this check if they need it
|
||||
Action rebuildIndexes = () =>
|
||||
{
|
||||
//If the developer has explicitly opted out of rebuilding indexes on startup then we
|
||||
// should adhere to that and not do it, this means that if they are load balancing things will be
|
||||
// out of sync if they are auto-scaling but there's not much we can do about that.
|
||||
if (ExamineSettings.Instance.RebuildOnAppStart == false) return;
|
||||
|
||||
foreach (var indexer in GetIndexesForColdBoot())
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
}
|
||||
};
|
||||
|
||||
ServerMessengerResolver.Current.SetServerMessenger(new BatchedDatabaseServerMessenger(
|
||||
ApplicationContext,
|
||||
true,
|
||||
@@ -453,7 +412,7 @@ namespace Umbraco.Web
|
||||
//rebuild indexes if the server is not synced
|
||||
// NOTE: This will rebuild ALL indexes including the members, if developers want to target specific
|
||||
// indexes then they can adjust this logic themselves.
|
||||
rebuildIndexes
|
||||
() => _examineStartup.RebuildIndexes()
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -489,9 +448,9 @@ namespace Umbraco.Web
|
||||
// add all known factories, devs can then modify this list on application
|
||||
// startup either by binding to events or in their own global.asax
|
||||
new[]
|
||||
{
|
||||
typeof (RenderControllerFactory)
|
||||
});
|
||||
{
|
||||
typeof (RenderControllerFactory)
|
||||
});
|
||||
|
||||
UrlProviderResolver.Current = new UrlProviderResolver(
|
||||
ServiceProvider, LoggerResolver.Current.Logger,
|
||||
@@ -559,42 +518,11 @@ namespace Umbraco.Web
|
||||
/// <remarks>
|
||||
/// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and
|
||||
/// will rebuild it's own caches itself.
|
||||
/// TODO: Does this method need to exist? Is it used publicly elsewhere (i.e. outside of core?)
|
||||
/// </remarks>
|
||||
public static IEnumerable<BaseIndexProvider> GetIndexesForColdBoot()
|
||||
{
|
||||
// NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed
|
||||
// on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty.
|
||||
// This callback is used above for the DatabaseServerMessenger startup options.
|
||||
|
||||
// all indexes
|
||||
IEnumerable<BaseIndexProvider> indexes = ExamineManager.Instance.IndexProviderCollection;
|
||||
|
||||
// except those that are already flagged
|
||||
// and are processed in Complete()
|
||||
if (IndexesToRebuild.Any())
|
||||
indexes = indexes.Except(IndexesToRebuild);
|
||||
|
||||
// return
|
||||
foreach (var index in indexes)
|
||||
yield return index;
|
||||
}
|
||||
|
||||
|
||||
private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args)
|
||||
{
|
||||
//store the indexer that needs rebuilding because it's empty for when the boot process
|
||||
// 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);
|
||||
}
|
||||
return _examineStartup.GetIndexesForColdBoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ using Examine;
|
||||
using Examine.LuceneEngine;
|
||||
using Examine.LuceneEngine.Providers;
|
||||
using Examine.Providers;
|
||||
using Lucene.Net.Index;
|
||||
using Lucene.Net.Search;
|
||||
using Lucene.Net.Store;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Search;
|
||||
@@ -189,20 +191,39 @@ namespace Umbraco.Web.WebServices
|
||||
{
|
||||
indexer.RebuildIndex();
|
||||
}
|
||||
catch (LockObtainFailedException)
|
||||
{
|
||||
//this will occur if the index is locked (which it should defo not be!) so in this case we'll forcibly unlock it and try again
|
||||
|
||||
try
|
||||
{
|
||||
IndexWriter.Unlock(indexer.GetLuceneDirectory());
|
||||
indexer.RebuildIndex();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return HandleException(e, indexer);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//ensure it's not listening
|
||||
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
|
||||
LogHelper.Error<ExamineManagementApiController>("An error occurred rebuilding index", ex);
|
||||
var response = Request.CreateResponse(HttpStatusCode.Conflict);
|
||||
response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex));
|
||||
response.ReasonPhrase = "Could Not Rebuild";
|
||||
return response;
|
||||
return HandleException(ex, indexer);
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
private HttpResponseMessage HandleException(Exception ex, LuceneIndexer indexer)
|
||||
{
|
||||
//ensure it's not listening
|
||||
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
|
||||
LogHelper.Error<ExamineManagementApiController>("An error occurred rebuilding index", ex);
|
||||
var response = Request.CreateResponse(HttpStatusCode.Conflict);
|
||||
response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex));
|
||||
response.ReasonPhrase = "Could Not Rebuild";
|
||||
return response;
|
||||
}
|
||||
|
||||
//static listener so it's not GC'd
|
||||
private static void Indexer_IndexOperationComplete(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
@@ -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.5.2" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.85" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.89" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
<package id="Markdown" version="1.14.7" targetFramework="net45" />
|
||||
|
||||
@@ -175,13 +175,16 @@ namespace umbraco.presentation.webservices
|
||||
{
|
||||
var contentService = ApplicationContext.Services.ContentService;
|
||||
try
|
||||
{
|
||||
var intIds = ids.Select(int.Parse).ToArray();
|
||||
var allContent = contentService.GetByIds(intIds).ToDictionary(x => x.Id, x => x);
|
||||
var sortedContent = intIds.Select(x => allContent[x]);
|
||||
|
||||
{
|
||||
// Save content with new sort order and update db+cache accordingly
|
||||
var sorted = contentService.Sort(sortedContent);
|
||||
var intIds = new List<int>();
|
||||
foreach (var stringId in ids)
|
||||
{
|
||||
int intId;
|
||||
if (int.TryParse(stringId, out intId))
|
||||
intIds.Add(intId);
|
||||
}
|
||||
var sorted = contentService.Sort(intIds.ToArray());
|
||||
|
||||
// refresh sort order on cached xml
|
||||
// but no... this is not distributed - solely relying on content service & events should be enough
|
||||
|
||||
@@ -150,7 +150,7 @@ namespace UmbracoExamine
|
||||
{
|
||||
//By default, we will be using the UmbracoDataService
|
||||
//generally this would only need to be set differently for unit testing
|
||||
DataService = new UmbracoDataService();
|
||||
DataService = CreateDefaultUmbracoDataService();
|
||||
}
|
||||
|
||||
DataService.LogService.LogLevel = LoggingLevel.Normal;
|
||||
@@ -206,10 +206,15 @@ namespace UmbracoExamine
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected virtual IDataService CreateDefaultUmbracoDataService()
|
||||
{
|
||||
return new UmbracoDataService();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to aquire the internal searcher
|
||||
/// </summary>
|
||||
|
||||
@@ -13,10 +13,12 @@ namespace UmbracoExamine.Config
|
||||
/// </summary>
|
||||
public static class IndexSetExtensions
|
||||
{
|
||||
internal static IIndexCriteria ToIndexCriteria(this IndexSet set, IDataService svc,
|
||||
StaticFieldCollection indexFieldPolicies)
|
||||
internal static IIndexCriteria ToIndexCriteria(this IndexSet set,
|
||||
IDataService svc,
|
||||
StaticFieldCollection indexFieldPolicies,
|
||||
IEnumerable<IndexField> additionalUserFields = null)
|
||||
{
|
||||
return new LazyIndexCriteria(set, svc, indexFieldPolicies);
|
||||
return new LazyIndexCriteria(set, svc, indexFieldPolicies, additionalUserFields);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace UmbracoExamine.Config
|
||||
public LazyIndexCriteria(
|
||||
IndexSet set,
|
||||
IDataService svc,
|
||||
StaticFieldCollection indexFieldPolicies)
|
||||
StaticFieldCollection indexFieldPolicies,
|
||||
IEnumerable<IndexField> additionalUserFields = null)
|
||||
{
|
||||
if (set == null) throw new ArgumentNullException("set");
|
||||
if (indexFieldPolicies == null) throw new ArgumentNullException("indexFieldPolicies");
|
||||
@@ -21,7 +22,7 @@ namespace UmbracoExamine.Config
|
||||
_lazyCriteria = new Lazy<IIndexCriteria>(() =>
|
||||
{
|
||||
var attributeFields = set.IndexAttributeFields.Cast<IIndexField>().ToArray();
|
||||
var userFields = set.IndexUserFields.Cast<IIndexField>().ToArray();
|
||||
var userFields = set.IndexUserFields.Cast<IIndexField>().ToList();
|
||||
var includeNodeTypes = set.IncludeNodeTypes.Cast<IIndexField>().Select(x => x.Name).ToArray();
|
||||
var excludeNodeTypes = set.ExcludeNodeTypes.Cast<IIndexField>().Select(x => x.Name).ToArray();
|
||||
var parentId = set.IndexParentId;
|
||||
@@ -44,7 +45,7 @@ namespace UmbracoExamine.Config
|
||||
}
|
||||
fields.Add(field);
|
||||
}
|
||||
userFields = fields.ToArray();
|
||||
userFields = fields.ToList();
|
||||
}
|
||||
|
||||
//if there are no attribute fields defined, we'll populate them from the data source (include them all)
|
||||
@@ -68,6 +69,19 @@ namespace UmbracoExamine.Config
|
||||
attributeFields = fields.ToArray();
|
||||
}
|
||||
|
||||
//merge in the additional user fields if any are defined
|
||||
if (additionalUserFields != null)
|
||||
{
|
||||
foreach (var field in additionalUserFields)
|
||||
{
|
||||
var f = field; //copy local
|
||||
if (userFields.Any(x => x.Name == f.Name) == false)
|
||||
{
|
||||
userFields.Add(f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new IndexCriteria(
|
||||
attributeFields,
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace UmbracoExamine.DataServices
|
||||
{
|
||||
public class UmbracoContentService : IContentService
|
||||
{
|
||||
private readonly ApplicationContext _applicationContext;
|
||||
protected ApplicationContext ApplicationContext { get; private set; }
|
||||
|
||||
public UmbracoContentService()
|
||||
: this(ApplicationContext.Current)
|
||||
@@ -21,7 +21,7 @@ namespace UmbracoExamine.DataServices
|
||||
|
||||
public UmbracoContentService(ApplicationContext applicationContext)
|
||||
{
|
||||
_applicationContext = applicationContext;
|
||||
ApplicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,11 +60,11 @@ namespace UmbracoExamine.DataServices
|
||||
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
|
||||
{
|
||||
var xmlContent = XDocument.Parse("<content></content>");
|
||||
var rootContent = _applicationContext.Services.ContentService.GetRootContent();
|
||||
var rootContent = ApplicationContext.Services.ContentService.GetRootContent();
|
||||
foreach (var c in rootContent)
|
||||
{
|
||||
// not sure this uses the database, but better be save
|
||||
xmlContent.Root.Add(c.ToDeepXml(_applicationContext.Services.PackagingService));
|
||||
xmlContent.Root.Add(c.ToDeepXml(ApplicationContext.Services.PackagingService));
|
||||
}
|
||||
var result = ((IEnumerable)xmlContent.XPathEvaluate(xpath)).Cast<XElement>();
|
||||
scope.Complete();
|
||||
@@ -82,7 +82,7 @@ namespace UmbracoExamine.DataServices
|
||||
{
|
||||
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
|
||||
{
|
||||
var ret = _applicationContext.Services.PublicAccessService.IsProtected(path.EnsureEndsWith("," + nodeId));
|
||||
var ret = ApplicationContext.Services.PublicAccessService.IsProtected(path.EnsureEndsWith("," + nodeId));
|
||||
scope.Complete();
|
||||
return ret;
|
||||
}
|
||||
@@ -93,14 +93,26 @@ namespace UmbracoExamine.DataServices
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
|
||||
public IEnumerable<string> GetAllUserPropertyNames()
|
||||
public virtual IEnumerable<string> GetAllUserPropertyNames()
|
||||
{
|
||||
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = _applicationContext.DatabaseContext.Database.Fetch<string>("select distinct alias from cmsPropertyType order by alias");
|
||||
scope.Complete();
|
||||
{
|
||||
//only return the property type aliases for media and content
|
||||
|
||||
var result = ApplicationContext.DatabaseContext.Database.Fetch<string>(
|
||||
@"select distinct cmsPropertyType.alias from cmsPropertyType
|
||||
inner join cmsContentType on cmsContentType.nodeId = cmsPropertyType.contentTypeId
|
||||
inner join umbracoNode on umbracoNode.id = cmsContentType.nodeId
|
||||
where umbracoNode.nodeObjectType = @contentNodeObjectType OR umbracoNode.nodeObjectType = @mediaNodeObjectType
|
||||
order by alias", new
|
||||
{
|
||||
contentNodeObjectType = Constants.ObjectTypes.DocumentType,
|
||||
mediaNodeObjectType = Constants.ObjectTypes.MediaType
|
||||
});
|
||||
|
||||
scope.Complete();
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace UmbracoExamine.DataServices
|
||||
{
|
||||
public class UmbracoMemberContentService : UmbracoContentService
|
||||
{
|
||||
public override IEnumerable<string> GetAllUserPropertyNames()
|
||||
{
|
||||
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
|
||||
{
|
||||
try
|
||||
{
|
||||
//only return the property type aliases for members
|
||||
|
||||
var result = ApplicationContext.DatabaseContext.Database.Fetch<string>(
|
||||
@"select distinct cmsPropertyType.alias from cmsPropertyType
|
||||
inner join cmsContentType on cmsContentType.nodeId = cmsPropertyType.contentTypeId
|
||||
inner join umbracoNode on umbracoNode.id = cmsContentType.nodeId
|
||||
where umbracoNode.nodeObjectType = @nodeObjectType
|
||||
order by alias", new {nodeObjectType = Constants.ObjectTypes.MemberType});
|
||||
|
||||
scope.Complete();
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<UmbracoMemberContentService>("EXCEPTION OCCURRED reading GetAllUserPropertyNames", ex);
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace UmbracoExamine.DataServices
|
||||
{
|
||||
public class UmbracoMemberDataService : UmbracoDataService
|
||||
{
|
||||
public UmbracoMemberDataService()
|
||||
{
|
||||
ContentService = new UmbracoMemberContentService();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.IO;
|
||||
using Examine;
|
||||
using Examine.LuceneEngine;
|
||||
using Lucene.Net.Store;
|
||||
|
||||
namespace UmbracoExamine
|
||||
{
|
||||
/// <summary>
|
||||
/// A custom <see cref="SimpleFSLockFactory"/> that ensures a prefixless lock prefix
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is a work around for the Lucene APIs. By default Lucene will use a null prefix however when we set a custom
|
||||
/// lock factory the null prefix is overwritten.
|
||||
/// </remarks>
|
||||
public class NoPrefixSimpleFsLockFactory : SimpleFSLockFactory
|
||||
{
|
||||
public NoPrefixSimpleFsLockFactory(DirectoryInfo lockDir) : base(lockDir)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SetLockPrefix(string lockPrefix)
|
||||
{
|
||||
base.SetLockPrefix(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -410,7 +410,11 @@ namespace UmbracoExamine
|
||||
{
|
||||
if (SupportedTypes.Contains(type) == false)
|
||||
return;
|
||||
|
||||
|
||||
//if the app is shutting down do not continue
|
||||
if (IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var pageIndex = 0;
|
||||
|
||||
DataService.LogService.AddInfoLog(-1, string.Format("PerformIndexAll - Start data queries - {0}", type));
|
||||
@@ -530,7 +534,7 @@ namespace UmbracoExamine
|
||||
content, notPublished).WhereNotNull(), type);
|
||||
|
||||
pageIndex++;
|
||||
} while (currentPageSize == PageSize);
|
||||
} while (currentPageSize == PageSize && IsCancellationRequested == false); //do not continue if app is shutting down
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -628,7 +632,7 @@ namespace UmbracoExamine
|
||||
|
||||
AddNodesToIndex(xElements, type);
|
||||
pageIndex++;
|
||||
} while (more);
|
||||
} while (more && IsCancellationRequested == false); //don't continue if the app is shutting down
|
||||
}
|
||||
|
||||
internal static IEnumerable<XElement> GetSerializedContent(
|
||||
|
||||
@@ -82,16 +82,14 @@
|
||||
<AssemblyOriginatorKeyFile>..\Solution Items\TheFARM-Public.snk</AssemblyOriginatorKeyFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Examine, Version=0.1.85.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.85\lib\net45\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.89\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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System" />
|
||||
@@ -119,6 +117,8 @@
|
||||
<Compile Include="DataServices\UmbracoDataService.cs" />
|
||||
<Compile Include="DataServices\UmbracoContentService.cs" />
|
||||
<Compile Include="DataServices\UmbracoMediaService.cs" />
|
||||
<Compile Include="DataServices\UmbracoMemberContentService.cs" />
|
||||
<Compile Include="DataServices\UmbracoMemberDataService.cs" />
|
||||
<Compile Include="DeletePolicyTracker.cs" />
|
||||
<Compile Include="ExamineHelper.cs" />
|
||||
<Compile Include="IndexTypes.cs" />
|
||||
@@ -134,6 +134,7 @@
|
||||
<Compile Include="LocalStorage\MultiIndexLockFactory.cs" />
|
||||
<Compile Include="LocalStorage\MultiIndexOutput.cs" />
|
||||
<Compile Include="LoggingLevel.cs" />
|
||||
<Compile Include="NoPrefixSimpleFsLockFactory.cs" />
|
||||
<Compile Include="StaticField.cs" />
|
||||
<Compile Include="StaticFieldCollection.cs" />
|
||||
<Compile Include="UmbracoMemberIndexer.cs" />
|
||||
|
||||
@@ -19,6 +19,8 @@ using Lucene.Net.Analysis;
|
||||
namespace UmbracoExamine
|
||||
{
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Custom indexer for members
|
||||
/// </summary>
|
||||
@@ -101,6 +103,11 @@ namespace UmbracoExamine
|
||||
_memberTypeService = memberTypeService;
|
||||
}
|
||||
|
||||
protected override IDataService CreateDefaultUmbracoDataService()
|
||||
{
|
||||
return new UmbracoMemberDataService();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the'_searchEmail' is added to the user fields so that it is indexed - without having to modify the config
|
||||
/// </summary>
|
||||
@@ -108,34 +115,26 @@ namespace UmbracoExamine
|
||||
/// <returns></returns>
|
||||
protected override IIndexCriteria GetIndexerData(IndexSet indexSet)
|
||||
{
|
||||
var indexerData = base.GetIndexerData(indexSet);
|
||||
|
||||
if (CanInitialize())
|
||||
{
|
||||
//If the fields are missing a custom _searchEmail, then add it
|
||||
|
||||
if (indexerData.UserFields.Any(x => x.Name == "_searchEmail") == false)
|
||||
//Add a custom _searchEmail to the index criteria no matter what is in config
|
||||
var field = new IndexField { Name = "_searchEmail" };
|
||||
StaticField policy;
|
||||
if (IndexFieldPolicies.TryGetValue("_searchEmail", out policy))
|
||||
{
|
||||
var field = new IndexField { Name = "_searchEmail" };
|
||||
|
||||
StaticField policy;
|
||||
if (IndexFieldPolicies.TryGetValue("_searchEmail", out policy))
|
||||
{
|
||||
field.Type = policy.Type;
|
||||
field.EnableSorting = policy.EnableSorting;
|
||||
}
|
||||
|
||||
return new IndexCriteria(
|
||||
indexerData.StandardFields,
|
||||
indexerData.UserFields.Concat(new[] { field }),
|
||||
indexerData.IncludeNodeTypes,
|
||||
indexerData.ExcludeNodeTypes,
|
||||
indexerData.ParentNodeId
|
||||
);
|
||||
field.Type = policy.Type;
|
||||
field.EnableSorting = policy.EnableSorting;
|
||||
}
|
||||
}
|
||||
|
||||
return indexerData;
|
||||
return indexSet.ToIndexCriteria(DataService, IndexFieldPolicies,
|
||||
//add additional explicit fields
|
||||
new []{field});
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.GetIndexerData(indexSet);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -198,7 +197,7 @@ namespace UmbracoExamine
|
||||
AddNodesToIndex(GetSerializedMembers(members), type);
|
||||
|
||||
pageIndex++;
|
||||
} while (members.Length == pageSize);
|
||||
} while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -212,7 +211,7 @@ namespace UmbracoExamine
|
||||
AddNodesToIndex(GetSerializedMembers(members), type);
|
||||
|
||||
pageIndex++;
|
||||
} while (members.Length == pageSize);
|
||||
} while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,8 +232,8 @@ namespace UmbracoExamine
|
||||
protected override XDocument GetXDocument(string xPath, string type)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the special __key and _searchEmail fields
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Examine" version="0.1.85" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.89" targetFramework="net45" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
|
||||
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Examine" version="0.1.85" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.89" targetFramework="net45" />
|
||||
<package id="HtmlAgilityPack" version="1.4.9.5" 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.85.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.85\lib\net45\Examine.dll</HintPath>
|
||||
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
@@ -54,11 +54,9 @@
|
||||
</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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
|
||||
@@ -108,11 +108,9 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
|
||||
@@ -122,11 +120,9 @@
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.configuration" />
|
||||
@@ -145,27 +141,21 @@
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Helpers, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Deployment, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml">
|
||||
<Name>System.XML</Name>
|
||||
|
||||
@@ -108,15 +108,12 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</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>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
@@ -168,7 +165,6 @@
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="TidyNet, Version=1.0.0.0, Culture=neutral">
|
||||
<HintPath>..\packages\Tidy.Net.1.0.0\lib\TidyNet.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.configuration" />
|
||||
|
||||
@@ -70,10 +70,10 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.ApplicationBlocks.Data, Version=1.0.1559.20655, Culture=neutral">
|
||||
<HintPath>..\packages\Microsoft.ApplicationBlocks.Data.1.0.1559.20655\lib\Microsoft.ApplicationBlocks.Data.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
|
||||
@@ -116,7 +116,6 @@
|
||||
</ProjectReference>
|
||||
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System">
|
||||
<Name>System</Name>
|
||||
|
||||
Reference in New Issue
Block a user