packages partial views associated with macros.

This commit is contained in:
Shannon
2021-07-07 16:16:14 -06:00
parent 2897ef9695
commit f7d0e417d6
5 changed files with 88 additions and 8 deletions

View File

@@ -14,6 +14,7 @@ namespace Umbraco.Cms.Core.Models.Packaging
public string Name { get; set; }
public InstallWarnings Warnings { get; set; } = new InstallWarnings();
public IEnumerable<XElement> Macros { get; set; } // TODO: make strongly typed
public IEnumerable<XElement> MacroPartialViews { get; set; } // TODO: make strongly typed
public IEnumerable<XElement> Templates { get; set; } // TODO: make strongly typed
public IEnumerable<XElement> Stylesheets { get; set; } // TODO: make strongly typed
public IEnumerable<XElement> DataTypes { get; set; } // TODO: make strongly typed

View File

@@ -38,6 +38,7 @@ namespace Umbraco.Cms.Core.Packaging
PackageFile = null,
Name = package.Element("name")?.Value,
Macros = xml.Root.Element("Macros")?.Elements("macro") ?? Enumerable.Empty<XElement>(),
MacroPartialViews = xml.Root.Element("MacroPartialViews")?.Elements("view") ?? Enumerable.Empty<XElement>(),
Templates = xml.Root.Element("Templates")?.Elements("Template") ?? Enumerable.Empty<XElement>(),
Stylesheets = xml.Root.Element("Stylesheets")?.Elements("styleSheet") ?? Enumerable.Empty<XElement>(),
DataTypes = xml.Root.Element("DataTypes")?.Elements("DataType") ?? Enumerable.Empty<XElement>(),

View File

@@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Extensions.Options;
@@ -372,18 +373,30 @@ namespace Umbraco.Cms.Core.Packaging
private void PackageMacros(PackageDefinition definition, XContainer root)
{
var packagedMacros = new List<IMacro>();
var macros = new XElement("Macros");
foreach (var macroId in definition.Macros)
{
if (!int.TryParse(macroId, out var outInt))
if (!int.TryParse(macroId, out int outInt))
{
continue;
}
var macroXml = GetMacroXml(outInt, out var macro);
XElement macroXml = GetMacroXml(outInt, out IMacro macro);
if (macroXml == null)
{
continue;
}
macros.Add(macroXml);
packagedMacros.Add(macro);
}
root.Add(macros);
// get the partial views for macros and package those
IEnumerable<string> views = packagedMacros.Select(x => x.MacroSource).Where(x => x.EndsWith(".cshtml"));
PackagePartialViews(views, root, "MacroPartialViews");
}
private void PackageStylesheets(PackageDefinition definition, XContainer root)
@@ -415,6 +428,33 @@ namespace Umbraco.Cms.Core.Packaging
root.Add(templatesXml);
}
private void PackagePartialViews(IEnumerable<string> viewPaths, XContainer root, string elementName)
{
var viewsXml = new XElement(elementName);
foreach (var viewPath in viewPaths)
{
// TODO: See TODO note in MacrosController about the inconsistencies of usages of partial views
// and how paths are saved. We have no choice currently but to assume that all views are 100% always
// on the content path.
var physicalPath = _hostingEnvironment.MapPathContentRoot(viewPath);
if (!File.Exists(physicalPath))
{
throw new InvalidOperationException("Could not find partial view at path " + viewPath);
}
var fileContents = File.ReadAllText(physicalPath, Encoding.UTF8);
viewsXml.Add(
new XElement(
"view",
new XAttribute("path", viewPath),
new XCData(fileContents)));
}
root.Add(viewsXml);
}
private void PackageDocumentTypes(PackageDefinition definition, XContainer root)
{
var contentTypes = new HashSet<IContentType>();

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using Microsoft.Extensions.Logging;
@@ -39,6 +40,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
private readonly IConfigurationEditorJsonSerializer _serializer;
private readonly IMediaService _mediaService;
private readonly IMediaTypeService _mediaTypeService;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IEntityService _entityService;
private readonly IContentTypeService _contentTypeService;
private readonly IContentService _contentService;
@@ -59,7 +61,8 @@ namespace Umbraco.Cms.Infrastructure.Packaging
IOptions<GlobalSettings> globalSettings,
IConfigurationEditorJsonSerializer serializer,
IMediaService mediaService,
IMediaTypeService mediaTypeService)
IMediaTypeService mediaTypeService,
IHostingEnvironment hostingEnvironment)
{
_dataValueEditorFactory = dataValueEditorFactory;
_logger = logger;
@@ -74,6 +77,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
_serializer = serializer;
_mediaService = mediaService;
_mediaTypeService = mediaTypeService;
_hostingEnvironment = hostingEnvironment;
_entityService = entityService;
_contentTypeService = contentTypeService;
_contentService = contentService;
@@ -91,7 +95,7 @@ namespace Umbraco.Cms.Infrastructure.Packaging
DataTypesInstalled = ImportDataTypes(compiledPackage.DataTypes.ToList(), userId),
LanguagesInstalled = ImportLanguages(compiledPackage.Languages, userId),
DictionaryItemsInstalled = ImportDictionaryItems(compiledPackage.DictionaryItems, userId),
MacrosInstalled = ImportMacros(compiledPackage.Macros, userId),
MacrosInstalled = ImportMacros(compiledPackage.Macros, compiledPackage.MacroPartialViews, userId),
TemplatesInstalled = ImportTemplates(compiledPackage.Templates.ToList(), userId),
DocumentTypesInstalled = ImportDocumentTypes(compiledPackage.DocumentTypes, userId),
MediaTypesInstalled = ImportMediaTypes(compiledPackage.MediaTypes, userId),
@@ -1235,6 +1239,30 @@ namespace Umbraco.Cms.Infrastructure.Packaging
#endregion
private void ImportPartialViews(IEnumerable<XElement> viewElements)
{
foreach(XElement element in viewElements)
{
var path = element.AttributeValue<string>("path");
if (path == null)
{
throw new InvalidOperationException("No path attribute found");
}
var contents = element.Value;
if (contents.IsNullOrWhiteSpace())
{
throw new InvalidOperationException("No content found for partial view");
}
var physicalPath = _hostingEnvironment.MapPathContentRoot(path);
// TODO: Do we overwrite? IMO I don't think so since these will be views a user will change.
if (!System.IO.File.Exists(physicalPath))
{
System.IO.File.WriteAllText(physicalPath, contents, Encoding.UTF8);
}
}
}
#region Macros
/// <summary>
@@ -1243,15 +1271,20 @@ namespace Umbraco.Cms.Infrastructure.Packaging
/// <param name="macroElements">Xml to import</param>
/// <param name="userId">Optional id of the User performing the operation</param>
/// <returns></returns>
public IReadOnlyList<IMacro> ImportMacros(IEnumerable<XElement> macroElements, int userId)
public IReadOnlyList<IMacro> ImportMacros(
IEnumerable<XElement> macroElements,
IEnumerable<XElement> macroPartialViewsElements,
int userId)
{
var macros = macroElements.Select(ParseMacroElement).ToList();
foreach (var macro in macros)
foreach (IMacro macro in macros)
{
_macroService.Save(macro, userId);
}
ImportPartialViews(macroPartialViewsElements);
return macros;
}

View File

@@ -46,8 +46,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
ILogger<MacrosController> logger,
IHostingEnvironment hostingEnvironment,
IUmbracoMapper umbracoMapper
)
IUmbracoMapper umbracoMapper)
{
_parameterEditorCollection = parameterEditorCollection ?? throw new ArgumentNullException(nameof(parameterEditorCollection));
_macroService = macroService ?? throw new ArgumentNullException(nameof(macroService));
@@ -315,6 +314,12 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
/// </returns>
private IEnumerable<string> FindPartialViewFilesInViewsFolder()
{
// TODO: This is inconsistent. We have FileSystems.MacroPartialsFileSystem but we basically don't use
// that at all except to render the tree. In the future we may want to use it. This also means that
// we are storing the virtual path of the macro like ~/Views/MacroPartials/Login.cshtml instead of the
// relative path which would work with the FileSystems.MacroPartialsFileSystem, but these are incompatible.
// At some point this should all be made consistent and probably just use FileSystems.MacroPartialsFileSystem.
var partialsDir = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.MacroPartials);
return this.FindPartialViewFilesInFolder(