Skip to content

Commit

Permalink
Use IsValidJsonString, inplace of DetectIsJson - more reliable. (#567)
Browse files Browse the repository at this point in the history
* Use IsValidJsonString, inplace of DetectIsJson - more reliable.

* Move to a TryParseValidJsonString, to reduce the number of times we parse the json.
  • Loading branch information
KevinJump authored Nov 9, 2023
1 parent 5c39f55 commit 583c0ba
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 95 deletions.
10 changes: 6 additions & 4 deletions uSync.Community.Contrib/Mappers/ContentmentContentBlocks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;

using uSync.Core;
using uSync.Core.Dependency;
using uSync.Core.Mapping;

Expand Down Expand Up @@ -55,10 +55,12 @@ protected override string ProcessValues(JToken jsonValue, string editorAlias, Fu
public override IEnumerable<uSyncDependency> GetDependencies(object value, string editorAlias, DependencyFlags flags)
{
var stringValue = GetValueAs<string>(value);
if (string.IsNullOrWhiteSpace(stringValue) || !stringValue.DetectIsJson()) return Enumerable.Empty<uSyncDependency>();

var elements = JsonConvert.DeserializeObject<JArray>(stringValue);
if (elements == null || !elements.Any()) return Enumerable.Empty<uSyncDependency>();
if (stringValue.TryParseValidJsonString(out JArray elements) is false)
return Enumerable.Empty<uSyncDependency>();

if (elements == null || !elements.Any())
return Enumerable.Empty<uSyncDependency>();

var dependencies = new List<uSyncDependency>();

Expand Down
48 changes: 47 additions & 1 deletion uSync.Core/Extensions/JsonExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.Net.Http.Headers;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
Expand Down Expand Up @@ -111,6 +112,51 @@ private static JToken ExpandStringValue(string stringValue)
return stringValue.GetJsonTokenValue();
}

public static bool IsValidJsonString(this string value)
{
if (string.IsNullOrWhiteSpace(value) || !value.DetectIsJson())
return false;

// umbraco thinks it's json, but is it ?

try
{
JToken.Parse(value);
return true;
}
catch {
return false;
}
}

public static bool TryParseValidJsonString(this string value, out JToken token)
=> TryParseValidJsonString<JToken>(value, out token);

/// <summary>
/// parse a value and return the JSON - only if it's valid JSON
/// </summary>
/// <remarks>
/// this value will return false for strings that don't look like json strings (e.g "hello" is false)
/// </remarks>
public static bool TryParseValidJsonString<TResult>(this string value, out TResult result)
where TResult : JToken
{
result = default;
if (string.IsNullOrWhiteSpace(value) || !value.DetectIsJson())
return false;

try
{
result = JsonConvert.DeserializeObject<TResult>(value);
return true;
}
catch
{
return false;
}
}



public static JToken GetJTokenFromObject(this object value)
{
Expand Down Expand Up @@ -140,4 +186,4 @@ public static TObject GetValueAs<TObject>(this object value)
public static bool IsAngularExpression(this string value)
=> value.StartsWith("{{") && value.EndsWith("}}");
}
}
}
14 changes: 4 additions & 10 deletions uSync.Core/Mapping/Mappers/BlockListMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;

using uSync.Core.Dependency;

Expand Down Expand Up @@ -40,26 +39,21 @@ public BlockListMapper(IEntityService entityService,
protected override JToken GetImportProperty(object value)
{
if (value == null) return null;

var stringValue = value.GetValueAs<string>();
if (stringValue == null || !stringValue.DetectIsJson())

if (stringValue.TryParseValidJsonString(out JToken tokenValue) is false)
return stringValue;

// we have to get the json, the serialize the json,
// this is to make sure we don't serizlize any formatting
// (like indented formatting). because that would
// register changes that are not there.
var b = JsonConvert.SerializeObject(value.GetJTokenFromObject(), Formatting.None);

return b;
return JsonConvert.SerializeObject(tokenValue, Formatting.None);
}


protected override JToken GetExportProperty(string value)
{
if (string.IsNullOrWhiteSpace(value) || !value.DetectIsJson()) return value;
return value.GetJsonTokenValue();
}
=> value.TryParseValidJsonString(out JToken tokenValue) is true ? tokenValue : value;

protected override string ProcessValues(JToken jsonValue, string editorAlias, Func<JObject, IContentType, JObject> GetPropertiesMethod)
{
Expand Down
71 changes: 26 additions & 45 deletions uSync.Core/Mapping/Mappers/ImagePathMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,30 +74,25 @@ public override string GetExportValue(object value, string editorAlias)
var stringValue = value?.ToString();
if (string.IsNullOrWhiteSpace(stringValue)) return stringValue;

if (stringValue.DetectIsJson())
if (stringValue.TryParseValidJsonString<JObject>(out JObject json) is false)
return StripSitePath(stringValue);

// json,
if (json != null)
{
// json,
var json = JsonConvert.DeserializeObject<JObject>(stringValue);
if (json != null)
var source = json.Value<string>("src");
if (!string.IsNullOrWhiteSpace(source))
{
var source = json.Value<string>("src");
if (!string.IsNullOrWhiteSpace(source))
{
// strip any virtual directory stuff from it.
json["src"] = StripSitePath(source);
return JsonConvert.SerializeObject(json);
}
// strip any virtual directory stuff from it.
json["src"] = StripSitePath(source);
return JsonConvert.SerializeObject(json);
}

// we always reserialize if we can, because you can get inconsitancies,
// and spaces in the json (especially from the starterkit)
// this just ensures it looks the same across sites (where possible).
return JsonConvert.SerializeObject(json, Formatting.Indented);
}


// else .
return StripSitePath(stringValue);
// we always reserialize if we can, because you can get inconsitancies,
// and spaces in the json (especially from the starterkit)
// this just ensures it looks the same across sites (where possible).
return JsonConvert.SerializeObject(json, Formatting.Indented);
}

private string StripSitePath(string filepath)
Expand Down Expand Up @@ -175,26 +170,17 @@ private string GetMediaFolderSetting(string umbracoMediaPath)
public override string GetImportValue(string value, string editorAlias)
{
var stringValue = value?.ToString();
if (string.IsNullOrWhiteSpace(stringValue)) return stringValue;
if (string.IsNullOrWhiteSpace(stringValue) is true) return stringValue;

if (stringValue.DetectIsJson())
{
// json,
var json = JsonConvert.DeserializeObject<JObject>(stringValue);
if (json != null)
{
var source = json.Value<string>("src");
if (!string.IsNullOrWhiteSpace(source))
{
// strip any virtual directory stuff from it.
json["src"] = PrePendSitePath(source);
return JsonConvert.SerializeObject(json);
}
}
}
else
{
if (stringValue.TryParseValidJsonString(out JObject json) is false)
return PrePendSitePath(stringValue);

var source = json.Value<string>("src");
if (string.IsNullOrWhiteSpace(source) is false)
{
// strip any virtual directory stuff from it.
json["src"] = PrePendSitePath(source);
return JsonConvert.SerializeObject(json);
}

return stringValue;
Expand Down Expand Up @@ -228,15 +214,10 @@ public override IEnumerable<uSyncDependency> GetDependencies(object value, strin

private string GetImagePath(string stringValue)
{
if (stringValue.DetectIsJson())
if (stringValue.TryParseValidJsonString(out JObject json))
{
// json,
var json = JsonConvert.DeserializeObject<JObject>(stringValue);
if (json != null)
{
var source = json.Value<string>("src");
if (!string.IsNullOrWhiteSpace(source)) return source;
}
var source = json.Value<string>("src");
if (string.IsNullOrWhiteSpace(source) is false) return source;
}
else
{
Expand Down
4 changes: 1 addition & 3 deletions uSync.Core/Mapping/Mappers/MacroMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,8 @@ public override IEnumerable<uSyncDependency> GetDependencies(object value, strin

private MacroValue LoadMacroValue(string macroString)
{
if (!macroString.DetectIsJson())
{
if (macroString.IsValidJsonString() is false)
return LoadFromMarkup(macroString);
}

return JsonConvert.DeserializeObject<MacroValue>(macroString);
}
Expand Down
16 changes: 5 additions & 11 deletions uSync.Core/Mapping/Mappers/MediaPicker3Mapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ public MediaPicker3Mapper(IEntityService entityService) : base(entityService)
public override string GetExportValue(object value, string editorAlias)
{
var stringValue = value?.ToString();
if (string.IsNullOrEmpty(stringValue)) return null;
if (string.IsNullOrEmpty(stringValue) is true) return null;

if (!stringValue.DetectIsJson()) return stringValue;
if (stringValue.TryParseValidJsonString(out JArray json) is false)
return stringValue;

// re-formatting the json in the picker.
//
Expand All @@ -45,29 +46,22 @@ public override string GetExportValue(object value, string editorAlias)

try
{
var json = JsonConvert.DeserializeObject<JArray>(value.ToString());
if (json != null)
return JsonConvert.SerializeObject(json, Formatting.Indented);
return JsonConvert.SerializeObject(json, Formatting.Indented);
}
catch
{
return stringValue;
}

return stringValue;

}


public override IEnumerable<uSyncDependency> GetDependencies(object value, string editorAlias, DependencyFlags flags)
{
// validate string
var stringValue = value?.ToString();
if (string.IsNullOrWhiteSpace(stringValue) || !stringValue.DetectIsJson())
if (!stringValue.TryParseValidJsonString(out JArray images) is false)
return Enumerable.Empty<uSyncDependency>();

// convert to an array.
var images = JsonConvert.DeserializeObject<JArray>(value.ToString());
if (images == null || !images.Any())
return Enumerable.Empty<uSyncDependency>();

Expand Down
3 changes: 1 addition & 2 deletions uSync.Core/Mapping/Mappers/NestedContentMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ protected override string ProcessValues(JToken jsonValue, string editorAlias, Fu
public override IEnumerable<uSyncDependency> GetDependencies(object value, string editorAlias, DependencyFlags flags)
{
var stringValue = GetValueAs<string>(value);
if (string.IsNullOrWhiteSpace(stringValue) || !stringValue.DetectIsJson())
if (stringValue.TryParseValidJsonString(out JArray nestedJson) is false)
return Enumerable.Empty<uSyncDependency>();

var nestedJson = JsonConvert.DeserializeObject<JArray>(stringValue);
if (nestedJson == null || !nestedJson.Any())
return Enumerable.Empty<uSyncDependency>();

Expand Down
2 changes: 1 addition & 1 deletion uSync.Core/Mapping/Mappers/RepeatableValueMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public RepeatableValueMapper(IEntityService entityService)

public override string GetImportValue(string value, string editorAlias)
{
if (value.DetectIsJson())
if (value.IsValidJsonString() is true)
{
try
{
Expand Down
6 changes: 3 additions & 3 deletions uSync.Core/Mapping/SyncValueMapperCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ public object GetImportValue(string value, string editorAlias)
/// </summary>
private string GetCleanFlatJson(string stringValue)
{
if (string.IsNullOrWhiteSpace(stringValue) || !stringValue.DetectIsJson()) return stringValue;

if (stringValue.TryParseValidJsonString(out JToken result) is false)
return stringValue;
try
{
return JsonConvert.SerializeObject(JsonConvert.DeserializeObject<JToken>(stringValue));
return JsonConvert.SerializeObject(result);
}
catch
{
Expand Down
4 changes: 2 additions & 2 deletions uSync.Core/Serialization/Serializers/ContentSerializerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Microsoft.Extensions.Logging;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
Expand Down Expand Up @@ -660,9 +661,8 @@ protected string GetExportValue(object value, IPropertyType propertyType, string
// TODO: in a perfect world, this is the best answer, don't escape any buried JSON in anything
// but there might be a couple of property value converters that don't like their nested JSON
// to not be escaped so we would need to do proper testing.
if (exportValue.DetectIsJson() && !exportValue.IsAngularExpression())
if (exportValue.TryParseValidJsonString(out JToken tokenValue) is true)
{
var tokenValue = exportValue.GetJsonTokenValue().ExpandAllJsonInToken();
return JsonConvert.SerializeObject(tokenValue, Formatting.Indented);
}
logger.LogTrace("Export Value {PropertyEditorAlias} {exportValue}", propertyType.PropertyEditorAlias, exportValue);
Expand Down
23 changes: 11 additions & 12 deletions uSync.Core/Serialization/Serializers/MediaSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ protected override SyncAttempt<IMedia> DeserializeCore(XElement node, SyncSerial
}

var saveAttempt = _mediaService.Save(item);
if (!saveAttempt.Success) {
if (!saveAttempt.Success)
{
var errors = saveAttempt.Result?.EventMessages?.FormatMessages() ?? "";
return SyncAttempt<IMedia>.Fail(item.Name, item, ChangeType.Fail, errors, saveAttempt.Exception);
}
Expand Down Expand Up @@ -194,19 +195,17 @@ private XElement SerializeFileHash(IMedia item)

private string GetFilePath(string value)
{
if (value.DetectIsJson())
{
// image cropper.
var imageCrops = JsonConvert.DeserializeObject<ImageCropperValue>(value, new JsonSerializerSettings
{
Culture = CultureInfo.InvariantCulture,
FloatParseHandling = FloatParseHandling.Decimal
});
if (value.IsValidJsonString() is false)
return value;

return imageCrops.Src;
}
// image cropper.
var imageCrops = JsonConvert.DeserializeObject<ImageCropperValue>(value, new JsonSerializerSettings
{
Culture = CultureInfo.InvariantCulture,
FloatParseHandling = FloatParseHandling.Decimal
});

return value;
return imageCrops.Src;
}

protected override Attempt<IMedia> CreateItem(string alias, ITreeEntity parent, string itemType)
Expand Down
2 changes: 1 addition & 1 deletion uSync.Core/Tracking/SyncXmlTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ private IEnumerable<uSyncChange> CompareNode(XElement target, XElement source, s

private uSyncChange Compare(string target, string source, string path, string name, bool maskValue)
{
if (source.DetectIsJson())
if (source.IsValidJsonString() is true)
{
return JsonChange(target, source, path, name, maskValue);
}
Expand Down
Loading

0 comments on commit 583c0ba

Please sign in to comment.