-
-
Save skttl/5b2d543c4871b5bfbd28deb93ff2c9e6 to your computer and use it in GitHub Desktop.
FixNestedContentKeys
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Newtonsoft.Json; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Web.Http; | |
using Umbraco.Core; | |
using Umbraco.Core.Logging; | |
using Umbraco.Core.Models; | |
using Umbraco.Web.WebApi; | |
namespace MyProject.Core | |
{ | |
public class FixController : UmbracoApiController | |
{ | |
private List<ContentTypeWithNestedContent> _contentTypes; | |
public FixController() | |
{ | |
_contentTypes = GetContentTypesAndTheirNestedContentPropertyAliases(); | |
} | |
[HttpGet] | |
public IHttpActionResult ResetKeys() | |
{ | |
//return InternalServerError(new Exception("Resetting keys is disabled")); | |
var contentTypeIds = _contentTypes.Select(x => x.Id); | |
foreach (var contentTypeId in contentTypeIds) | |
{ | |
var nodes = Services.ContentService.GetPagedOfType(contentTypeId, 0, int.MaxValue, out long totalNodes, null, null); | |
foreach (var node in nodes) | |
{ | |
ResetKeys(node); | |
} | |
} | |
return Ok(); | |
} | |
/// <summary> | |
/// Gets nested content values on an IContent, resets their keys and save/publish the node when done | |
/// </summary> | |
/// <param name="node"></param> | |
private void ResetKeys(IContent node) | |
{ | |
if (node == null) return; | |
Logger.Info<FixController>("Resetting keys on {id}: {name}", node.Id, node.Name); | |
var aliases = GetNestedContentPropertyAliasesByContentTypeAlias(node.ContentType.Alias); | |
foreach (var alias in aliases) | |
{ | |
if (node.HasProperty(alias)) | |
{ | |
var input = node.GetValue<string>(alias); | |
var output = ResetKeys(input); | |
if (input != output) | |
{ | |
node.SetValue(alias, output); | |
} | |
} | |
} | |
if (node.IsDirty()) | |
{ | |
// save or publish the node | |
if (node.Published) | |
{ | |
Services.ContentService.SaveAndPublish(node); | |
} | |
else | |
{ | |
Services.ContentService.Save(node); | |
} | |
} | |
} | |
/// <summary> | |
/// Takes a serialized nested content value, reset its key, and loops through any nested nested content values. | |
/// </summary> | |
/// <param name="input"></param> | |
/// <returns></returns> | |
private string ResetKeys(string input) | |
{ | |
if (input == null) return input; | |
try | |
{ | |
// get the nested content value, deserialize the string | |
var nestedItems = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(input); | |
// only do anything if there actually is nested content items inside | |
if (nestedItems != null && nestedItems.Count > 0) | |
{ | |
// loop through the nested items, resetting the key | |
nestedItems.ForEach(item => | |
{ | |
var oldKey = item["key"]; | |
var newKey = Guid.NewGuid().ToString(); | |
item["key"] = newKey; | |
var aliases = GetNestedContentPropertyAliasesByContentTypeAlias(item["ncContentTypeAlias"]); | |
foreach (var alias in aliases) | |
{ | |
if (item.ContainsKey(alias)) | |
{ | |
item[alias] = ResetKeys(item[alias]); | |
} | |
} | |
Logger.Info<FixController>("Converting {name} from {oldKey} to {newKey}", item["name"], oldKey, newKey); | |
}); | |
return JsonConvert.SerializeObject(nestedItems); | |
} | |
} | |
catch (Exception ex) | |
{ | |
Logger.Error<FixController>(ex); | |
Logger.Error<FixController>("Failed converting {input}", input); | |
} | |
return input; | |
} | |
/// <summary> | |
/// Gets content types containing Nested Content properties | |
/// </summary> | |
/// <returns></returns> | |
private List<ContentTypeWithNestedContent> GetContentTypesAndTheirNestedContentPropertyAliases() | |
{ | |
var result = new List<ContentTypeWithNestedContent>(); | |
var contentTypes = Services.ContentTypeService.GetAll(); | |
foreach (var contentType in contentTypes) | |
{ | |
var nestedContentPropertyTypes = contentType.CompositionPropertyTypes.Where(x => x.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.NestedContent)).ToList(); | |
if (nestedContentPropertyTypes.Any()) | |
{ | |
result.Add(new ContentTypeWithNestedContent() | |
{ | |
Id = contentType.Id, | |
Alias = contentType.Alias, | |
NestedContentPropertyAliases = nestedContentPropertyTypes.Select(x => x.Alias).ToList() | |
}); | |
} | |
} | |
return result; | |
} | |
/// <summary> | |
/// Gets Nested Content property aliases by content type alias | |
/// </summary> | |
/// <param name="contentTypeAlias"></param> | |
/// <returns></returns> | |
private List<string> GetNestedContentPropertyAliasesByContentTypeAlias(string contentTypeAlias) | |
{ | |
if (contentTypeAlias == null) return new List<string>(); | |
var contentType = _contentTypes.FirstOrDefault(x => x.Alias == contentTypeAlias); | |
if (contentType != null) | |
{ | |
return contentType.NestedContentPropertyAliases; | |
} | |
return new List<string>(); | |
} | |
private class ContentTypeWithNestedContent | |
{ | |
public int Id { get; set; } | |
public string Alias { get; set; } | |
public List<string> NestedContentPropertyAliases { get; set; } | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment