Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Umbraco.Core/Persistence/Repositories/IMacroRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;

namespace Umbraco.Core.Persistence.Repositories
Expand All @@ -7,6 +8,8 @@ public interface IMacroRepository : IReadWriteQueryRepository<int, IMacro>, IRea
{

//IEnumerable<IMacro> GetAll(params string[] aliases);
IMacro GetByAlias(string alias);
IEnumerable<IMacro> GetAllByAlias(string[] aliases);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
internal class MacroRepository : NPocoRepositoryBase<int, IMacro>, IMacroRepository
{
private readonly IRepositoryCachePolicy<IMacro, string> _macroByAliasCachePolicy;
public MacroRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger)
: base(scopeAccessor, cache, logger)
{ }
{
_macroByAliasCachePolicy = new DefaultRepositoryCachePolicy<IMacro, string>(GlobalIsolatedCache, ScopeAccessor, DefaultOptions);
}

protected override IMacro PerformGet(int id)
{
Expand Down Expand Up @@ -213,5 +216,24 @@ protected override void PersistUpdatedItem(IMacro entity)

entity.ResetDirtyProperties();
}

public IMacro GetByAlias(string alias)
{
return _macroByAliasCachePolicy.Get(alias, PerformGetByAlias, PerformGetAllByAlias);
}
public IEnumerable<IMacro> GetAllByAlias(string[] aliases)
{
return _macroByAliasCachePolicy.GetAll(aliases, PerformGetAllByAlias);
}
private IMacro PerformGetByAlias(string alias)
{
var query = Query<IMacro>().Where(x => x.Alias.Equals(alias));
return PerformGetByQuery(query).FirstOrDefault();
}
private IEnumerable<IMacro> PerformGetAllByAlias(params string[] aliases)
{
var query = Query<IMacro>().WhereIn(x => x.Alias, aliases);
return PerformGetByQuery(query);
}
}
}
6 changes: 3 additions & 3 deletions src/Umbraco.Core/Services/IMacroService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ public interface IMacroService : IService
IMacro GetByAlias(string alias);

///// <summary>
///// Gets a list all available <see cref="IMacro"/> objects
///// Gets a list of available <see cref="IMacro"/> objects by Alias
///// </summary>
///// <param name="aliases">Optional array of aliases to limit the results</param>
///// <returns>An enumerable list of <see cref="IMacro"/> objects</returns>
//IEnumerable<IMacro> GetAll(params string[] aliases);

IEnumerable<IMacro> GetAll(params string[] aliases);
IEnumerable<IMacro> GetAll();

IEnumerable<IMacro> GetAll(params int[] ids);
Expand Down
10 changes: 8 additions & 2 deletions src/Umbraco.Core/Services/Implement/MacroService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,14 @@ public IMacro GetByAlias(string alias)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
var q = Query<IMacro>().Where(x => x.Alias == alias);
return _macroRepository.Get(q).FirstOrDefault();
return _macroRepository.GetByAlias(alias);
}
}
public IEnumerable<IMacro> GetAll(params string[] aliases)
{
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
{
return _macroRepository.GetAllByAlias(aliases);
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/Umbraco.Tests/Services/MacroServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,21 @@ public void Can_Get_By_Alias()
Assert.IsNotNull(macro);
Assert.AreEqual("Test1", macro.Name);
}
[Test]
public void Can_Get_By_Aliases()
{
// Arrange
var macroService = ServiceContext.MacroService;

// Act
var macros = macroService.GetAll("test1","test2");

//assert
Assert.IsNotNull(macros);
Assert.AreEqual(2, macros.Count());
Assert.AreEqual("Test1", macros.ToArray()[0].Name);
Assert.AreEqual("Test2", macros.ToArray()[1].Name);
}
[Test]
public void Can_Get_All()
{
Expand Down
5 changes: 4 additions & 1 deletion src/Umbraco.Web/Cache/MacroCacheRefresher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public override void Refresh(string json)
if (macroRepoCache)
{
macroRepoCache.Result.Clear(RepositoryCacheKeys.GetKey<IMacro>(payload.Id));
macroRepoCache.Result.Clear(RepositoryCacheKeys.GetKey<IMacro>(payload.Alias));//repository caching of macro definition by alias
}
}

Expand Down Expand Up @@ -99,12 +100,14 @@ internal static string[] GetAllMacroCacheKeys()
return new[]
{
CacheKeys.MacroContentCacheKey, // macro render cache
CacheKeys.MacroFromAliasCacheKey, // lookup macro by alias
CacheKeys.MacroFromAliasCacheKey // lookup macro by alias

};
}

internal static string[] GetCacheKeysForAlias(string alias)
{

return GetAllMacroCacheKeys().Select(x => x + alias).ToArray();
}

Expand Down
50 changes: 40 additions & 10 deletions src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class GridPropertyEditor : DataEditor
{
private IUmbracoContextAccessor _umbracoContextAccessor;
private readonly HtmlImageSourceParser _imageSourceParser;
private readonly HtmlMacroParameterParser _macroParameterParser;
private readonly RichTextEditorPastedImages _pastedImages;
private readonly HtmlLocalLinkParser _localLinkParser;
private readonly IImageUrlGenerator _imageUrlGenerator;
Expand All @@ -39,22 +40,33 @@ public GridPropertyEditor(ILogger logger,
HtmlImageSourceParser imageSourceParser,
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser)
: this(logger, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser, Current.ImageUrlGenerator)
: this(logger, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser, Current.Factory.GetInstance<HtmlMacroParameterParser>(),Current.ImageUrlGenerator)
{
}
[Obsolete("Use the constructor which takes an HtmlMacroParameterParser")]
public GridPropertyEditor(ILogger logger,
IUmbracoContextAccessor umbracoContextAccessor,
HtmlImageSourceParser imageSourceParser,
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser,
IImageUrlGenerator imageUrlGenerator)
: this(logger, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser, Current.Factory.GetInstance<HtmlMacroParameterParser>(), imageUrlGenerator)
{
}

public GridPropertyEditor(ILogger logger,
IUmbracoContextAccessor umbracoContextAccessor,
HtmlImageSourceParser imageSourceParser,
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser,
HtmlMacroParameterParser macroParameterParser,
IImageUrlGenerator imageUrlGenerator)
: base(logger)
{
_umbracoContextAccessor = umbracoContextAccessor;
_imageSourceParser = imageSourceParser;
_pastedImages = pastedImages;
_localLinkParser = localLinkParser;
_macroParameterParser = macroParameterParser;
_imageUrlGenerator = imageUrlGenerator;
}

Expand All @@ -72,6 +84,7 @@ internal class GridPropertyValueEditor : DataValueEditor, IDataValueReference
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly HtmlImageSourceParser _imageSourceParser;
private readonly HtmlMacroParameterParser _macroParameterParser;
private readonly RichTextEditorPastedImages _pastedImages;
private readonly RichTextPropertyEditor.RichTextPropertyValueEditor _richTextPropertyValueEditor;
private readonly MediaPickerPropertyEditor.MediaPickerPropertyValueEditor _mediaPickerPropertyValueEditor;
Expand All @@ -83,23 +96,34 @@ public GridPropertyValueEditor(DataEditorAttribute attribute,
HtmlImageSourceParser imageSourceParser,
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser)
: this(attribute, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser, Current.ImageUrlGenerator)
: this(attribute, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser,Current.Factory.GetInstance<HtmlMacroParameterParser>(), Current.ImageUrlGenerator)
{
}
[Obsolete("Use the constructor which takes an HtmlMacroParameterParser")]
public GridPropertyValueEditor(DataEditorAttribute attribute,
IUmbracoContextAccessor umbracoContextAccessor,
HtmlImageSourceParser imageSourceParser,
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser,
IImageUrlGenerator imageUrlGenerator)
: this(attribute, umbracoContextAccessor, imageSourceParser, pastedImages, localLinkParser, Current.Factory.GetInstance<HtmlMacroParameterParser>(), imageUrlGenerator)
{
}

public GridPropertyValueEditor(DataEditorAttribute attribute,
IUmbracoContextAccessor umbracoContextAccessor,
HtmlImageSourceParser imageSourceParser,
RichTextEditorPastedImages pastedImages,
HtmlLocalLinkParser localLinkParser,
HtmlMacroParameterParser macroParameterParser,
IImageUrlGenerator imageUrlGenerator)
: base(attribute)
{
_umbracoContextAccessor = umbracoContextAccessor;
_imageSourceParser = imageSourceParser;
_pastedImages = pastedImages;
_richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, umbracoContextAccessor, imageSourceParser, localLinkParser, pastedImages, _imageUrlGenerator);
_richTextPropertyValueEditor = new RichTextPropertyEditor.RichTextPropertyValueEditor(attribute, umbracoContextAccessor, imageSourceParser, localLinkParser, macroParameterParser, pastedImages, _imageUrlGenerator);
_mediaPickerPropertyValueEditor = new MediaPickerPropertyEditor.MediaPickerPropertyValueEditor(attribute);
_macroParameterParser = macroParameterParser;
_imageUrlGenerator = imageUrlGenerator;
}

Expand All @@ -125,7 +149,7 @@ public override object FromEditor(ContentPropertyData editorValue, object curren
var mediaParent = config?.MediaParentId;
var mediaParentId = mediaParent == null ? Guid.Empty : mediaParent.Guid;

var grid = DeserializeGridValue(rawJson, out var rtes, out _);
var grid = DeserializeGridValue(rawJson, out var rtes, out _, out _);

var userId = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser?.Id ?? Constants.Security.SuperUserId;

Expand Down Expand Up @@ -158,7 +182,7 @@ public override object ToEditor(Property property, IDataTypeService dataTypeServ
var val = property.GetValue(culture, segment)?.ToString();
if (val.IsNullOrWhiteSpace()) return string.Empty;

var grid = DeserializeGridValue(val, out var rtes, out _);
var grid = DeserializeGridValue(val, out var rtes, out _, out _);

//process the rte values
foreach (var rte in rtes.ToList())
Expand All @@ -172,15 +196,16 @@ public override object ToEditor(Property property, IDataTypeService dataTypeServ
return grid;
}

private GridValue DeserializeGridValue(string rawJson, out IEnumerable<GridValue.GridControl> richTextValues, out IEnumerable<GridValue.GridControl> mediaValues)
private GridValue DeserializeGridValue(string rawJson, out IEnumerable<GridValue.GridControl> richTextValues, out IEnumerable<GridValue.GridControl> mediaValues, out IEnumerable<GridValue.GridControl> macroValues)
{
var grid = JsonConvert.DeserializeObject<GridValue>(rawJson);

// Find all controls that use the RTE editor
var controls = grid.Sections.SelectMany(x => x.Rows.SelectMany(r => r.Areas).SelectMany(a => a.Controls)).ToArray();
richTextValues = controls.Where(x => x.Editor.Alias.ToLowerInvariant() == "rte");
mediaValues = controls.Where(x => x.Editor.Alias.ToLowerInvariant() == "media");

// Find all the macros
macroValues = controls.Where(x => x.Editor.Alias.ToLowerInvariant() == "macro");
return grid;
}

Expand All @@ -196,7 +221,7 @@ public IEnumerable<UmbracoEntityReference> GetReferences(object value)
if (rawJson.IsNullOrWhiteSpace())
yield break;

DeserializeGridValue(rawJson, out var richTextEditorValues, out var mediaValues);
DeserializeGridValue(rawJson, out var richTextEditorValues, out var mediaValues, out var macroValues);

foreach (var umbracoEntityReference in richTextEditorValues.SelectMany(x =>
_richTextPropertyValueEditor.GetReferences(x.Value)))
Expand All @@ -205,6 +230,11 @@ public IEnumerable<UmbracoEntityReference> GetReferences(object value)
foreach (var umbracoEntityReference in mediaValues.SelectMany(x =>
_mediaPickerPropertyValueEditor.GetReferences(x.Value["udi"])))
yield return umbracoEntityReference;

foreach (var umbracoEntityReference in _macroParameterParser.FindUmbracoEntityReferencesFromGridControlMacros(macroValues))
yield return umbracoEntityReference;


}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
using Umbraco.Core;
using System;
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.PropertyEditors;
using static Umbraco.Web.PropertyEditors.MediaPickerPropertyEditor;

namespace Umbraco.Web.PropertyEditors.ParameterEditors
{
Expand All @@ -23,5 +29,42 @@ public MultipleMediaPickerParameterEditor(ILogger logger)
{
DefaultConfiguration.Add("multiPicker", "1");
}
protected override IDataValueEditor CreateValueEditor() => new MultipleMediaPickerPropertyValueEditor(Attribute);

internal class MultipleMediaPickerPropertyValueEditor : DataValueEditor, IDataValueReference
{
public MultipleMediaPickerPropertyValueEditor(DataEditorAttribute attribute) : base(attribute)
{
}

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 (Udi.TryParse(udiStr, out var udi))
{
yield return new UmbracoEntityReference(udi);
}
// for legacy reasons the multiple media picker parameter editor is configured to store as ints not udis - there is a PR to perhaps change this: https://github.com/umbraco/Umbraco-CMS/pull/8388
// but adding below should support both scenarios, or should this be added as a fallback on the MediaPickerPropertyValueEditor
if (int.TryParse(udiStr, out var id))
{
//TODO: inject the service?
var guidAttempt = Current.Services.EntityService.GetKey(id, UmbracoObjectTypes.Media);
var guid = guidAttempt.Success ? guidAttempt.Result : Guid.Empty;
if (guid != Guid.Empty)
{
yield return new UmbracoEntityReference(new GuidUdi(Constants.UdiEntityType.Media, guid));
}

}
}
}
}

}
}
Loading