Merge remote-tracking branch 'origin/netcore/dev' into netcore/feature/executable-backoffice

This commit is contained in:
Bjarke Berg
2020-02-26 10:39:11 +01:00
46 changed files with 199 additions and 610 deletions
+20
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();
}
}
@@ -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;
}
}
}
-12
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();
}
}
-18
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
}
}
@@ -24,7 +24,7 @@ namespace Umbraco.Web.Templates
_publishedUrlProvider = publishedUrlProvider;
}
internal IEnumerable<Udi> FindUdisFromLocalLinks(string text)
public IEnumerable<Udi> FindUdisFromLocalLinks(string text)
{
foreach ((int? intId, GuidUdi udi, string tagValue) in FindLocalLinkIds(text))
{
@@ -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 )
@@ -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();
+1 -15
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>
@@ -1,18 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Trees;
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
namespace Umbraco.Web.Models.Mapping
@@ -23,17 +20,15 @@ namespace Umbraco.Web.Models.Mapping
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
private readonly ContentAppFactoryCollection _contentAppDefinitions;
private readonly ILocalizedTextService _localizedTextService;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor,
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService, IHttpContextAccessor httpContextAccessor)
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService)
{
_userService = userService;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
_contentAppDefinitions = contentAppDefinitions;
_localizedTextService = localizedTextService;
_httpContextAccessor = httpContextAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
}
@@ -64,25 +59,6 @@ namespace Umbraco.Web.Models.Mapping
return null;
}
public string GetTreeNodeUrl<TController>(IContentBase source)
where TController : ContentTreeControllerBase
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return null;
var urlHelper = new UrlHelper(httpContext.Request.RequestContext);
return urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
}
public string GetMemberTreeNodeUrl(IContentBase source)
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return null;
var urlHelper = new UrlHelper(httpContext.Request.RequestContext);
return urlHelper.GetUmbracoApiService<MemberTreeController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
}
public IEnumerable<ContentApp> GetContentApps(IContentBase source)
{
var apps = _contentAppDefinitions.GetContentAppsFor(source).ToArray();
@@ -11,7 +11,7 @@ using Umbraco.Examine;
namespace Umbraco.Web.Models.Mapping
{
internal class EntityMapDefinition : IMapDefinition
public class EntityMapDefinition : IMapDefinition
{
public void DefineMaps(UmbracoMapper mapper)
{
@@ -236,7 +236,7 @@ namespace Umbraco.Web.Models.Mapping
return memberEntity.ContentTypeIcon.IfNullOrWhiteSpace(Constants.Icons.Member);
case IContentEntitySlim contentEntity:
// NOTE: this case covers both content and media entities
return contentEntity.ContentTypeIcon;
return contentEntity.ContentTypeIcon;
}
return null;
@@ -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");
@@ -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)
@@ -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));
@@ -1,10 +1,8 @@
using Newtonsoft.Json;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Web.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -64,7 +62,7 @@ namespace Umbraco.Web.PropertyEditors
/// Overridden to ensure that the value is validated
/// </summary>
/// <returns></returns>
protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute,_umbracoContextAccessor, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper, _imageUrlGenerator);
protected override IDataValueEditor CreateValueEditor() => new GridPropertyValueEditor(Attribute, _umbracoContextAccessor, DataTypeService, LocalizationService, LocalizedTextService, _imageSourceParser, _pastedImages, _localLinkParser, ShortStringHelper, _imageUrlGenerator);
protected override IConfigurationEditor CreateConfigurationEditor() => new GridConfigurationEditor(_ioHelper);
@@ -1,18 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Xml;
using Umbraco.Examine;
namespace Umbraco.Web.PropertyEditors
{
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
/// <summary>
/// Parses the grid value into indexable values
/// </summary>
@@ -1,7 +1,7 @@
using HtmlAgilityPack;
using System;
using System;
using System.Collections.Generic;
using System.IO;
using HtmlAgilityPack;
using Umbraco.Core;
using Umbraco.Core.Exceptions;
using Umbraco.Core.IO;
@@ -9,6 +9,7 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Strings;
using Umbraco.Web.Routing;
using Umbraco.Web.Templates;
namespace Umbraco.Web.PropertyEditors
@@ -22,10 +23,11 @@ namespace Umbraco.Web.PropertyEditors
private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider;
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IShortStringHelper _shortStringHelper;
private readonly IPublishedUrlProvider _publishedUrlProvider;
const string TemporaryImageDataAttribute = "data-tmpimg";
public RichTextEditorPastedImages(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IIOHelper ioHelper, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper)
public RichTextEditorPastedImages(IUmbracoContextAccessor umbracoContextAccessor, ILogger logger, IIOHelper ioHelper, IMediaService mediaService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, IPublishedUrlProvider publishedUrlProvider)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
@@ -34,6 +36,7 @@ namespace Umbraco.Web.PropertyEditors
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider ?? throw new ArgumentNullException(nameof(contentTypeBaseServiceProvider));
_mediaFileSystem = mediaFileSystem;
_shortStringHelper = shortStringHelper;
_publishedUrlProvider = publishedUrlProvider;
}
/// <summary>
@@ -43,7 +46,7 @@ namespace Umbraco.Web.PropertyEditors
/// <param name="mediaParentFolder"></param>
/// <param name="userId"></param>
/// <returns></returns>
internal string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId, IImageUrlGenerator imageUrlGenerator)
public string FindAndPersistPastedTempImages(string html, Guid mediaParentFolder, int userId, IImageUrlGenerator imageUrlGenerator)
{
// Find all img's that has data-tmpimg attribute
// Use HTML Agility Pack - https://html-agility-pack.net
@@ -108,7 +111,7 @@ namespace Umbraco.Web.PropertyEditors
if (mediaTyped == null)
throw new PanicException($"Could not find media by id {udi.Guid} or there was no UmbracoContext available.");
var location = mediaTyped.Url();
var location = mediaTyped.Url(_publishedUrlProvider);
// Find the width & height attributes as we need to set the imageprocessor QueryString
var width = img.GetAttributeValue("width", int.MinValue);
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using Umbraco.Core;
using Umbraco.Web.Composing;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
@@ -1,13 +1,13 @@
using System.Text;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Web.Templates;
using System.Linq;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using Umbraco.Web.Macros;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Strings;
using Umbraco.Web.Macros;
using Umbraco.Web.Templates;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
@@ -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();
}
@@ -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()));
@@ -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" />
+4 -6
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)
+1 -1
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();
@@ -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();
}
@@ -48,7 +48,7 @@ namespace Umbraco.Tests.PublishedContent
var logger = Mock.Of<ILogger>();
var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider);
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, Mock.Of<IMediaService>(), Mock.Of<IContentTypeBaseServiceProvider>(), Mock.Of<IMediaFileSystem>(), ShortStringHelper);
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, Mock.Of<IMediaService>(), Mock.Of<IContentTypeBaseServiceProvider>(), Mock.Of<IMediaFileSystem>(), ShortStringHelper, publishedUrlProvider);
var localLinkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider);
var dataTypeService = new TestObjects.TestDataTypeService(
new DataType(new RichTextPropertyEditor(
@@ -52,7 +52,7 @@ namespace Umbraco.Tests.PublishedContent
var umbracoContextAccessor = Mock.Of<IUmbracoContextAccessor>();
var publishedUrlProvider = Mock.Of<IPublishedUrlProvider>();
var imageSourceParser = new HtmlImageSourceParser(publishedUrlProvider);
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper);
var pastedImages = new RichTextEditorPastedImages(umbracoContextAccessor, logger, IOHelper, mediaService, contentTypeBaseServiceProvider, mediaFileService, ShortStringHelper, publishedUrlProvider);
var linkParser = new HtmlLocalLinkParser(umbracoContextAccessor, publishedUrlProvider);
var localizationService = Mock.Of<ILocalizationService>();
@@ -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
+10 -10
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));
@@ -32,6 +32,7 @@ namespace Umbraco.Web.Composing.CompositionExtensions
.Add<IdentityMapDefinition>();;
composition.Register<CommonMapper>();
composition.Register<CommonTreeNodeMapper>();
composition.Register<MemberTabsAndPropertiesMapper>();
return composition;
@@ -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
+1 -3
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
-53
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);
}
}
}
+15 -77
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
}
@@ -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
}
}
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Trees;
using Umbraco.Web.WebApi;
using UserProfile = Umbraco.Web.Models.ContentEditing.UserProfile;
namespace Umbraco.Web.Models.Mapping
{
public class CommonTreeNodeMapper
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CommonTreeNodeMapper(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string GetTreeNodeUrl<TController>(IContentBase source)
where TController : UmbracoApiController, ITreeNodeController
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null) return null;
var urlHelper = new UrlHelper(httpContext.Request.RequestContext);
return urlHelper.GetUmbracoApiService<TController>(controller => controller.GetTreeNode(source.Key.ToString("N"), null));
}
}
}
@@ -21,6 +21,7 @@ namespace Umbraco.Web.Models.Mapping
internal class ContentMapDefinition : IMapDefinition
{
private readonly CommonMapper _commonMapper;
private readonly CommonTreeNodeMapper _commonTreeNodeMapper;
private readonly ICultureDictionary _cultureDictionary;
private readonly ILocalizedTextService _localizedTextService;
private readonly IContentService _contentService;
@@ -41,11 +42,12 @@ namespace Umbraco.Web.Models.Mapping
private readonly ContentVariantMapper _contentVariantMapper;
public ContentMapDefinition(CommonMapper commonMapper, ICultureDictionary cultureDictionary, ILocalizedTextService localizedTextService, IContentService contentService, IContentTypeService contentTypeService,
public ContentMapDefinition(CommonMapper commonMapper, CommonTreeNodeMapper commonTreeNodeMapper, ICultureDictionary cultureDictionary, ILocalizedTextService localizedTextService, IContentService contentService, IContentTypeService contentTypeService,
IFileService fileService, IUmbracoContextAccessor umbracoContextAccessor, IPublishedRouter publishedRouter, ILocalizationService localizationService, ILogger logger,
IUserService userService, IVariationContextAccessor variationContextAccessor, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, UriUtility uriUtility, IPublishedUrlProvider publishedUrlProvider, IEntityService entityService)
{
_commonMapper = commonMapper;
_commonTreeNodeMapper = commonTreeNodeMapper;
_cultureDictionary = cultureDictionary;
_localizedTextService = localizedTextService;
_contentService = contentService;
@@ -105,7 +107,7 @@ namespace Umbraco.Web.Models.Mapping
target.TemplateAlias = GetDefaultTemplate(source);
target.TemplateId = source.TemplateId ?? default;
target.Trashed = source.Trashed;
target.TreeNodeUrl = _commonMapper.GetTreeNodeUrl<ContentTreeController>(source);
target.TreeNodeUrl = _commonTreeNodeMapper.GetTreeNodeUrl<ContentTreeController>(source);
target.Udi = Udi.Create(source.Blueprint ? Constants.UdiEntityType.DocumentBlueprint : Constants.UdiEntityType.Document, source.Key);
target.UpdateDate = source.UpdateDate;
target.Updater = _commonMapper.GetCreator(source, context);
@@ -18,16 +18,18 @@ namespace Umbraco.Web.Models.Mapping
public class MediaMapDefinition : IMapDefinition
{
private readonly CommonMapper _commonMapper;
private readonly CommonTreeNodeMapper _commonTreeNodeMapper;
private readonly IMediaService _mediaService;
private readonly IMediaTypeService _mediaTypeService;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly TabsAndPropertiesMapper<IMedia> _tabsAndPropertiesMapper;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
public MediaMapDefinition(ICultureDictionary cultureDictionary, CommonMapper commonMapper, IMediaService mediaService, IMediaTypeService mediaTypeService,
public MediaMapDefinition(ICultureDictionary cultureDictionary, CommonMapper commonMapper, CommonTreeNodeMapper commonTreeNodeMapper, IMediaService mediaService, IMediaTypeService mediaTypeService,
ILocalizedTextService localizedTextService, MediaUrlGeneratorCollection mediaUrlGenerators, IUmbracoSettingsSection umbracoSettingsSection, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider)
{
_commonMapper = commonMapper;
_commonTreeNodeMapper = commonTreeNodeMapper;
_mediaService = mediaService;
_mediaTypeService = mediaTypeService;
_mediaUrlGenerators = mediaUrlGenerators;
@@ -71,7 +73,7 @@ namespace Umbraco.Web.Models.Mapping
target.State = null;
target.Tabs = _tabsAndPropertiesMapper.Map(source, context);
target.Trashed = source.Trashed;
target.TreeNodeUrl = _commonMapper.GetTreeNodeUrl<MediaTreeController>(source);
target.TreeNodeUrl = _commonTreeNodeMapper.GetTreeNodeUrl<MediaTreeController>(source);
target.Udi = Udi.Create(Constants.UdiEntityType.Media, source.Key);
target.UpdateDate = source.UpdateDate;
target.VariesByCulture = source.ContentType.VariesByCulture();
@@ -1,7 +1,9 @@
using Umbraco.Core;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Trees;
namespace Umbraco.Web.Models.Mapping
{
@@ -11,13 +13,17 @@ namespace Umbraco.Web.Models.Mapping
public class MemberMapDefinition : IMapDefinition
{
private readonly CommonMapper _commonMapper;
private readonly CommonTreeNodeMapper _commonTreeNodeMapper;
private readonly MemberTabsAndPropertiesMapper _tabsAndPropertiesMapper;
private readonly IHttpContextAccessor _httpContextAccessor;
public MemberMapDefinition(CommonMapper commonMapper, MemberTabsAndPropertiesMapper tabsAndPropertiesMapper)
public MemberMapDefinition(CommonMapper commonMapper, CommonTreeNodeMapper commonTreeNodeMapper, MemberTabsAndPropertiesMapper tabsAndPropertiesMapper, IHttpContextAccessor httpContextAccessor)
{
_commonMapper = commonMapper;
_commonTreeNodeMapper = commonTreeNodeMapper;
_tabsAndPropertiesMapper = tabsAndPropertiesMapper;
_httpContextAccessor = httpContextAccessor;
}
public void DefineMaps(UmbracoMapper mapper)
@@ -48,7 +54,7 @@ namespace Umbraco.Web.Models.Mapping
target.SortOrder = source.SortOrder;
target.State = null;
target.Tabs = _tabsAndPropertiesMapper.Map(source, context);
target.TreeNodeUrl = _commonMapper.GetMemberTreeNodeUrl(source);
target.TreeNodeUrl = _commonTreeNodeMapper.GetTreeNodeUrl<MemberTreeController>(source);
target.Udi = Udi.Create(Constants.UdiEntityType.Member, source.Key);
target.UpdateDate = source.UpdateDate;
target.Username = source.Username;
@@ -92,5 +98,7 @@ namespace Umbraco.Web.Models.Mapping
target.Properties = context.MapEnumerable<IProperty, ContentPropertyDto>(source.Properties);
}
}
}
@@ -12,7 +12,6 @@ using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using System.Globalization;
using Umbraco.Core.Models.Entities;
using System.Web.Http.ModelBinding;
using Umbraco.Web.Actions;
@@ -26,7 +25,7 @@ using Umbraco.Web.Routing;
namespace Umbraco.Web.Trees
{
public abstract class ContentTreeControllerBase : TreeController
public abstract class ContentTreeControllerBase : TreeController, ITreeNodeController
{
public IMenuItemCollectionFactory MenuItemCollectionFactory { get; }
@@ -0,0 +1,22 @@
using System.Net.Http.Formatting;
using Umbraco.Web.Models.Trees;
using Umbraco.Web.WebApi.Filters;
using System.Web.Http.ModelBinding;
namespace Umbraco.Web.Trees
{
/// <summary>
/// Represents an TreeNodeController
/// </summary>
public interface ITreeNodeController
{
/// <summary>
/// Gets an individual tree node
/// </summary>
/// <param name="id"></param>
/// <param name="queryStrings"></param>
/// <returns></returns>
TreeNode GetTreeNode(string id, [ModelBinder(typeof(HttpQueryStringModelBinder))]
FormDataCollection queryStrings);
}
}
+1 -1
View File
@@ -37,7 +37,7 @@ namespace Umbraco.Web.Trees
[PluginController("UmbracoTrees")]
[CoreTree]
[SearchableTree("searchResultFormatter", "configureMediaResult", 20)]
public class MediaTreeController : ContentTreeControllerBase, ISearchableTree
public class MediaTreeController : ContentTreeControllerBase, ISearchableTree, ITreeNodeController
{
private readonly UmbracoTreeSearcher _treeSearcher;
@@ -37,7 +37,7 @@ namespace Umbraco.Web.Trees
[PluginController("UmbracoTrees")]
[CoreTree]
[SearchableTree("searchResultFormatter", "configureMemberResult")]
public class MemberTreeController : TreeController, ISearchableTree
public class MemberTreeController : TreeController, ISearchableTree, ITreeNodeController
{
+5 -15
View File
@@ -55,6 +55,9 @@
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Mvc, Version=5.2.7.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<HintPath>C:\Users\Bjarke\.nuget\packages\microsoft.aspnet.mvc\5.2.7\lib\net45\System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Web.Services" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
@@ -163,15 +166,12 @@
<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" />
<Compile Include="Models\Identity\UserLoginInfoWrapper.cs" />
<Compile Include="Models\Mapping\CommonMapper.cs" />
<Compile Include="Models\Mapping\CommonTreeNodeMapper.cs" />
<Compile Include="Models\Mapping\ContentMapDefinition.cs" />
<Compile Include="Models\Mapping\EntityMapDefinition.cs" />
<Compile Include="Models\Mapping\MediaMapDefinition.cs" />
<Compile Include="Models\Mapping\MemberMapDefinition.cs" />
<Compile Include="Models\Membership\UmbracoMembershipMember.cs" />
@@ -187,10 +187,6 @@
<Compile Include="AspNet\AspNetPasswordHasher.cs" />
<Compile Include="AspNet\AspNetSessionIdResolver.cs" />
<Compile Include="Profiling\WebProfilingController.cs" />
<Compile Include="PropertyEditors\GridPropertyEditor.cs" />
<Compile Include="PropertyEditors\RichTextEditorPastedImages.cs" />
<Compile Include="PropertyEditors\RichTextPropertyEditor.cs" />
<Compile Include="PropertyEditors\ValueConverters\RteMacroRenderingValueConverter.cs" />
<Compile Include="RoutableDocumentFilter.cs" />
<Compile Include="Runtime\AspNetUmbracoBootPermissionChecker.cs" />
<Compile Include="Scheduling\SchedulerComponent.cs" />
@@ -209,6 +205,7 @@
<Compile Include="Security\UmbracoMembershipProviderBase.cs" />
<Compile Include="Security\UserAwarePasswordHasher.cs" />
<Compile Include="StringExtensions.cs" />
<Compile Include="Trees\ITreeNodeController.cs" />
<Compile Include="Trees\TreeCollectionBuilder.cs" />
<Compile Include="UmbracoContext.cs" />
<Compile Include="UmbracoContextFactory.cs" />
@@ -217,7 +214,6 @@
<Compile Include="ViewDataExtensions.cs" />
<Compile Include="WebApi\Filters\AdminUsersAuthorizeAttribute.cs" />
<Compile Include="WebApi\Filters\OnlyLocalRequestsAttribute.cs" />
<Compile Include="PropertyEditors\GridPropertyIndexValueFactory.cs" />
<Compile Include="Routing\RedirectTrackingComposer.cs" />
<Compile Include="Runtime\WebInitialComposer.cs" />
<Compile Include="Security\ActiveDirectoryBackOfficeUserPasswordChecker.cs" />
@@ -234,7 +230,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 +273,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" />
@@ -604,6 +596,4 @@
</None>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
+1 -1
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);
}
+1 -1
View File
@@ -57,7 +57,7 @@ namespace Umbraco.Web
//
// all in all, this context may be disposed more than once, but DisposableObject ensures that
// it is ok and it will be actually disposed only once.
httpContextAccessor.GetRequiredHttpContext().DisposeOnPipelineCompleted(this);
httpContextAccessor.HttpContext?.DisposeOnPipelineCompleted(this);
ObjectCreated = DateTime.Now;
UmbracoRequestId = Guid.NewGuid();