Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 861e5908a7 | |||
| 75fb070825 | |||
| 8a0f32e980 | |||
| 15eb40aedb | |||
| cc3e75dc63 | |||
| eeaf17c857 | |||
| 21a8395142 | |||
| 7d171b1e95 | |||
| d63061fade | |||
| 4664266b8d | |||
| 5003a55aca | |||
| 7225ec29fe | |||
| cf1069e0e1 | |||
| 99ce88228c | |||
| edb62b740b | |||
| 11d4189c8d | |||
| ebbd05dc97 |
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.10.2")]
|
||||
[assembly: AssemblyInformationalVersion("7.10.2")]
|
||||
[assembly: AssemblyFileVersion("7.10.4")]
|
||||
[assembly: AssemblyInformationalVersion("7.10.4")]
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.10.2");
|
||||
private static readonly Version Version = new Version("7.10.4");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -402,7 +402,7 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
|
||||
// Helper to handle named parameters from object properties
|
||||
static Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
static readonly Regex rxParams = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
public static string ProcessParams(string _sql, object[] args_src, List<object> args_dest)
|
||||
{
|
||||
return rxParams.Replace(_sql, m =>
|
||||
@@ -545,7 +545,7 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
|
||||
// Create a command
|
||||
static Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
static readonly Regex rxParamsPrefix = new Regex(@"(?<!@)@\w+", RegexOptions.Compiled);
|
||||
public IDbCommand CreateCommand(IDbConnection connection, string sql, params object[] args)
|
||||
{
|
||||
// Perform named argument replacements
|
||||
@@ -666,8 +666,8 @@ namespace Umbraco.Core.Persistence
|
||||
return ExecuteScalar<T>(sql.SQL, sql.Arguments);
|
||||
}
|
||||
|
||||
Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
static readonly Regex rxSelect = new Regex(@"\A\s*(SELECT|EXECUTE|CALL)\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
static readonly Regex rxFrom = new Regex(@"\A\s*FROM\s", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
string AddSelectClause<T>(string sql)
|
||||
{
|
||||
if (sql.StartsWith(";"))
|
||||
@@ -701,9 +701,9 @@ namespace Umbraco.Core.Persistence
|
||||
return Fetch<T>(sql.SQL, sql.Arguments);
|
||||
}
|
||||
|
||||
static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static readonly Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static readonly Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
static readonly Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
public static bool SplitSqlForPaging(string sql, out string sqlCount, out string sqlSelectRemoved, out string sqlOrderBy)
|
||||
{
|
||||
sqlSelectRemoved = null;
|
||||
@@ -2546,5 +2546,4 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Umbraco.Core.Scoping
|
||||
public NoScope(ScopeProvider scopeProvider)
|
||||
{
|
||||
_scopeProvider = scopeProvider;
|
||||
Timestamp = DateTime.Now;
|
||||
#if DEBUG_SCOPES
|
||||
_scopeProvider.RegisterScope(this);
|
||||
#endif
|
||||
@@ -28,6 +29,8 @@ namespace Umbraco.Core.Scoping
|
||||
private readonly Guid _instanceId = Guid.NewGuid();
|
||||
public Guid InstanceId { get { return _instanceId; } }
|
||||
|
||||
public DateTime Timestamp { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CallContext { get { return false; } }
|
||||
|
||||
|
||||
@@ -374,7 +374,7 @@ namespace Umbraco.Core.Scoping
|
||||
}
|
||||
|
||||
var parent = ParentScope;
|
||||
_scopeProvider.AmbientScope = parent;
|
||||
_scopeProvider.AmbientScope = parent; // might be null = this is how scopes are removed from context objects
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
_scopeProvider.Disposed(this);
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
#if DEBUG_SCOPES
|
||||
using System.Linq;
|
||||
@@ -66,22 +68,38 @@ namespace Umbraco.Core.Scoping
|
||||
// tests, any other things (see https://msdn.microsoft.com/en-us/library/dn458353(v=vs.110).aspx),
|
||||
// but we don't want to make all of our objects serializable since they are *not* meant to be
|
||||
// used in cross-AppDomain scenario anyways.
|
||||
//
|
||||
// in addition, whatever goes into the logical call context is serialized back and forth any
|
||||
// time cross-AppDomain code executes, so if we put an "object" there, we'll can *another*
|
||||
// "object" instance - and so we cannot use a random object as a key.
|
||||
// time cross-AppDomain code executes, so if we put an "object" there, we'll get *another*
|
||||
// "object" instance back - and so we cannot use a random object as a key.
|
||||
//
|
||||
// so what we do is: we register a guid in the call context, and we keep a table mapping those
|
||||
// guids to the actual objects. the guid serializes back and forth without causing any issue,
|
||||
// and we can retrieve the actual objects from the table.
|
||||
// only issue: how are we supposed to clear the table? we can't, really. objects should take
|
||||
// care of de-registering themselves from context.
|
||||
// everything we use does, except the NoScope scope, which just stays there
|
||||
//
|
||||
// during tests, NoScope can to into call context... nothing much we can do about it
|
||||
// so far, the only objects that go into this table are scopes (using ScopeItemKey) and
|
||||
// scope contexts (using ContextItemKey).
|
||||
|
||||
private static readonly object StaticCallContextObjectsLock = new object();
|
||||
private static readonly Dictionary<Guid, object> StaticCallContextObjects
|
||||
= new Dictionary<Guid, object>();
|
||||
|
||||
// normal scopes and scope contexts take greate care removing themselves when disposed, so it
|
||||
// is all safe. OTOH the NoScope *CANNOT* remove itself, this is by design, it *WILL* leak and
|
||||
// there is little (nothing) we can do about it - NoScope exists for backward compatibility
|
||||
// reasons and relying on it is greatly discouraged.
|
||||
//
|
||||
// however... we can *try* at protecting the app against memory leaks, by collecting NoScope
|
||||
// instances that are too old. if anything actually *need* to retain a NoScope instance for
|
||||
// a long time, it will break. but that's probably ok. so: the constants below define how
|
||||
// long a NoScope instance can stay in the table before being removed, and how often we should
|
||||
// collect the table - and collecting happens anytime SetCallContextObject is invoked
|
||||
|
||||
private static readonly TimeSpan StaticCallContextNoScopeLifeSpan = TimeSpan.FromMinutes(30);
|
||||
private static readonly TimeSpan StaticCallContextCollectPeriod = TimeSpan.FromMinutes(4);
|
||||
private static DateTime _staticCallContextLastCollect = DateTime.MinValue;
|
||||
|
||||
|
||||
#if DEBUG_SCOPES
|
||||
public Dictionary<Guid, object> CallContextObjects
|
||||
{
|
||||
@@ -156,6 +174,7 @@ namespace Umbraco.Core.Scoping
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
StaticCallContextObjects.Remove(objectKey);
|
||||
CollectStaticCallContextObjectsLocked();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -171,11 +190,37 @@ namespace Umbraco.Core.Scoping
|
||||
//Logging.LogHelper.Debug<ScopeProvider>("At:\r\n" + Head(Environment.StackTrace, 24));
|
||||
#endif
|
||||
StaticCallContextObjects.Add(objectKey, value);
|
||||
CollectStaticCallContextObjectsLocked();
|
||||
}
|
||||
CallContext.LogicalSetData(key, objectKey);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CollectStaticCallContextObjectsLocked()
|
||||
{
|
||||
// is it time to collect?
|
||||
var now = DateTime.Now;
|
||||
if (now - _staticCallContextLastCollect <= StaticCallContextCollectPeriod)
|
||||
return;
|
||||
|
||||
// disable warning: this method is invoked from within a lock
|
||||
// ReSharper disable InconsistentlySynchronizedField
|
||||
var threshold = now.Add(-StaticCallContextNoScopeLifeSpan);
|
||||
var guids = StaticCallContextObjects
|
||||
.Where(x => x.Value is NoScope noScope && noScope.Timestamp < threshold)
|
||||
.Select(x => x.Key)
|
||||
.ToList();
|
||||
if (guids.Count > 0)
|
||||
{
|
||||
LogHelper.Warn<ScopeProvider>($"Collected {guids.Count} NoScope instances from StaticCallContextObjects.");
|
||||
foreach (var guid in guids)
|
||||
StaticCallContextObjects.Remove(guid);
|
||||
}
|
||||
// ReSharper restore InconsistentlySynchronizedField
|
||||
|
||||
_staticCallContextLastCollect = now;
|
||||
}
|
||||
|
||||
// this is for tests exclusively until we have a proper accessor in v8
|
||||
internal static Func<IDictionary> HttpContextItemsGetter { get; set; }
|
||||
|
||||
|
||||
@@ -76,8 +76,9 @@ namespace Umbraco.Core.Services
|
||||
_locker.EnterWriteLock();
|
||||
foreach (var pair in pairs)
|
||||
{
|
||||
_id2Key.Add(pair.id, new TypedId<Guid>(pair.key, umbracoObjectType));
|
||||
_key2Id.Add(pair.key, new TypedId<int>(pair.id, umbracoObjectType));
|
||||
|
||||
_id2Key[pair.id] = new TypedId<Guid>(pair.key, umbracoObjectType);
|
||||
_key2Id[pair.key] = new TypedId<int>(pair.id, umbracoObjectType);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
||||
@@ -84,27 +84,21 @@
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.trimStart) {
|
||||
|
||||
/** trims the start of the string*/
|
||||
String.prototype.trimStart = function (str) {
|
||||
if (this.startsWith(str)) {
|
||||
return this.substring(str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
if (!String.prototype.trimEnd) {
|
||||
/** trims the start of the string*/
|
||||
String.prototype.trimStart = function (str) {
|
||||
if (this.startsWith(str)) {
|
||||
return this.substring(str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/** trims the end of the string*/
|
||||
String.prototype.trimEnd = function (str) {
|
||||
if (this.endsWith(str)) {
|
||||
return this.substring(0, this.length - str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
/** trims the end of the string*/
|
||||
String.prototype.trimEnd = function (str) {
|
||||
if (this.endsWith(str)) {
|
||||
return this.substring(0, this.length - str.length);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
if (!String.prototype.utf8Encode) {
|
||||
|
||||
@@ -332,4 +326,4 @@
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
+2
-2
@@ -58,7 +58,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
|
||||
|
||||
$scope.renderModel = [];
|
||||
|
||||
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
|
||||
$scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
|
||||
|
||||
//the default pre-values
|
||||
var defaultConfig = {
|
||||
@@ -93,7 +93,7 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
|
||||
$scope.model.config.showOpenButton = ($scope.model.config.showOpenButton === "1" ? true : false);
|
||||
$scope.model.config.showEditButton = ($scope.model.config.showEditButton === "1" ? true : false);
|
||||
$scope.model.config.showPathOnHover = ($scope.model.config.showPathOnHover === "1" ? true : false);
|
||||
|
||||
|
||||
var entityType = $scope.model.config.startNode.type === "member"
|
||||
? "Member"
|
||||
: $scope.model.config.startNode.type === "media"
|
||||
|
||||
-5
@@ -267,11 +267,6 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
|
||||
}
|
||||
|
||||
var notSupported = [
|
||||
"Umbraco.CheckBoxList",
|
||||
"Umbraco.DropDownMultiple",
|
||||
"Umbraco.MacroContainer",
|
||||
"Umbraco.RadioButtonList",
|
||||
"Umbraco.MultipleTextstring",
|
||||
"Umbraco.Tags",
|
||||
"Umbraco.UploadField",
|
||||
"Umbraco.ImageCropper"
|
||||
|
||||
@@ -266,7 +266,7 @@ angular.module("umbraco")
|
||||
|
||||
|
||||
editor.on('ObjectResized', function (e) {
|
||||
var qs = "?width=" + e.width + "&height=" + e.height;
|
||||
var qs = "?width=" + e.width + "&height=" + e.height + "&mode=max";
|
||||
var srcAttr = $(e.target).attr("src");
|
||||
var path = srcAttr.split("?")[0];
|
||||
$(e.target).attr("data-mce-src", path + qs);
|
||||
@@ -384,7 +384,7 @@ 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) {
|
||||
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
|
||||
tinyMceEditor.destroy()
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1035,9 +1035,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7102</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7104</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7102</IISUrl>
|
||||
<IISUrl>http://localhost:7104</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Web.Scheduling;
|
||||
|
||||
namespace Umbraco.Web
|
||||
@@ -21,9 +22,12 @@ namespace Umbraco.Web
|
||||
/// </remarks>
|
||||
public class BatchedDatabaseServerMessenger : DatabaseServerMessenger
|
||||
{
|
||||
private readonly ApplicationContext _appContext;
|
||||
|
||||
public BatchedDatabaseServerMessenger(ApplicationContext appContext, bool enableDistCalls, DatabaseServerMessengerOptions options)
|
||||
: base(appContext, enableDistCalls, options)
|
||||
{
|
||||
_appContext = appContext;
|
||||
Scheduler.Initializing += Scheduler_Initializing;
|
||||
}
|
||||
|
||||
@@ -42,7 +46,7 @@ namespace Umbraco.Web
|
||||
//start the background task runner for processing instructions
|
||||
const int delayMilliseconds = 60000;
|
||||
var instructionProcessingRunner = new BackgroundTaskRunner<IBackgroundTask>("InstructionProcessing", ApplicationContext.ProfilingLogger.Logger);
|
||||
var instructionProcessingTask = new InstructionProcessing(instructionProcessingRunner, this, delayMilliseconds, Options.ThrottleSeconds * 1000);
|
||||
var instructionProcessingTask = new InstructionProcessing(instructionProcessingRunner, this, _appContext.ScopeProvider, delayMilliseconds, Options.ThrottleSeconds * 1000);
|
||||
instructionProcessingRunner.TryAdd(instructionProcessingTask);
|
||||
e.Add(instructionProcessingTask);
|
||||
}
|
||||
@@ -73,18 +77,31 @@ namespace Umbraco.Web
|
||||
private class InstructionProcessing : RecurringTaskBase
|
||||
{
|
||||
private readonly DatabaseServerMessenger _messenger;
|
||||
private readonly IScopeProvider _scopeProvider;
|
||||
|
||||
public InstructionProcessing(IBackgroundTaskRunner<RecurringTaskBase> runner,
|
||||
DatabaseServerMessenger messenger,
|
||||
IScopeProvider scopeProvider,
|
||||
int delayMilliseconds, int periodMilliseconds)
|
||||
: base(runner, delayMilliseconds, periodMilliseconds)
|
||||
{
|
||||
_messenger = messenger;
|
||||
_scopeProvider = scopeProvider;
|
||||
}
|
||||
|
||||
public override bool PerformRun()
|
||||
{
|
||||
_messenger.Sync();
|
||||
// beware!
|
||||
// DatabaseServerMessenger uses _appContext.DatabaseContext.Database without creating
|
||||
// scopes, and since we are running in a background task, there will be no ambient
|
||||
// scope (as would be the case within a web request), and so we would end up creating
|
||||
// (and leaking) a NoScope instance, which is bad - better make sure we have a true
|
||||
// scope here! - see U4-11207
|
||||
using (var scope = _scopeProvider.CreateScope())
|
||||
{
|
||||
_messenger.Sync();
|
||||
scope.Complete();
|
||||
}
|
||||
//return true to repeat
|
||||
return true;
|
||||
}
|
||||
@@ -121,14 +138,17 @@ namespace Umbraco.Web
|
||||
batch.Clear();
|
||||
|
||||
//Write the instructions but only create JSON blobs with a max instruction count equal to MaxProcessingInstructionCount
|
||||
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
|
||||
using (var scope = _appContext.ScopeProvider.CreateScope())
|
||||
{
|
||||
WriteInstructions(instructionsBatch);
|
||||
foreach (var instructionsBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
|
||||
{
|
||||
WriteInstructions(scope, instructionsBatch);
|
||||
}
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void WriteInstructions(IEnumerable<RefreshInstruction> instructions)
|
||||
private void WriteInstructions(IScope scope, IEnumerable<RefreshInstruction> instructions)
|
||||
{
|
||||
var dto = new CacheInstructionDto
|
||||
{
|
||||
@@ -137,8 +157,7 @@ namespace Umbraco.Web
|
||||
OriginIdentity = LocalIdentity,
|
||||
InstructionCount = instructions.Sum(x => x.JsonIdCount)
|
||||
};
|
||||
|
||||
ApplicationContext.DatabaseContext.Database.Insert(dto);
|
||||
scope.Database.Insert(dto);
|
||||
}
|
||||
|
||||
protected ICollection<RefreshInstructionEnvelope> GetBatch(bool create)
|
||||
@@ -179,16 +198,19 @@ namespace Umbraco.Web
|
||||
if (batch == null)
|
||||
{
|
||||
//only write the json blob with a maximum count of the MaxProcessingInstructionCount
|
||||
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
|
||||
using (var scope = _appContext.ScopeProvider.CreateScope())
|
||||
{
|
||||
WriteInstructions(maxBatch);
|
||||
foreach (var maxBatch in instructions.InGroupsOf(Options.MaxProcessingInstructionCount))
|
||||
{
|
||||
WriteInstructions(scope, maxBatch);
|
||||
}
|
||||
scope.Complete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
batch.Add(new RefreshInstructionEnvelope(servers, refresher, instructions));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core;
|
||||
@@ -104,10 +102,9 @@ namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
base.ConfigureForDisplay(preValues);
|
||||
|
||||
var asDictionary = preValues.PreValuesAsDictionary.ToDictionary(x => x.Key, x => x.Value.Value);
|
||||
if (asDictionary.ContainsKey("hideLabel"))
|
||||
if (preValues.PreValuesAsDictionary.ContainsKey("hideLabel"))
|
||||
{
|
||||
var boolAttempt = asDictionary["hideLabel"].TryConvertTo<bool>();
|
||||
var boolAttempt = preValues.PreValuesAsDictionary["hideLabel"].Value.TryConvertTo<bool>();
|
||||
if (boolAttempt.Success)
|
||||
{
|
||||
HideLabel = boolAttempt.Result;
|
||||
@@ -120,10 +117,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
public override string ConvertDbToString(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
|
||||
{
|
||||
// Convert / validate value
|
||||
if (property.Value == null || string.IsNullOrWhiteSpace(property.Value.ToString()))
|
||||
if (property.Value == null)
|
||||
return string.Empty;
|
||||
|
||||
var value = JsonConvert.DeserializeObject<List<object>>(property.Value.ToString());
|
||||
var propertyValue = property.Value.ToString();
|
||||
if (string.IsNullOrWhiteSpace(propertyValue))
|
||||
return string.Empty;
|
||||
|
||||
var value = JsonConvert.DeserializeObject<List<object>>(propertyValue);
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
@@ -182,11 +183,8 @@ namespace Umbraco.Web.PropertyEditors
|
||||
}
|
||||
}
|
||||
|
||||
// Update the value on the property
|
||||
property.Value = JsonConvert.SerializeObject(value);
|
||||
|
||||
// Pass the call down
|
||||
return base.ConvertDbToString(property, propertyType, dataTypeService);
|
||||
// Return the serialized value
|
||||
return JsonConvert.SerializeObject(value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -195,10 +193,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
|
||||
public override object ConvertDbToEditor(Property property, PropertyType propertyType, IDataTypeService dataTypeService)
|
||||
{
|
||||
if (property.Value == null || string.IsNullOrWhiteSpace(property.Value.ToString()))
|
||||
if (property.Value == null)
|
||||
return string.Empty;
|
||||
|
||||
var value = JsonConvert.DeserializeObject<List<object>>(property.Value.ToString());
|
||||
var propertyValue = property.Value.ToString();
|
||||
if (string.IsNullOrWhiteSpace(propertyValue))
|
||||
return string.Empty;
|
||||
|
||||
var value = JsonConvert.DeserializeObject<List<object>>(propertyValue);
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
@@ -260,11 +262,8 @@ namespace Umbraco.Web.PropertyEditors
|
||||
}
|
||||
}
|
||||
|
||||
// Update the value on the property
|
||||
property.Value = JsonConvert.SerializeObject(value);
|
||||
|
||||
// Pass the call down
|
||||
return base.ConvertDbToEditor(property, propertyType, dataTypeService);
|
||||
// Return the strongly-typed object, Umbraco will handle the JSON serializing/parsing, then Angular can handle it directly
|
||||
return value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -273,10 +272,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
|
||||
public override object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue)
|
||||
{
|
||||
if (editorValue.Value == null || string.IsNullOrWhiteSpace(editorValue.Value.ToString()))
|
||||
if (editorValue.Value == null)
|
||||
return null;
|
||||
|
||||
var value = JsonConvert.DeserializeObject<List<object>>(editorValue.Value.ToString());
|
||||
var rawValue = editorValue.Value.ToString();
|
||||
if (string.IsNullOrWhiteSpace(rawValue))
|
||||
return null;
|
||||
|
||||
var value = JsonConvert.DeserializeObject<List<object>>(rawValue);
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
|
||||
+3
-1
@@ -9,6 +9,8 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
public MultipleContentPickerParameterEditor()
|
||||
{
|
||||
Configuration.Add("multiPicker", "1");
|
||||
Configuration.Add("minNumber",0 );
|
||||
Configuration.Add("maxNumber", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,12 @@ namespace Umbraco.Web.Trees
|
||||
return null;
|
||||
|
||||
var treeNode = GetSingleTreeNode(e, parentId, queryStrings);
|
||||
if (treeNode == null)
|
||||
{
|
||||
//this means that the user has NO access to this node via permissions! They at least need to have browse permissions to see
|
||||
//the node so we need to return null;
|
||||
return null;
|
||||
}
|
||||
if (hasPathAccess == false)
|
||||
{
|
||||
treeNode.AdditionalData["noAccess"] = true;
|
||||
@@ -189,8 +195,7 @@ namespace Umbraco.Web.Trees
|
||||
{
|
||||
// try to parse id as an integer else use GetEntityFromId
|
||||
// which will grok Guids, Udis, etc and let use obtain the id
|
||||
int entityId;
|
||||
if (int.TryParse(id, out entityId) == false)
|
||||
if (int.TryParse(id, out var entityId) == false)
|
||||
{
|
||||
var entity = GetEntityFromId(id);
|
||||
if (entity == null)
|
||||
@@ -198,15 +203,6 @@ namespace Umbraco.Web.Trees
|
||||
entityId = entity.Id;
|
||||
}
|
||||
|
||||
// if a request is made for the root node but user has no access to
|
||||
// root node, return start nodes instead
|
||||
if (entityId == Constants.System.Root && UserStartNodes.Contains(Constants.System.Root) == false)
|
||||
{
|
||||
return UserStartNodes.Length > 0
|
||||
? Services.EntityService.GetAll(UmbracoObjectType, UserStartNodes)
|
||||
: Enumerable.Empty<IUmbracoEntity>();
|
||||
}
|
||||
|
||||
return Services.EntityService.GetChildren(entityId, UmbracoObjectType).ToArray();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user