public IEnumerable <UmbracoEntityReference> GetReferences(object?value) { var asString = value is string str ? str : value?.ToString(); if (string.IsNullOrEmpty(asString)) { yield break; } foreach (var udiStr in asString.Split(',')) { if (UdiParser.TryParse(udiStr, out Udi? udi)) { yield return(new UmbracoEntityReference(udi)); } // this is needed to support the legacy case when the multiple media picker parameter editor stores ints not udis if (int.TryParse(udiStr, out var id)) { Attempt <Guid> guidAttempt = _entityService.GetKey(id, UmbracoObjectType); Guid guid = guidAttempt.Success ? guidAttempt.Result : Guid.Empty; if (guid != Guid.Empty) { yield return(new UmbracoEntityReference(new GuidUdi(Constants.UdiEntityType.Media, guid))); } } } }
/// <summary> /// Parses the string looking for Umbraco image tags and updates them to their up-to-date image sources. /// </summary> /// <param name="text"></param> /// <returns></returns> /// <remarks>Umbraco image tags are identified by their data-udi attributes</remarks> public static string ResolveMediaFromTextString(string text) { // don't attempt to proceed without a context if (Current.UmbracoContext == null || Current.UmbracoContext.Media == null) { return(text); } return(ResolveImgPattern.Replace(text, match => { // match groups: // - 1 = from the beginning of the image tag until src attribute value begins // - 2 = the src attribute value excluding the querystring (if present) // - 3 = anything after group 2 and before the data-udi attribute value begins // - 4 = the data-udi attribute value // - 5 = anything after group 4 until the image tag is closed var udi = match.Groups[4].Value; if (udi.IsNullOrWhiteSpace() || UdiParser.TryParse(udi, out GuidUdi guidUdi) == false) { return match.Value; } var media = Current.UmbracoContext.Media.GetById(guidUdi.Guid); if (media == null) { // image does not exist - we could choose to remove the image entirely here (return empty string), // but that would leave the editors completely in the dark as to why the image doesn't show return match.Value; } var url = media.Url; return $"{match.Groups[1].Value}{url}{match.Groups[3].Value}{udi}{match.Groups[5].Value}"; })); }
/// <summary> /// Parses the string looking for Umbraco image tags and updates them to their up-to-date image sources. /// </summary> /// <param name="text"></param> /// <returns></returns> /// <remarks>Umbraco image tags are identified by their data-udi attributes</remarks> public string EnsureImageSources(string text) { if (_getMediaUrl == null) { _getMediaUrl = (guid) => _publishedUrlProvider?.GetMediaUrl(guid); } return(ResolveImgPattern.Replace(text, match => { // match groups: // - 1 = from the beginning of the image tag until src attribute value begins // - 2 = the src attribute value excluding the querystring (if present) // - 3 = anything after group 2 and before the data-udi attribute value begins // - 4 = the data-udi attribute value // - 5 = anything after group 4 until the image tag is closed var udi = match.Groups[4].Value; if (udi.IsNullOrWhiteSpace() || UdiParser.TryParse <GuidUdi>(udi, out var guidUdi) == false) { return match.Value; } var mediaUrl = _getMediaUrl(guidUdi.Guid); if (mediaUrl == null) { // image does not exist - we could choose to remove the image entirely here (return empty string), // but that would leave the editors completely in the dark as to why the image doesn't show return match.Value; } return $"{match.Groups[1].Value}{mediaUrl}{match.Groups[3].Value}{udi}{match.Groups[5].Value}"; })); }
/// <summary> /// this will parse the string into either a GUID or INT /// </summary> /// <param name="id"></param> /// <returns></returns> internal Tuple <Guid?, int?> GetIdentifierFromString(string id) { Guid idGuid; int idInt; Udi idUdi; if (Guid.TryParse(id, out idGuid)) { return(new Tuple <Guid?, int?>(idGuid, null)); } if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out idInt)) { return(new Tuple <Guid?, int?>(null, idInt)); } if (UdiParser.TryParse(id, out idUdi)) { var guidUdi = idUdi as GuidUdi; if (guidUdi != null) { return(new Tuple <Guid?, int?>(guidUdi.Guid, null)); } } return(null); }
/// <summary> /// Attempts to parse a node ID from a string representation found in a querystring value. /// </summary> /// <param name="argument">Querystring value.</param> /// <param name="nodeId">Output parsed Id.</param> /// <returns>True of node ID could be parased, false it not.</returns> protected bool TryParseNodeId(string argument, out int nodeId) { // If the argument is an int, it will parse and can be assigned to nodeId. // It might be a udi, so check that next. // Otherwise treat it as a guid - unlikely we ever get here. // Failing that, we can't parse it. if (int.TryParse(argument, NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsedId)) { nodeId = parsedId; return(true); } else if (UdiParser.TryParse(argument, true, out Udi udi)) { nodeId = EntityService.GetId(udi).Result; return(true); } else if (Guid.TryParse(argument, out Guid key)) { nodeId = EntityService.GetId(key, UmbracoObjectTypes.Document).Result; return(true); } else { nodeId = 0; return(false); } }
public void KnownTypes() { // cannot parse an unknown type, udi is null // this will scan Assert.IsFalse(UdiParser.TryParse("umb://whatever/1234", out Udi udi)); Assert.IsNull(udi); UdiParser.ResetUdiTypes(); // unless we want to know Assert.IsFalse(UdiParser.TryParse("umb://whatever/1234", true, out udi)); Assert.AreEqual(Constants.UdiEntityType.Unknown, udi.EntityType); Assert.AreEqual("Umbraco.Cms.Core.UnknownTypeUdi", udi.GetType().FullName); UdiParser.ResetUdiTypes(); // not known Assert.IsFalse(UdiParser.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi)); Assert.AreEqual(Constants.UdiEntityType.Unknown, udi.EntityType); Assert.AreEqual("Umbraco.Cms.Core.UnknownTypeUdi", udi.GetType().FullName); // scanned UdiParserServiceConnectors.RegisterServiceConnector <FooConnector>(); // this is the equivalent of scanning but we'll just manually register this one Assert.IsTrue(UdiParser.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", out udi)); Assert.IsInstanceOf <GuidUdi>(udi); // known Assert.IsTrue(UdiParser.TryParse("umb://foo/A87F65C8D6B94E868F6949BA92C93045", true, out udi)); Assert.IsInstanceOf <GuidUdi>(udi); // can get method for Deploy compatibility MethodInfo method = typeof(UdiParser).GetMethod("Parse", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string), typeof(bool) }, null); Assert.IsNotNull(method); }
/// <summary> /// Get an entity via an id that can be either an integer, Guid or UDI /// </summary> /// <param name="id"></param> /// <returns></returns> /// <remarks> /// This object has it's own contextual cache for these lookups /// </remarks> internal IEntitySlim GetEntityFromId(string id) { return(_entityCache.GetOrAdd(id, s => { IEntitySlim entity; if (Guid.TryParse(s, out var idGuid)) { entity = _entityService.Get(idGuid, UmbracoObjectType); } else if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out var idInt)) { entity = _entityService.Get(idInt, UmbracoObjectType); } else if (UdiParser.TryParse(s, out var idUdi)) { var guidUdi = idUdi as GuidUdi; entity = guidUdi != null ? _entityService.Get(guidUdi.Guid, UmbracoObjectType) : null; } else { entity = null; } return entity; })); }
private IEnumerable <(int?intId, GuidUdi?udi, string tagValue)> FindLocalLinkIds(string text) { // Parse internal links var tags = LocalLinkPattern.Matches(text); foreach (Match tag in tags) { if (tag.Groups.Count > 0) { var id = tag.Groups[1].Value; //.Remove(tag.Groups[1].Value.Length - 1, 1); //The id could be an int or a UDI if (UdiParser.TryParse(id, out var udi)) { var guidUdi = udi as GuidUdi; if (guidUdi is not null) { yield return(null, guidUdi, tag.Value); } } if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId)) { yield return(intId, null, tag.Value); } } } }
private void AppendPath(StringBuilder sb, UmbracoObjectTypes objectType, int[]?startNodeIds, string?searchFrom, bool ignoreUserStartNodes, IEntityService entityService) { if (sb == null) { throw new ArgumentNullException(nameof(sb)); } if (entityService == null) { throw new ArgumentNullException(nameof(entityService)); } UdiParser.TryParse(searchFrom, true, out Udi? udi); searchFrom = udi == null ? searchFrom : entityService.GetId(udi).Result.ToString(); TreeEntityPath?entityPath = int.TryParse(searchFrom, NumberStyles.Integer, CultureInfo.InvariantCulture, out var searchFromId) && searchFromId > 0 ? entityService.GetAllPaths(objectType, searchFromId).FirstOrDefault() : null; if (entityPath != null) { // find... only what's underneath sb.Append("+__Path:"); AppendPath(sb, entityPath.Path, false); sb.Append(" "); } else if (startNodeIds?.Length == 0) { // make sure we don't find anything sb.Append("+__Path:none "); } else if (startNodeIds?.Contains(-1) == false && ignoreUserStartNodes == false) // -1 = no restriction { IEnumerable <TreeEntityPath> entityPaths = entityService.GetAllPaths(objectType, startNodeIds); // for each start node, find the start node, and what's underneath // +__Path:(-1*,1234 -1*,1234,* -1*,5678 -1*,5678,* ...) sb.Append("+__Path:("); var first = true; foreach (TreeEntityPath ep in entityPaths) { if (first) { first = false; } else { sb.Append(" "); } AppendPath(sb, ep.Path, true); } sb.Append(") "); } }
protected uSyncDependency CreateDependency(string udiString, DependencyFlags flags) { if (UdiParser.TryParse <GuidUdi>(udiString, out GuidUdi udi)) { return(CreateDependency(udi, flags)); } return(null); }
// TODO: Replace mediaCache with media url provider internal static string ParseInternalLinks(string text, UrlProvider urlProvider, IPublishedMediaCache mediaCache) { if (urlProvider == null) { throw new ArgumentNullException(nameof(urlProvider)); } if (mediaCache == null) { throw new ArgumentNullException(nameof(mediaCache)); } // Parse internal links var tags = LocalLinkPattern.Matches(text); foreach (Match tag in tags) { if (tag.Groups.Count > 0) { var id = tag.Groups[1].Value; //.Remove(tag.Groups[1].Value.Length - 1, 1); //The id could be an int or a UDI if (UdiParser.TryParse(id, out var udi)) { var guidUdi = udi as GuidUdi; if (guidUdi != null) { var newLink = "#"; if (guidUdi.EntityType == Constants.UdiEntityType.Document) { newLink = urlProvider.GetUrl(guidUdi.Guid); } else if (guidUdi.EntityType == Constants.UdiEntityType.Media) { newLink = mediaCache.GetById(guidUdi.Guid)?.Url; } if (newLink == null) { newLink = "#"; } text = text.Replace(tag.Value, "href=\"" + newLink); } } if (int.TryParse(id, out var intId)) { var newLink = urlProvider.GetUrl(intId); text = text.Replace(tag.Value, "href=\"" + newLink); } } } return(text); }
/// <summary> /// Given a parent id which could be a GUID, UDI or an INT, this will resolve the INT /// </summary> /// <param name="parentId"></param> /// <param name="validatePermissions"> /// If true, this will check if the current user has access to the resolved integer parent id /// and if that check fails an unauthorized exception will occur /// </param> /// <returns></returns> private async Task <ActionResult <int?> > GetParentIdAsIntAsync(string parentId, bool validatePermissions) { int intParentId; // test for udi if (UdiParser.TryParse(parentId, out GuidUdi parentUdi)) { parentId = parentUdi.Guid.ToString(); } //if it's not an INT then we'll check for GUID if (int.TryParse(parentId, NumberStyles.Integer, CultureInfo.InvariantCulture, out intParentId) == false) { // if a guid then try to look up the entity Guid idGuid; if (Guid.TryParse(parentId, out idGuid)) { var entity = _entityService.Get(idGuid); if (entity != null) { intParentId = entity.Id; } else { return(null); } } else { return(ValidationProblem("The request was not formatted correctly, the parentId is not an integer, Guid or UDI")); } } // Authorize... //ensure the user has access to this folder by parent id! if (validatePermissions) { var requirement = new MediaPermissionsResourceRequirement(); var authorizationResult = await _authorizationService.AuthorizeAsync(User, new MediaPermissionsResource(_mediaService.GetById(intParentId)), requirement); if (!authorizationResult.Succeeded) { return(ValidationProblem( new SimpleNotificationModel(new BackOfficeNotification( _localizedTextService.Localize("speechBubbles", "operationFailedHeader"), _localizedTextService.Localize("speechBubbles", "invalidUserPermissionsText"), NotificationStyle.Warning)), StatusCodes.Status403Forbidden)); } } return(intParentId); }
public override object?ConvertFrom(ITypeDescriptorContext?context, CultureInfo?culture, object value) { if (value is string) { if (UdiParser.TryParse((string)value, out Udi? udi)) { return(udi); } } return(base.ConvertFrom(context, culture, value)); }
/// <summary> /// Given a parent id which could be a GUID, UDI or an INT, this will resolve the INT /// </summary> /// <param name="parentId"></param> /// <param name="validatePermissions"> /// If true, this will check if the current user has access to the resolved integer parent id /// and if that check fails an unauthorized exception will occur /// </param> /// <returns></returns> private int GetParentIdAsInt(string parentId, bool validatePermissions) { int intParentId; // test for udi if (UdiParser.TryParse(parentId, out GuidUdi parentUdi)) { parentId = parentUdi.Guid.ToString(); } //if it's not an INT then we'll check for GUID if (int.TryParse(parentId, out intParentId) == false) { // if a guid then try to look up the entity Guid idGuid; if (Guid.TryParse(parentId, out idGuid)) { var entity = Services.EntityService.Get(idGuid); if (entity != null) { intParentId = entity.Id; } else { throw new EntityNotFoundException(parentId, "The passed id doesn't exist"); } } else { throw new HttpResponseException( Request.CreateValidationErrorResponse("The request was not formatted correctly, the parentId is not an integer, Guid or UDI")); } } //ensure the user has access to this folder by parent id! if (validatePermissions && CheckPermissions( new Dictionary <string, object>(), Security.CurrentUser, Services.MediaService, Services.EntityService, intParentId) == false) { throw new HttpResponseException(Request.CreateResponse( HttpStatusCode.Forbidden, new SimpleNotificationModel(new Notification( Services.TextService.Localize("speechBubbles/operationFailedHeader"), Services.TextService.Localize("speechBubbles/invalidUserPermissionsText"), NotificationStyle.Warning)))); } return(intParentId); }
public IEnumerable <UmbracoEntityReference> GetReferences(object value) { var asString = value == null ? string.Empty : value is string str ? str : value.ToString(); var udiPaths = asString.Split(','); foreach (var udiPath in udiPaths) { if (UdiParser.TryParse(udiPath, out var udi)) { yield return(new UmbracoEntityReference(udi)); } } }
public IEnumerable <UmbracoEntityReference> GetReferences(object?value) { var asString = value is string str ? str : value?.ToString(); if (string.IsNullOrEmpty(asString)) { yield break; } if (UdiParser.TryParse(asString, out Udi? udi)) { yield return(new UmbracoEntityReference(udi)); } }
public IEnumerable <UmbracoEntityReference> GetReferences(object value) { // This is the same as the media picker, it will just try to parse the value directly as a UDI. var asString = value is string str ? str : value?.ToString(); if (string.IsNullOrEmpty(asString)) { yield break; } if (UdiParser.TryParse(asString, out Udi udi)) { yield return(new UmbracoEntityReference(udi)); } }
private static bool ConvertIdObjectToUdi(object id, out Udi guidId) { switch (id) { case string s: return(UdiParser.TryParse(s, out guidId)); case Udi u: guidId = u; return(true); default: guidId = default; return(false); } }
public RedirectUrlSearchResult RedirectUrlsForContentItem(string contentUdi) { var redirectsResult = new RedirectUrlSearchResult(); if (UdiParser.TryParse(contentUdi, out GuidUdi? guidIdi)) { var redirects = _redirectUrlService.GetContentRedirectUrls(guidIdi !.Guid); var mapped = _umbracoMapper.MapEnumerable <IRedirectUrl, ContentRedirectUrl>(redirects).WhereNotNull().ToList(); redirectsResult.SearchResults = mapped; //not doing paging 'yet' redirectsResult.TotalCount = mapped.Count; redirectsResult.CurrentPage = 1; redirectsResult.PageCount = 1; } return(redirectsResult); }
public IEnumerable <UmbracoEntityReference> GetReferences(object value) { var asString = value is string str ? str : value?.ToString(); if (string.IsNullOrEmpty(asString)) { yield break; } foreach (var udiStr in asString.Split(',')) { if (UdiParser.TryParse(udiStr, out var udi)) { yield return(new UmbracoEntityReference(udi)); } } }
public RedirectUrlSearchResult RedirectUrlsForContentItem(string contentUdi) { var redirectsResult = new RedirectUrlSearchResult(); if (UdiParser.TryParse(contentUdi, out GuidUdi guidIdi)) { var redirectUrlService = Services.RedirectUrlService; var redirects = redirectUrlService.GetContentRedirectUrls(guidIdi.Guid); var mapped = Mapper.MapEnumerable <IRedirectUrl, ContentRedirectUrl>(redirects); redirectsResult.SearchResults = mapped; //not doing paging 'yet' redirectsResult.TotalCount = mapped.Count(); redirectsResult.CurrentPage = 1; redirectsResult.PageCount = 1; } return(redirectsResult); }
/// <summary> /// Parses out media UDIs from an html string based on 'data-udi' html attributes /// </summary> /// <param name="text"></param> /// <returns></returns> public IEnumerable <Udi> FindUdisFromDataAttributes(string text) { var matches = DataUdiAttributeRegex.Matches(text); if (matches.Count == 0) { yield break; } foreach (Match match in matches) { if (match.Groups.Count == 2 && UdiParser.TryParse(match.Groups[1].Value, out var udi)) { yield return(udi); } } }
public override IEnumerable <uSyncDependency> GetDependencies(object value, string editorAlias, DependencyFlags flags) { // value null check. if (value == null) { return(Enumerable.Empty <uSyncDependency>()); } var stringValue = value.ToString(); if (string.IsNullOrWhiteSpace(stringValue)) { return(Enumerable.Empty <uSyncDependency>()); } var dependencies = new List <uSyncDependency>(); foreach (Match m in UdiRegEx.Matches(stringValue)) { if (UdiParser.TryParse <GuidUdi>(m.Value, out GuidUdi udi)) { if (!dependencies.Any(x => x.Udi == udi)) { dependencies.Add(CreateDependency(udi, flags)); } } } if (MacroRegEx.IsMatch(stringValue)) { var mappers = mapperCollection.Value.GetSyncMappers(editorAlias + ".macro"); if (mappers.Any()) { foreach (var macro in MacroRegEx.Matches(stringValue)) { foreach (var mapper in mappers) { dependencies.AddRange(mapper.GetDependencies(stringValue, editorAlias + ".macro", flags)); } } } } return(dependencies.Distinct()); }
internal static IEnumerable <MediaWithCropsDto> Deserialize(IJsonSerializer jsonSerializer, object?value) { var rawJson = value is string str ? str : value?.ToString(); if (string.IsNullOrWhiteSpace(rawJson)) { yield break; } if (!rawJson.DetectIsJson()) { // Old comma seperated UDI format foreach (var udiStr in rawJson.Split(Constants.CharArrays.Comma)) { if (UdiParser.TryParse(udiStr, out Udi? udi) && udi is GuidUdi guidUdi) { yield return(new MediaWithCropsDto { Key = Guid.NewGuid(), MediaKey = guidUdi.Guid, Crops = Enumerable.Empty <ImageCropperValue.ImageCropperCrop>(), FocalPoint = new ImageCropperValue.ImageCropperFocalPoint { Left = 0.5m, Top = 0.5m }, }); } } } else { IEnumerable <MediaWithCropsDto>?dtos = jsonSerializer.Deserialize <IEnumerable <MediaWithCropsDto> >(rawJson); if (dtos is not null) { // New JSON format foreach (MediaWithCropsDto dto in dtos) { yield return(dto); } } } }
public void RangeTest() { // can parse open string udi var stringUdiString = "umb://" + Constants.UdiEntityType.AnyString; Assert.IsTrue(UdiParser.TryParse(stringUdiString, out Udi stringUdi)); Assert.AreEqual(string.Empty, ((StringUdi)stringUdi).Id); // can parse open guid udi var guidUdiString = "umb://" + Constants.UdiEntityType.AnyGuid; Assert.IsTrue(UdiParser.TryParse(guidUdiString, out Udi guidUdi)); Assert.AreEqual(Guid.Empty, ((GuidUdi)guidUdi).Guid); // can create a range var range = new UdiRange(stringUdi, Constants.DeploySelector.ChildrenOfThis); // cannot create invalid ranges Assert.Throws <ArgumentException>(() => new UdiRange(guidUdi, "x")); }
public override void OnActionExecuting(HttpActionContext actionContext) { if (Current.UmbracoContext.Security.CurrentUser == null) { //not logged in throw new HttpResponseException(System.Net.HttpStatusCode.Unauthorized); } int nodeId; if (_nodeId.HasValue == false) { var parts = _paramName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); if (actionContext.ActionArguments[parts[0]] == null) { throw new InvalidOperationException("No argument found for the current action with the name: " + _paramName); } if (parts.Length == 1) { var argument = actionContext.ActionArguments[parts[0]].ToString(); // if the argument is an int, it will parse and can be assigned to nodeId // if might be a udi, so check that next // otherwise treat it as a guid - unlikely we ever get here if (int.TryParse(argument, out int parsedId)) { nodeId = parsedId; } else if (UdiParser.TryParse(argument, true, out Udi udi)) { // TODO: inject? we can't because this is an attribute but we could provide ctors and empty ctors that pass in the required services nodeId = Current.Services.EntityService.GetId(udi).Result; } else { Guid.TryParse(argument, out Guid key); // TODO: inject? we can't because this is an attribute but we could provide ctors and empty ctors that pass in the required services nodeId = Current.Services.EntityService.GetId(key, UmbracoObjectTypes.Document).Result; } } else { //now we need to see if we can get the property of whatever object it is var pType = actionContext.ActionArguments[parts[0]].GetType(); var prop = pType.GetProperty(parts[1]); if (prop == null) { throw new InvalidOperationException("No argument found for the current action with the name: " + _paramName); } nodeId = (int)prop.GetValue(actionContext.ActionArguments[parts[0]]); } } else { nodeId = _nodeId.Value; } var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId, Current.UmbracoContext.Security.CurrentUser, Current.Services.UserService, Current.Services.ContentService, Current.Services.EntityService, out var contentItem, _permissionToCheck.HasValue ? new[] { _permissionToCheck.Value } : null); if (permissionResult == ContentPermissionsHelper.ContentAccess.NotFound) { throw new HttpResponseException(HttpStatusCode.NotFound); } if (permissionResult == ContentPermissionsHelper.ContentAccess.Denied) { throw new HttpResponseException(actionContext.Request.CreateUserNoAccessResponse()); } if (contentItem != null) { //store the content item in request cache so it can be resolved in the controller without re-looking it up actionContext.Request.Properties[typeof(IContent).ToString()] = contentItem; } base.OnActionExecuting(actionContext); }
public override void Migrate() { var sqlDataTypes = Sql() .Select <DataTypeDto>() .From <DataTypeDto>() .Where <DataTypeDto>(x => x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks || x.EditorAlias == Constants.PropertyEditors.Legacy.Aliases.RelatedLinks2); var dataTypes = Database.Fetch <DataTypeDto>(sqlDataTypes); var dataTypeIds = dataTypes.Select(x => x.NodeId).ToList(); if (dataTypeIds.Count == 0) { return; } foreach (var dataType in dataTypes) { dataType.EditorAlias = Constants.PropertyEditors.Aliases.MultiUrlPicker; Database.Update(dataType); } var sqlPropertyTpes = Sql() .Select <PropertyTypeDto>() .From <PropertyTypeDto>() .Where <PropertyTypeDto>(x => dataTypeIds.Contains(x.DataTypeId)); var propertyTypeIds = Database.Fetch <PropertyTypeDto>(sqlPropertyTpes).Select(x => x.Id).ToList(); if (propertyTypeIds.Count == 0) { return; } var sqlPropertyData = Sql() .Select <PropertyDataDto>() .From <PropertyDataDto>() .Where <PropertyDataDto>(x => propertyTypeIds.Contains(x.PropertyTypeId)); var properties = Database.Fetch <PropertyDataDto>(sqlPropertyData); // Create a Multi URL Picker datatype for the converted RelatedLinks data foreach (var property in properties) { var value = property.Value?.ToString(); if (string.IsNullOrWhiteSpace(value)) { continue; } var relatedLinks = JsonConvert.DeserializeObject <List <RelatedLink> >(value); var links = new List <LinkDto>(); foreach (var relatedLink in relatedLinks) { GuidUdi udi = null; if (relatedLink.IsInternal) { var linkIsUdi = UdiParser.TryParse(relatedLink.Link, out udi); if (linkIsUdi == false) { // oh no.. probably an integer, yikes! if (int.TryParse(relatedLink.Link, out var intId)) { var sqlNodeData = Sql() .Select <NodeDto>() .From <NodeDto>() .Where <NodeDto>(x => x.NodeId == intId); var node = Database.Fetch <NodeDto>(sqlNodeData).FirstOrDefault(); if (node != null) { // Note: RelatedLinks did not allow for picking media items, // so if there's a value this will be a content item - hence // the hardcoded "document" here udi = new GuidUdi("document", node.UniqueId); } } } } var link = new LinkDto { Name = relatedLink.Caption, Target = relatedLink.NewWindow ? "_blank" : null, Udi = udi, // Should only have a URL if it's an external link otherwise it wil be a UDI Url = relatedLink.IsInternal == false ? relatedLink.Link : null }; links.Add(link); } var json = JsonConvert.SerializeObject(links); // Update existing data property.TextValue = json; Database.Update(property); } }