Merge pull request #7712 from umbraco/netcore/feature/AB5168-migrate-macros

Netcore: Move macros to Abstractions and Infrastructure
This commit is contained in:
Bjarke Berg
2020-02-26 07:39:06 +01:00
committed by GitHub
27 changed files with 78 additions and 535 deletions

View File

@@ -0,0 +1,20 @@
using System;
namespace Umbraco.Web.Macros
{
// represents the content of a macro
public class MacroContent
{
// gets or sets the text content
public string Text { get; set; }
// gets or sets the date the content was generated
public DateTime Date { get; set; } = DateTime.Now;
// a value indicating whether the content is empty
public bool IsEmpty => Text is null;
// gets an empty macro content
public static MacroContent Empty { get; } = new MacroContent();
}
}

View File

@@ -20,8 +20,6 @@ namespace Umbraco.Web.Macros
/// </summary>
public string Alias { get; set; }
public MacroTypes MacroType { get; set; }
public string MacroSource { get; set; }
public int CacheDuration { get; set; }
@@ -46,7 +44,6 @@ namespace Umbraco.Web.Macros
Id = macro.Id;
Name = macro.Name;
Alias = macro.Alias;
MacroType = macro.MacroType;
MacroSource = macro.MacroSource;
CacheDuration = macro.CacheDuration;
CacheByPage = macro.CacheByPage;
@@ -55,8 +52,6 @@ namespace Umbraco.Web.Macros
foreach (var prop in macro.Properties)
Properties.Add(new MacroPropertyModel(prop.Alias, string.Empty, prop.EditorAlias));
MacroType = macro.MacroType;
}
}
}

View File

@@ -58,22 +58,10 @@ namespace Umbraco.Core.Models
[DataMember]
string MacroSource { get; set; }
/// <summary>
/// Gets or set the macro type
/// </summary>
[DataMember]
MacroTypes MacroType { get; set; }
/// <summary>
/// Gets or sets a list of Macro Properties
/// </summary>
[DataMember]
MacroPropertyCollection Properties { get; }
///// <summary>
///// Returns an enum <see cref="MacroTypes"/> based on the properties on the Macro
///// </summary>
///// <returns><see cref="MacroTypes"/></returns>
//MacroTypes MacroType();
}
}

View File

@@ -1,18 +0,0 @@
using System;
using System.Runtime.Serialization;
namespace Umbraco.Core.Models
{
/// <summary>
/// Enum for the various types of Macros
/// </summary>
[Serializable]
[DataContract(IsReference = true)]
public enum MacroTypes
{
[EnumMember]
Unknown = 4,
[EnumMember]
PartialView = 7
}
}

View File

@@ -10,7 +10,7 @@ namespace Umbraco.Web.Macros
/// <summary>
/// Parses the macro syntax in a string and renders out it's contents
/// </summary>
internal class MacroTagParser
public class MacroTagParser
{
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Singleline);
@@ -35,7 +35,7 @@ namespace Umbraco.Web.Macros
/// {/div}
///
/// </remarks>
internal static string FormatRichTextPersistedDataForEditor(string persistedContent, IDictionary<string ,string> htmlAttributes)
public static string FormatRichTextPersistedDataForEditor(string persistedContent, IDictionary<string ,string> htmlAttributes)
{
return MacroPersistedFormat.Replace(persistedContent, match =>
{
@@ -92,7 +92,7 @@ namespace Umbraco.Web.Macros
/// since this is exactly how we need to persist it to the db.
///
/// </remarks>
internal static string FormatRichTextContentForPersistence(string rteContent)
public static string FormatRichTextContentForPersistence(string rteContent)
{
if (string.IsNullOrEmpty(rteContent))
{
@@ -145,7 +145,7 @@ namespace Umbraco.Web.Macros
/// This method simply parses the macro contents, it does not create a string or result,
/// this is up to the developer calling this method to implement this with the callbacks.
/// </remarks>
internal static void ParseMacros(
public static void ParseMacros(
string text,
Action<string> textFoundCallback,
Action<string, Dictionary<string, string>> macroFoundCallback )

View File

@@ -18,11 +18,12 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
AddColumn<MacroDto>("macroSource", out var sqls2);
//populate the new columns with legacy data
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = '', macroType = {(int)MacroTypes.Unknown}").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroXSLT, macroType = {(int)MacroTypes.Unknown} WHERE macroXSLT != '' AND macroXSLT IS NOT NULL").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptAssembly, macroType = {(int)MacroTypes.Unknown} WHERE macroScriptAssembly != '' AND macroScriptAssembly IS NOT NULL").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptType, macroType = {(int)MacroTypes.Unknown} WHERE macroScriptType != '' AND macroScriptType IS NOT NULL").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroPython, macroType = {(int)MacroTypes.PartialView} WHERE macroPython != '' AND macroPython IS NOT NULL").Do();
//when the macro type is PartialView, it corresponds to 7, else it is 4 for Unknown
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = '', macroType = 4").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroXSLT, macroType = 4 WHERE macroXSLT != '' AND macroXSLT IS NOT NULL").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptAssembly, macroType = 4 WHERE macroScriptAssembly != '' AND macroScriptAssembly IS NOT NULL").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptType, macroType = 4 WHERE macroScriptType != '' AND macroScriptType IS NOT NULL").Do();
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroPython, macroType = 7 WHERE macroPython != '' AND macroPython IS NOT NULL").Do();
//now apply constraints (NOT NULL) to new table
foreach (var sql in sqls1) Execute.Sql(sql).Do();

View File

@@ -40,7 +40,7 @@ namespace Umbraco.Core.Models
/// <param name="cacheByMember"></param>
/// <param name="dontRender"></param>
/// <param name="macroSource"></param>
public Macro(IShortStringHelper shortStringHelper, int id, Guid key, bool useInEditor, int cacheDuration, string @alias, string name, bool cacheByPage, bool cacheByMember, bool dontRender, string macroSource, MacroTypes macroType)
public Macro(IShortStringHelper shortStringHelper, int id, Guid key, bool useInEditor, int cacheDuration, string @alias, string name, bool cacheByPage, bool cacheByMember, bool dontRender, string macroSource)
: this(shortStringHelper)
{
Id = id;
@@ -53,7 +53,6 @@ namespace Umbraco.Core.Models
CacheByMember = cacheByMember;
DontRender = dontRender;
MacroSource = macroSource;
MacroType = macroType;
}
/// <summary>
@@ -69,7 +68,6 @@ namespace Umbraco.Core.Models
/// <param name="macroSource"></param>
public Macro(IShortStringHelper shortStringHelper, string @alias, string name,
string macroSource,
MacroTypes macroType,
bool cacheByPage = false,
bool cacheByMember = false,
bool dontRender = true,
@@ -85,7 +83,6 @@ namespace Umbraco.Core.Models
CacheByMember = cacheByMember;
DontRender = dontRender;
MacroSource = macroSource;
MacroType = macroType;
}
private string _alias;
@@ -96,7 +93,6 @@ namespace Umbraco.Core.Models
private bool _cacheByMember;
private bool _dontRender;
private string _macroSource;
private MacroTypes _macroType = MacroTypes.Unknown;
private MacroPropertyCollection _properties;
private List<string> _addedProperties;
private List<string> _removedProperties;
@@ -247,16 +243,6 @@ namespace Umbraco.Core.Models
set => SetPropertyValueAndDetectChanges(value, ref _macroSource, nameof(MacroSource));
}
/// <summary>
/// Gets or set the path to the Partial View to render
/// </summary>
[DataMember]
public MacroTypes MacroType
{
get => _macroType;
set => SetPropertyValueAndDetectChanges(value, ref _macroType, nameof(MacroType));
}
/// <summary>
/// Gets or sets a list of Macro Properties
/// </summary>

View File

@@ -1133,7 +1133,6 @@ namespace Umbraco.Core.Packaging
{
var macroName = macroElement.Element("name").Value;
var macroAlias = macroElement.Element("alias").Value;
var macroType = Enum<MacroTypes>.Parse(macroElement.Element("macroType").Value);
var macroSource = macroElement.Element("macroSource").Value;
//Following xml elements are treated as nullable properties
@@ -1169,7 +1168,7 @@ namespace Umbraco.Core.Packaging
}
var existingMacro = _macroService.GetByAlias(macroAlias) as Macro;
var macro = existingMacro ?? new Macro(_shortStringHelper, macroAlias, macroName, macroSource, macroType,
var macro = existingMacro ?? new Macro(_shortStringHelper, macroAlias, macroName, macroSource,
cacheByPage, cacheByMember, dontRender, useInEditor, cacheDuration);
var properties = macroElement.Element("properties");

View File

@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.Factories
{
public static IMacro BuildEntity(IShortStringHelper shortStringHelper, MacroDto dto)
{
var model = new Macro(shortStringHelper, dto.Id, dto.UniqueId, dto.UseInEditor, dto.RefreshRate, dto.Alias, dto.Name, dto.CacheByPage, dto.CachePersonalized, dto.DontRender, dto.MacroSource, (MacroTypes)dto.MacroType);
var model = new Macro(shortStringHelper, dto.Id, dto.UniqueId, dto.UseInEditor, dto.RefreshRate, dto.Alias, dto.Name, dto.CacheByPage, dto.CachePersonalized, dto.DontRender, dto.MacroSource);
try
{
@@ -45,7 +45,7 @@ namespace Umbraco.Core.Persistence.Factories
RefreshRate = entity.CacheDuration,
UseInEditor = entity.UseInEditor,
MacroPropertyDtos = BuildPropertyDtos(entity),
MacroType = (int)entity.MacroType
MacroType = 7 //PartialView
};
if (entity.HasIdentity)

View File

@@ -19,7 +19,6 @@ namespace Umbraco.Core.Persistence.Mappers
DefineMap<Macro, MacroDto>(nameof(Macro.Alias), nameof(MacroDto.Alias));
DefineMap<Macro, MacroDto>(nameof(Macro.CacheByPage), nameof(MacroDto.CacheByPage));
DefineMap<Macro, MacroDto>(nameof(Macro.CacheByMember), nameof(MacroDto.CachePersonalized));
DefineMap<Macro, MacroDto>(nameof(Macro.MacroType), nameof(MacroDto.MacroType));
DefineMap<Macro, MacroDto>(nameof(Macro.DontRender), nameof(MacroDto.DontRender));
DefineMap<Macro, MacroDto>(nameof(Macro.Name), nameof(MacroDto.Name));
DefineMap<Macro, MacroDto>(nameof(Macro.CacheDuration), nameof(MacroDto.RefreshRate));

View File

@@ -415,7 +415,6 @@ namespace Umbraco.Core.Services.Implement
var xml = new XElement("macro");
xml.Add(new XElement("name", macro.Name));
xml.Add(new XElement("alias", macro.Alias));
xml.Add(new XElement("macroType", macro.MacroType));
xml.Add(new XElement("macroSource", macro.MacroSource));
xml.Add(new XElement("useInEditor", macro.UseInEditor.ToString()));
xml.Add(new XElement("dontRender", macro.DontRender.ToString()));

View File

@@ -6,6 +6,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HtmlAgilityPack" Version="1.8.14" />
<PackageReference Include="LightInject" Version="6.2.0" />
<PackageReference Include="LightInject.Annotation" Version="1.1.0" />
<PackageReference Include="Markdown" Version="2.2.1" />

View File

@@ -25,15 +25,13 @@ namespace Umbraco.Tests.Macros
new IsolatedCaches(type => new ObjectCacheAppCache(typeFinder)));
}
[TestCase("PartialView", true)]
[TestCase("Unknown", false)]
public void Macro_Is_File_Based(string macroTypeString, bool expectedNonNull)
[TestCase("anything", true)]
[TestCase("", false)]
public void Macro_Is_File_Based(string macroSource, bool expectedNonNull)
{
var macroType = Enum<MacroTypes>.Parse(macroTypeString);
var model = new MacroModel
{
MacroType = macroType,
MacroSource = "anything"
MacroSource = macroSource
};
var filename = MacroRenderer.GetMacroFileName(model);
if (expectedNonNull)

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Tests.Models
[Test]
public void Can_Deep_Clone()
{
var macro = new Macro(TestHelper.ShortStringHelper, 1, Guid.NewGuid(), true, 3, "test", "Test", false, true, true, "~/script.cshtml", MacroTypes.PartialView);
var macro = new Macro(TestHelper.ShortStringHelper, 1, Guid.NewGuid(), true, 3, "test", "Test", false, true, true, "~/script.cshtml");
macro.Properties.Add(new MacroProperty(6, Guid.NewGuid(), "rewq", "REWQ", 1, "asdfasdf"));
var clone = (Macro)macro.DeepClone();

View File

@@ -37,7 +37,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper);
var macro = new Macro(ShortStringHelper, "test1", "Test", "~/views/macropartials/test.cshtml", MacroTypes.PartialView);
var macro = new Macro(ShortStringHelper, "test1", "Test", "~/views/macropartials/test.cshtml");
;
Assert.Throws<SqlCeException>(() => repository.Save(macro));
@@ -168,7 +168,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper);
// Act
var macro = new Macro(ShortStringHelper, "test", "Test", "~/views/macropartials/test.cshtml", MacroTypes.PartialView);
var macro = new Macro(ShortStringHelper, "test", "Test", "~/views/macropartials/test.cshtml");
macro.Properties.Add(new MacroProperty("test", "Test", 0, "test"));
repository.Save(macro);
@@ -289,7 +289,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper);
var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView);
var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml");
macro.Properties.Add(new MacroProperty("blah1", "New1", 4, "test.editor"));
repository.Save(macro);
@@ -314,7 +314,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper);
var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView);
var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml");
macro.Properties.Add(new MacroProperty("blah1", "New1", 4, "test.editor"));
repository.Save(macro);
@@ -338,7 +338,7 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper);
var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView);
var macro = new Macro(ShortStringHelper, "newmacro", "A new macro", "~/views/macropartials/test1.cshtml");
var prop1 = new MacroProperty("blah1", "New1", 4, "test.editor");
var prop2 = new MacroProperty("blah2", "New2", 3, "test.editor");
@@ -424,9 +424,9 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper);
repository.Save(new Macro(ShortStringHelper, "test1", "Test1", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView));
repository.Save(new Macro(ShortStringHelper, "test2", "Test2", "~/views/macropartials/test2.cshtml", MacroTypes.PartialView));
repository.Save(new Macro(ShortStringHelper, "test3", "Tet3", "~/views/macropartials/test3.cshtml", MacroTypes.PartialView));
repository.Save(new Macro(ShortStringHelper, "test1", "Test1", "~/views/macropartials/test1.cshtml"));
repository.Save(new Macro(ShortStringHelper, "test2", "Test2", "~/views/macropartials/test2.cshtml"));
repository.Save(new Macro(ShortStringHelper, "test3", "Tet3", "~/views/macropartials/test3.cshtml"));
scope.Complete();
}

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Tests.Services
public void Can_Export_Macro()
{
// Arrange
var macro = new Macro(ShortStringHelper, "test1", "Test", "~/views/macropartials/test.cshtml", MacroTypes.PartialView);
var macro = new Macro(ShortStringHelper, "test1", "Test", "~/views/macropartials/test.cshtml");
ServiceContext.MacroService.Save(macro);
// Act

View File

@@ -28,9 +28,9 @@ namespace Umbraco.Tests.Services
{
var repository = new MacroRepository((IScopeAccessor) provider, AppCaches.Disabled, Mock.Of<ILogger>(), ShortStringHelper);
repository.Save(new Macro(ShortStringHelper, "test1", "Test1", "~/views/macropartials/test1.cshtml", MacroTypes.PartialView));
repository.Save(new Macro(ShortStringHelper, "test2", "Test2", "~/views/macropartials/test2.cshtml", MacroTypes.PartialView));
repository.Save(new Macro(ShortStringHelper, "test3", "Tet3", "~/views/macropartials/test3.cshtml", MacroTypes.PartialView));
repository.Save(new Macro(ShortStringHelper, "test1", "Test1", "~/views/macropartials/test1.cshtml"));
repository.Save(new Macro(ShortStringHelper, "test2", "Test2", "~/views/macropartials/test2.cshtml"));
repository.Save(new Macro(ShortStringHelper, "test3", "Tet3", "~/views/macropartials/test3.cshtml"));
scope.Complete();
}
}
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.Services
var macroService = ServiceContext.MacroService;
// Act
var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", MacroTypes.PartialView, cacheDuration: 1234);
var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
macroService.Save(macro);
//assert
@@ -100,7 +100,7 @@ namespace Umbraco.Tests.Services
{
// Arrange
var macroService = ServiceContext.MacroService;
var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", MacroTypes.PartialView, cacheDuration: 1234);
var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
macroService.Save(macro);
// Act
@@ -119,7 +119,7 @@ namespace Umbraco.Tests.Services
{
// Arrange
var macroService = ServiceContext.MacroService;
IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", MacroTypes.PartialView, cacheDuration: 1234);
IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
macroService.Save(macro);
// Act
@@ -143,7 +143,7 @@ namespace Umbraco.Tests.Services
{
// Arrange
var macroService = ServiceContext.MacroService;
IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", MacroTypes.PartialView, cacheDuration: 1234);
IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
macro.Properties.Add(new MacroProperty("blah", "Blah", 0, "blah"));
macroService.Save(macro);
@@ -174,7 +174,7 @@ namespace Umbraco.Tests.Services
{
// Arrange
var macroService = ServiceContext.MacroService;
IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", MacroTypes.PartialView, cacheDuration: 1234);
IMacro macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
macro.Properties.Add(new MacroProperty("blah1", "Blah1", 0, "blah1"));
macro.Properties.Add(new MacroProperty("blah2", "Blah2", 1, "blah2"));
macro.Properties.Add(new MacroProperty("blah3", "Blah3", 2, "blah3"));
@@ -218,7 +218,7 @@ namespace Umbraco.Tests.Services
public void Can_Add_And_Remove_Properties()
{
var macroService = ServiceContext.MacroService;
var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", MacroTypes.PartialView, cacheDuration: 1234);
var macro = new Macro(ShortStringHelper, "test", "Test", "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
//adds some properties
macro.Properties.Add(new MacroProperty("blah1", "Blah1", 0, "blah1"));
@@ -253,7 +253,7 @@ namespace Umbraco.Tests.Services
{
// Arrange
var macroService = ServiceContext.MacroService;
var macro = new Macro(ShortStringHelper, "test", string.Empty, "~/Views/MacroPartials/Test.cshtml", MacroTypes.PartialView, cacheDuration: 1234);
var macro = new Macro(ShortStringHelper, "test", string.Empty, "~/Views/MacroPartials/Test.cshtml", cacheDuration: 1234);
// Act & Assert
Assert.Throws<ArgumentException>(() => macroService.Save(macro));

View File

@@ -195,8 +195,7 @@ namespace Umbraco.Web.Editors
{
Alias = macroName.ToSafeAlias(ShortStringHelper),
Name = macroName,
MacroSource = model.VirtualPath.EnsureStartsWith("~"),
MacroType = MacroTypes.PartialView
MacroSource = model.VirtualPath.EnsureStartsWith("~")
};
_macroService.Save(macro); // may throw

View File

@@ -108,8 +108,7 @@ namespace Umbraco.Web.Editors
{
Alias = alias,
Name = name,
MacroSource = string.Empty,
MacroType = MacroTypes.PartialView
MacroSource = string.Empty
};
_macroService.Save(macro, this.Security.CurrentUser.Id);
@@ -223,7 +222,6 @@ namespace Umbraco.Web.Editors
macro.DontRender = !macroDisplay.RenderInEditor;
macro.UseInEditor = macroDisplay.UseInEditor;
macro.MacroSource = macroDisplay.View;
macro.MacroType = MacroTypes.PartialView;
macro.Properties.ReplaceAll(macroDisplay.Parameters.Select((x,i) => new MacroProperty(x.Key, x.Label, i, x.Editor)));
try

View File

@@ -1,53 +0,0 @@
using System;
using System.IO;
using System.Web.UI;
namespace Umbraco.Web.Macros
{
// represents the content of a macro
public class MacroContent
{
// gets or sets the text content
public string Text { get; set; }
// gets or sets the control content
public Control Control { get; set; }
public string ControlId { get; set; }
// gets or sets the date the content was generated
public DateTime Date { get; set; } = DateTime.Now;
// a value indicating whether the content is empty
public bool IsEmpty => Text == null && Control == null;
// a value indicating whether the content is pure text (no control)
public bool IsText => Control == null;
// a value indicating whether the content is a control
public bool IsControl => Control != null;
// gets an empty macro content
public static MacroContent Empty { get; } = new MacroContent();
// gets the macro content as a string
// ie executes the control if any
public string GetAsText()
{
if (Control == null) return Text ?? string.Empty;
using (var textWriter = new StringWriter())
using (var htmlWriter = new HtmlTextWriter(textWriter))
{
Control.RenderControl(htmlWriter);
return textWriter.ToString();
}
}
// gets the macro content as a control
// ie wraps the text in a control if needed
public Control GetAsControl()
{
return Control ?? new LiteralControl(Text ?? string.Empty);
}
}
}

View File

@@ -112,10 +112,6 @@ namespace Umbraco.Web.Macros
}
}
// this is legacy and I'm not sure what exactly it is supposed to do
if (macroContent.Control != null)
macroContent.Control.ID = macroContent.ControlId;
return macroContent;
}
@@ -137,10 +133,6 @@ namespace Umbraco.Web.Macros
if (key == null) return;
}
// this is legacy and I'm not sure what exactly it is supposed to do
if (macroContent.Control != null)
macroContent.ControlId = macroContent.Control.ID;
// remember when we cache the content
macroContent.Date = DateTime.Now;
@@ -155,23 +147,12 @@ namespace Umbraco.Web.Macros
}
// gets the macro source file name
// null if the macro is not file-based
// null if the macro is not file-based, or not supported
internal static string GetMacroFileName(MacroModel model)
{
string filename;
string filename = model.MacroSource; // partial views are saved with their full virtual path
switch (model.MacroType)
{
case MacroTypes.PartialView:
filename = model.MacroSource; // partial views are saved with their full virtual path
break;
default:
// not file-based, or not supported
filename = null;
break;
}
return filename;
return string.IsNullOrEmpty(filename) ? null : filename;
}
// gets the macro source file
@@ -210,24 +191,22 @@ namespace Umbraco.Web.Macros
if (m == null)
throw new InvalidOperationException("No macro found by alias " + macroAlias);
var page = new PublishedContentHashtableConverter(content, _userService);
var macro = new MacroModel(m);
UpdateMacroModelProperties(macro, macroParams);
return Render(macro, content, page.Elements);
return Render(macro, content);
}
private MacroContent Render(MacroModel macro, IPublishedContent content, IDictionary pageElements)
private MacroContent Render(MacroModel macro, IPublishedContent content)
{
if (content == null) throw new ArgumentNullException(nameof(content));
var macroInfo = $"Render Macro: {macro.Name}, type: {macro.MacroType}, cache: {macro.CacheDuration}";
var macroInfo = $"Render Macro: {macro.Name}, cache: {macro.CacheDuration}";
using (_plogger.DebugDuration<MacroRenderer>(macroInfo, "Rendered Macro."))
{
// parse macro parameters ie replace the special [#key], [$key], etc. syntaxes
foreach (var prop in macro.Properties)
prop.Value = ParseAttribute(pageElements, prop.Value);
prop.Value = ParseAttribute(prop.Value);
macro.CacheIdentifier = GetContentCacheIdentifier(macro, content.Id);
@@ -334,22 +313,11 @@ namespace Umbraco.Web.Macros
var textService = _textService;
switch (model.MacroType)
{
case MacroTypes.PartialView:
return ExecuteMacroWithErrorWrapper(model,
$"Executing PartialView: MacroSource=\"{model.MacroSource}\".",
"Executed PartialView.",
() => ExecutePartialView(model, content),
() => textService.Localize("errors/macroErrorLoadingPartialView", new[] { model.MacroSource }));
default:
return ExecuteMacroWithErrorWrapper(model,
$"Execute macro with unsupported type \"{model.MacroType}\".",
"Executed.",
() => { throw new Exception("Unsupported macro type."); },
() => textService.Localize("errors/macroErrorUnsupportedType"));
}
return ExecuteMacroWithErrorWrapper(model,
$"Executing PartialView: MacroSource=\"{model.MacroSource}\".",
"Executed PartialView.",
() => ExecutePartialView(model, content),
() => textService.Localize("errors/macroErrorLoadingPartialView", new[] { model.MacroSource }));
}
@@ -371,12 +339,10 @@ namespace Umbraco.Web.Macros
#region Execution helpers
// parses attribute value looking for [@requestKey], [%sessionKey], [#pageElement], [$recursiveValue]
// parses attribute value looking for [@requestKey], [%sessionKey]
// supports fallbacks eg "[@requestKey],[%sessionKey],1234"
private string ParseAttribute(IDictionary pageElements, string attributeValue)
private string ParseAttribute(string attributeValue)
{
if (pageElements == null) throw new ArgumentNullException(nameof(pageElements));
// check for potential querystring/cookie variables
attributeValue = attributeValue.Trim();
if (attributeValue.StartsWith("[") == false)
@@ -388,7 +354,7 @@ namespace Umbraco.Web.Macros
// like [1,2,3] which we don't want to parse - however the last one can be a literal, so
// don't check on the last one which can be just anything - check all previous tokens
char[] validTypes = { '@', '%', '#', '$' };
char[] validTypes = { '@', '%' };
if (tokens.Take(tokens.Length - 1).Any(x =>
x.Length < 4 // ie "[?x]".Length - too short
|| x[0] != '[' // starts with [
@@ -424,14 +390,6 @@ namespace Umbraco.Web.Macros
if (string.IsNullOrEmpty(attributeValue))
attributeValue = _cookieManager.GetCookieValue(name);
break;
case '#':
attributeValue = pageElements[name]?.ToString();
break;
case '$':
attributeValue = pageElements[name]?.ToString();
if (string.IsNullOrEmpty(attributeValue))
attributeValue = ParseAttributeOnParents(pageElements, name);
break;
}
attributeValue = attributeValue?.Trim();
@@ -442,26 +400,6 @@ namespace Umbraco.Web.Macros
return attributeValue;
}
private string ParseAttributeOnParents(IDictionary pageElements, string name)
{
if (pageElements == null) throw new ArgumentNullException(nameof(pageElements));
// this was, and still is, an ugly piece of nonsense
var value = string.Empty;
var cache = _umbracoContextAccessor.UmbracoContext.Content;
var splitpath = (string[])pageElements["splitpath"];
for (var i = splitpath.Length - 1; i > 0; i--) // at 0 we have root (-1)
{
var content = cache.GetById(int.Parse(splitpath[i]));
if (content == null) continue;
value = content.Value(name)?.ToString();
if (string.IsNullOrEmpty(value) == false) break;
}
return value;
}
#endregion
}

View File

@@ -1,301 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Web.Editors;
using Umbraco.Web.Routing;
namespace Umbraco.Web.Macros
{
/// <summary>
/// Legacy class used by macros which converts a published content item into a hashset of values
/// </summary>
internal class PublishedContentHashtableConverter
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="PublishedContentHashtableConverter"/> class for a published document request.
/// </summary>
/// <param name="frequest">The <see cref="IPublishedRequest"/> pointing to the document.</param>
/// <param name="userService">The <see cref="IUserService"/>.</param>
/// <remarks>
/// The difference between creating the page with PublishedRequest vs an IPublishedContent item is
/// that the PublishedRequest takes into account how a template is assigned during the routing process whereas
/// with an IPublishedContent item, the template id is assigned purely based on the default.
/// </remarks>
internal PublishedContentHashtableConverter(IPublishedRequest frequest, IUserService userService)
{
if (!frequest.HasPublishedContent)
throw new ArgumentException("Document request has no node.", nameof(frequest));
PopulatePageData(frequest.PublishedContent.Id,
frequest.PublishedContent.Name, frequest.PublishedContent.ContentType.Id, frequest.PublishedContent.ContentType.Alias,
frequest.PublishedContent.GetWriterName(userService), frequest.PublishedContent.GetCreatorName(userService), frequest.PublishedContent.CreateDate, frequest.PublishedContent.UpdateDate,
frequest.PublishedContent.Path, frequest.PublishedContent.Parent?.Id ?? -1);
if (frequest.HasTemplate)
{
Elements["template"] = frequest.TemplateModel.Id.ToString();
}
PopulateElementData(frequest.PublishedContent);
}
/// <summary>
/// Initializes a new instance of the page for a published document
/// </summary>
/// <param name="doc"></param>
internal PublishedContentHashtableConverter(IPublishedContent doc, IUserService userService)
{
if (doc == null) throw new ArgumentNullException(nameof(doc));
PopulatePageData(doc.Id,
doc.Name, doc.ContentType.Id, doc.ContentType.Alias,
doc.GetWriterName(userService), doc.GetCreatorName(userService), doc.CreateDate, doc.UpdateDate,
doc.Path, doc.Parent?.Id ?? -1);
if (doc.TemplateId.HasValue)
{
//set the template to whatever is assigned to the doc
Elements["template"] = doc.TemplateId.Value.ToString();
}
PopulateElementData(doc);
}
/// <summary>
/// Initializes a new instance of the page for a content.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="variationContextAccessor"></param>
/// <remarks>This is for <see cref="MacroRenderingController"/> usage only.</remarks>
internal PublishedContentHashtableConverter(IContent content, IVariationContextAccessor variationContextAccessor, IUserService userService, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IPublishedContentTypeFactory publishedContentTypeFactory, UrlSegmentProviderCollection urlSegmentProviders)
: this(new PagePublishedContent(content, variationContextAccessor, userService, shortStringHelper, contentTypeBaseServiceProvider, publishedContentTypeFactory, urlSegmentProviders), userService)
{ }
#endregion
#region Initialize
private void PopulatePageData(int pageId,
string pageName, int nodeType, string nodeTypeAlias,
string writerName, string creatorName, DateTime createDate, DateTime updateDate,
string path, int parentId)
{
// Update the elements hashtable
Elements.Add("pageID", pageId);
Elements.Add("parentID", parentId);
Elements.Add("pageName", pageName);
Elements.Add("nodeType", nodeType);
Elements.Add("nodeTypeAlias", nodeTypeAlias);
Elements.Add("writerName", writerName);
Elements.Add("creatorName", creatorName);
Elements.Add("createDate", createDate);
Elements.Add("updateDate", updateDate);
Elements.Add("path", path);
Elements.Add("splitpath", path.Split(','));
}
/// <summary>
/// Puts the properties of the node into the elements table
/// </summary>
/// <param name="node"></param>
private void PopulateElementData(IPublishedElement node)
{
foreach (var p in node.Properties)
{
if (Elements.ContainsKey(p.Alias) == false)
{
// note: legacy used the raw value (see populating from an Xml node below)
// so we're doing the same here, using DataValue. If we use Value then every
// value will be converted NOW - including RTEs that may contain macros that
// require that the 'page' is already initialized = catch-22.
// to properly fix this, we'd need to turn the elements collection into some
// sort of collection of lazy values.
Elements[p.Alias] = p.GetSourceValue();
}
}
}
#endregion
/// <summary>
/// Returns a Hashtable of data for a published content item
/// </summary>
public Hashtable Elements { get; } = new Hashtable();
#region PublishedContent
private class PagePublishedProperty : PublishedPropertyBase
{
private readonly object _sourceValue;
private readonly IPublishedContent _content;
public PagePublishedProperty(IPublishedPropertyType propertyType, IPublishedContent content)
: base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored
{
_sourceValue = null;
_content = content;
}
public PagePublishedProperty(IPublishedPropertyType propertyType, IPublishedContent content, IProperty property)
: base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored
{
_sourceValue = property.GetValue();
_content = content;
}
public override bool HasValue(string culture = null, string segment = null)
{
return _sourceValue != null && ((_sourceValue is string) == false || string.IsNullOrWhiteSpace((string)_sourceValue) == false);
}
public override object GetSourceValue(string culture = null, string segment = null)
{
return _sourceValue;
}
public override object GetValue(string culture = null, string segment = null)
{
// isPreviewing is true here since we want to preview anyway...
const bool isPreviewing = true;
var source = PropertyType.ConvertSourceToInter(_content, _sourceValue, isPreviewing);
return PropertyType.ConvertInterToObject(_content, PropertyCacheLevel.Unknown, source, isPreviewing);
}
public override object GetXPathValue(string culture = null, string segment = null)
{
throw new NotImplementedException();
}
}
private class PagePublishedContent : IPublishedContent
{
private readonly IContent _inner;
private readonly IPublishedProperty[] _properties;
private IReadOnlyDictionary<string, PublishedCultureInfo> _cultureInfos;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IShortStringHelper _shortStringHelper;
private readonly UrlSegmentProviderCollection _urlSegmentProviders;
private static readonly IReadOnlyDictionary<string, PublishedCultureInfo> NoCultureInfos = new Dictionary<string, PublishedCultureInfo>();
private PagePublishedContent(int id)
{
Id = id;
}
public PagePublishedContent(IContent inner, IVariationContextAccessor variationContextAccessor, IUserService userService, IShortStringHelper shortStringHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IPublishedContentTypeFactory publishedContentTypeFactory, UrlSegmentProviderCollection urlSegmentProviders)
{
_inner = inner ?? throw new ArgumentNullException(nameof(inner));
_variationContextAccessor = variationContextAccessor;
_shortStringHelper = shortStringHelper ?? throw new ArgumentNullException(nameof(shortStringHelper));
_urlSegmentProviders = urlSegmentProviders ?? throw new ArgumentNullException(nameof(urlSegmentProviders));
Id = _inner.Id;
Key = _inner.Key;
CreatorName = _inner.GetCreatorProfile(userService)?.Name;
WriterName = _inner.GetWriterProfile(userService)?.Name;
var contentType = contentTypeBaseServiceProvider.GetContentTypeOf(_inner);
ContentType = publishedContentTypeFactory.CreateContentType(contentType);
_properties = ContentType.PropertyTypes
.Select(x =>
{
var p = _inner.Properties.SingleOrDefault(xx => xx.Alias == x.Alias);
return p == null ? new PagePublishedProperty(x, this) : new PagePublishedProperty(x, this, p);
})
.Cast<IPublishedProperty>()
.ToArray();
Parent = new PagePublishedContent(_inner.ParentId);
}
public IPublishedContentType ContentType { get; }
public int Id { get; }
public Guid Key { get; }
public int? TemplateId => _inner.TemplateId;
public int SortOrder => _inner.SortOrder;
public string Name => _inner.Name;
public IReadOnlyDictionary<string, PublishedCultureInfo> Cultures
{
get
{
if (!_inner.ContentType.VariesByCulture())
return NoCultureInfos;
if (_cultureInfos != null)
return _cultureInfos;
return _cultureInfos = _inner.PublishCultureInfos.Values
.ToDictionary(x => x.Culture, x => new PublishedCultureInfo(x.Culture, x.Name, _inner.GetUrlSegment(_shortStringHelper, _urlSegmentProviders, x.Culture), x.Date));
}
}
public string UrlSegment => throw new NotImplementedException();
public string WriterName { get; }
public string CreatorName { get; }
public int WriterId => _inner.WriterId;
public int CreatorId => _inner.CreatorId;
public string Path => _inner.Path;
public DateTime CreateDate => _inner.CreateDate;
public DateTime UpdateDate => _inner.UpdateDate;
public int Level => _inner.Level;
public string Url => throw new NotImplementedException();
public PublishedItemType ItemType => PublishedItemType.Content;
public bool IsDraft(string culture = null)
{
throw new NotImplementedException();
}
public bool IsPublished(string culture = null)
{
throw new NotImplementedException();
}
public IPublishedContent Parent { get; }
public IEnumerable<IPublishedContent> Children => throw new NotImplementedException();
public IEnumerable<IPublishedContent> ChildrenForAllCultures => throw new NotImplementedException();
public IEnumerable<IPublishedProperty> Properties => _properties;
public IPublishedProperty GetProperty(string alias)
{
throw new NotImplementedException();
}
}
#endregion
}
}

View File

@@ -61,7 +61,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
macroAlias,
umbracoContext.PublishedRequest?.PublishedContent,
//needs to be explicitly casted to Dictionary<string, object>
macroAttributes.ConvertTo(x => (string)x, x => x)).GetAsText()));
macroAttributes.ConvertTo(x => (string)x, x => x)).Text));
return sb.ToString();
}

View File

@@ -163,8 +163,6 @@
<Compile Include="Logging\WebProfilerComponent.cs" />
<Compile Include="Logging\WebProfilerComposer.cs" />
<Compile Include="Logging\WebProfilerProvider.cs" />
<Compile Include="Macros\IMacroRenderer.cs" />
<Compile Include="Macros\PublishedContentHashtableConverter.cs" />
<Compile Include="Models\Identity\BackOfficeIdentityUser.cs" />
<Compile Include="Models\Identity\IdentityMapDefinition.cs" />
<Compile Include="Models\Identity\IdentityUser.cs" />
@@ -234,7 +232,6 @@
<Compile Include="Editors\BackOfficeServerVariables.cs" />
<Compile Include="Editors\LogViewerController.cs" />
<Compile Include="ImageProcessorLogger.cs" />
<Compile Include="Macros\MacroTagParser.cs" />
<Compile Include="Trees\LogViewerTreeController.cs" />
<Compile Include="Mvc\ContainerControllerFactory.cs" />
<Compile Include="OwinExtensions.cs" />
@@ -278,10 +275,7 @@
<Compile Include="Install\InstallSteps\ConfigureMachineKey.cs" />
<Compile Include="Editors\MemberGroupController.cs" />
<Compile Include="Composing\CompositionExtensions\Controllers.cs" />
<Compile Include="Macros\MacroContent.cs" />
<Compile Include="Macros\MacroModel.cs" />
<Compile Include="HealthCheck\HealthCheckController.cs" />
<Compile Include="Macros\MacroPropertyModel.cs" />
<Compile Include="Macros\MacroRenderer.cs" />
<Compile Include="HtmlHelperBackOfficeExtensions.cs" />
<Compile Include="Composing\ModuleInjector.cs" />

View File

@@ -119,7 +119,7 @@ namespace Umbraco.Web
x => x.Key.ToLowerInvariant(),
i => (i.Value is string) ? HttpUtility.HtmlDecode(i.Value.ToString()) : i.Value);
var html = _macroRenderer.Render(alias, content, macroProps).GetAsText();
var html = _macroRenderer.Render(alias, content, macroProps).Text;
return new HtmlString(html);
}