mirror of https://github.com/Squidex/squidex.git
Browse Source
# Conflicts: # src/Squidex.Domain.Apps.Entities/Backup/IRestoreGrain.cs # src/Squidex.Domain.Apps.Entities/Backup/RestoreGrain.cs # src/Squidex/Areas/Api/Controllers/Backups/RestoreController.cspull/311/head
19 changed files with 560 additions and 114 deletions
@ -1,41 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.IO; |
|||
using Newtonsoft.Json; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup |
|||
{ |
|||
public static class BackupSerializer |
|||
{ |
|||
private static readonly JsonSerializer JsonSerializer = JsonSerializer.CreateDefault(); |
|||
|
|||
public static void SerializeAsJson<T>(this Stream stream, T value) |
|||
{ |
|||
using (var writer = new StreamWriter(stream)) |
|||
{ |
|||
JsonSerializer.Serialize(writer, value); |
|||
} |
|||
} |
|||
|
|||
public static T DeserializeAsJson<T>(this Stream stream) |
|||
{ |
|||
using (var reader = new StreamReader(stream)) |
|||
{ |
|||
return (T)JsonSerializer.Deserialize(reader, typeof(T)); |
|||
} |
|||
} |
|||
|
|||
public static void DeserializeAsJson<T>(this Stream stream, T result) |
|||
{ |
|||
using (var reader = new StreamReader(stream)) |
|||
{ |
|||
JsonSerializer.Populate(reader, result); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,170 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Newtonsoft.Json.Linq; |
|||
using Squidex.Infrastructure; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup |
|||
{ |
|||
public sealed class GuidMapper |
|||
{ |
|||
private static readonly int GuidLength = Guid.Empty.ToString().Length; |
|||
private readonly List<(JObject Source, string NewKey, string OldKey)> mappings = new List<(JObject Source, string NewKey, string OldKey)>(); |
|||
private readonly Dictionary<Guid, Guid> oldToNewGuid = new Dictionary<Guid, Guid>(); |
|||
private readonly Dictionary<Guid, Guid> newToOldGuid = new Dictionary<Guid, Guid>(); |
|||
|
|||
public Guid NewGuid(Guid oldGuid) |
|||
{ |
|||
return oldToNewGuid.GetOrDefault(oldGuid); |
|||
} |
|||
|
|||
public Guid OldGuid(Guid newGuid) |
|||
{ |
|||
return newToOldGuid.GetOrDefault(newGuid); |
|||
} |
|||
|
|||
public string NewGuidString(string key) |
|||
{ |
|||
if (Guid.TryParse(key, out var guid)) |
|||
{ |
|||
return GenerateNewGuid(guid).ToString(); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
|
|||
public JToken NewGuids(JToken jToken) |
|||
{ |
|||
var result = NewGuidsCore(jToken); |
|||
|
|||
if (mappings.Count > 0) |
|||
{ |
|||
foreach (var mapping in mappings) |
|||
{ |
|||
if (mapping.Source.TryGetValue(mapping.OldKey, out var value)) |
|||
{ |
|||
mapping.Source.Remove(mapping.OldKey); |
|||
mapping.Source[mapping.NewKey] = value; |
|||
} |
|||
} |
|||
|
|||
mappings.Clear(); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
private JToken NewGuidsCore(JToken jToken) |
|||
{ |
|||
switch (jToken.Type) |
|||
{ |
|||
case JTokenType.String: |
|||
if (TryConvertString(jToken.ToString(), out var result)) |
|||
{ |
|||
return result; |
|||
} |
|||
|
|||
break; |
|||
case JTokenType.Guid: |
|||
return GenerateNewGuid((Guid)jToken); |
|||
case JTokenType.Object: |
|||
NewGuidsCore((JObject)jToken); |
|||
break; |
|||
case JTokenType.Array: |
|||
NewGuidsCore((JArray)jToken); |
|||
break; |
|||
} |
|||
|
|||
return jToken; |
|||
} |
|||
|
|||
private void NewGuidsCore(JArray jArray) |
|||
{ |
|||
for (var i = 0; i < jArray.Count; i++) |
|||
{ |
|||
jArray[i] = NewGuidsCore(jArray[i]); |
|||
} |
|||
} |
|||
|
|||
private void NewGuidsCore(JObject jObject) |
|||
{ |
|||
foreach (var jProperty in jObject.Properties()) |
|||
{ |
|||
var newValue = NewGuidsCore(jProperty.Value); |
|||
|
|||
if (!ReferenceEquals(newValue, jProperty.Value)) |
|||
{ |
|||
jProperty.Value = newValue; |
|||
} |
|||
|
|||
if (TryConvertString(jProperty.Name, out var newKey)) |
|||
{ |
|||
mappings.Add((jObject, newKey, jProperty.Name)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private bool TryConvertString(string value, out string result) |
|||
{ |
|||
return TryGenerateNewGuidString(value, out result) || TryGenerateNewNamedId(value, out result); |
|||
} |
|||
|
|||
private bool TryGenerateNewGuidString(string value, out string result) |
|||
{ |
|||
result = null; |
|||
|
|||
if (value.Length == GuidLength) |
|||
{ |
|||
if (Guid.TryParse(value, out var guid)) |
|||
{ |
|||
var newGuid = GenerateNewGuid(guid); |
|||
|
|||
result = newGuid.ToString(); |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private bool TryGenerateNewNamedId(string value, out string result) |
|||
{ |
|||
result = null; |
|||
|
|||
if (value.Length > GuidLength && value[GuidLength] == ',') |
|||
{ |
|||
if (Guid.TryParse(value.Substring(0, GuidLength), out var guid)) |
|||
{ |
|||
var newGuid = GenerateNewGuid(guid); |
|||
|
|||
result = newGuid + value.Substring(GuidLength); |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
private Guid GenerateNewGuid(Guid oldGuid) |
|||
{ |
|||
return oldToNewGuid.GetOrAdd(oldGuid, GuidGenerator); |
|||
} |
|||
|
|||
private Guid GuidGenerator(Guid oldGuid) |
|||
{ |
|||
var newGuid = Guid.NewGuid(); |
|||
|
|||
newToOldGuid[newGuid] = oldGuid; |
|||
|
|||
return newGuid; |
|||
} |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System.Threading.Tasks; |
|||
using Orleans; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities |
|||
{ |
|||
public interface ICleanableAppGrain : IGrainWithGuidKey |
|||
{ |
|||
Task ClearAsync(); |
|||
} |
|||
} |
|||
@ -0,0 +1,161 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Newtonsoft.Json.Linq; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Domain.Apps.Entities.Backup |
|||
{ |
|||
public class GuidMapperTests |
|||
{ |
|||
private readonly Guid id1 = Guid.NewGuid(); |
|||
private readonly Guid id2 = Guid.NewGuid(); |
|||
private readonly GuidMapper map = new GuidMapper(); |
|||
|
|||
[Fact] |
|||
public void Should_map_guid_string_if_valid() |
|||
{ |
|||
var result = map.NewGuidString(id1.ToString()); |
|||
|
|||
Assert.Equal(map.NewGuid(id1).ToString(), result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_null_if_mapping_invalid_guid_string() |
|||
{ |
|||
var result = map.NewGuidString("invalid"); |
|||
|
|||
Assert.Null(result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_null_if_mapping_null_guid_string() |
|||
{ |
|||
var result = map.NewGuidString(null); |
|||
|
|||
Assert.Null(result); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_guid() |
|||
{ |
|||
var result = map.NewGuids(id1); |
|||
|
|||
Assert.Equal(map.NewGuid(id1), result.Value<Guid>()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_return_old_guid() |
|||
{ |
|||
var newGuid = map.NewGuids(id1).Value<Guid>(); |
|||
|
|||
Assert.Equal(id1, map.OldGuid(newGuid)); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_guid_string() |
|||
{ |
|||
var result = map.NewGuids(id1.ToString()); |
|||
|
|||
Assert.Equal(map.NewGuid(id1).ToString(), result.Value<string>()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_named_id() |
|||
{ |
|||
var result = map.NewGuids($"{id1},name"); |
|||
|
|||
Assert.Equal($"{map.NewGuid(id1)},name", result.Value<string>()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_array_with_guid() |
|||
{ |
|||
var obj = |
|||
new JObject( |
|||
new JProperty("k", |
|||
new JArray(id1, id1, id2))); |
|||
|
|||
map.NewGuids(obj); |
|||
|
|||
Assert.Equal(map.NewGuid(id1), obj["k"][0].Value<Guid>()); |
|||
Assert.Equal(map.NewGuid(id1), obj["k"][1].Value<Guid>()); |
|||
Assert.Equal(map.NewGuid(id2), obj["k"][2].Value<Guid>()); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_objects_with_guid_keys() |
|||
{ |
|||
var obj = |
|||
new JObject( |
|||
new JProperty("k", |
|||
new JObject( |
|||
new JProperty(id1.ToString(), id1), |
|||
new JProperty(id2.ToString(), id2)))); |
|||
|
|||
map.NewGuids(obj); |
|||
|
|||
Assert.Equal(map.NewGuid(id1), obj["k"].Value<Guid>(map.NewGuid(id1).ToString())); |
|||
Assert.Equal(map.NewGuid(id2), obj["k"].Value<Guid>(map.NewGuid(id2).ToString())); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_objects_with_guid() |
|||
{ |
|||
var obj = |
|||
new JObject( |
|||
new JProperty("k", |
|||
new JObject( |
|||
new JProperty("v1", id1), |
|||
new JProperty("v2", id1), |
|||
new JProperty("v3", id2)))); |
|||
|
|||
map.NewGuids(obj); |
|||
|
|||
Assert.Equal(map.NewGuid(id1), obj["k"].Value<Guid>("v1")); |
|||
Assert.Equal(map.NewGuid(id1), obj["k"].Value<Guid>("v2")); |
|||
Assert.Equal(map.NewGuid(id2), obj["k"].Value<Guid>("v3")); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_objects_with_guid_string() |
|||
{ |
|||
var obj = |
|||
new JObject( |
|||
new JProperty("k", |
|||
new JObject( |
|||
new JProperty("v1", id1.ToString()), |
|||
new JProperty("v2", id1.ToString()), |
|||
new JProperty("v3", id2.ToString())))); |
|||
|
|||
map.NewGuids(obj); |
|||
|
|||
Assert.Equal(map.NewGuid(id1).ToString(), obj["k"].Value<string>("v1")); |
|||
Assert.Equal(map.NewGuid(id1).ToString(), obj["k"].Value<string>("v2")); |
|||
Assert.Equal(map.NewGuid(id2).ToString(), obj["k"].Value<string>("v3")); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_map_objects_with_named_id() |
|||
{ |
|||
var obj = |
|||
new JObject( |
|||
new JProperty("k", |
|||
new JObject( |
|||
new JProperty("v1", $"{id1},v1"), |
|||
new JProperty("v2", $"{id1},v2"), |
|||
new JProperty("v3", $"{id2},v3")))); |
|||
|
|||
map.NewGuids(obj); |
|||
|
|||
Assert.Equal($"{map.NewGuid(id1).ToString()},v1", obj["k"].Value<string>("v1")); |
|||
Assert.Equal($"{map.NewGuid(id1).ToString()},v2", obj["k"].Value<string>("v2")); |
|||
Assert.Equal($"{map.NewGuid(id2).ToString()},v3", obj["k"].Value<string>("v3")); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue