mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Working towards definition import/export
Reader and writer mapping definition to infoset Devtools placeholder providing way to see/alter metadata Reader on builder over existing content definition provides merge capabilies on import --HG-- branch : dev
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
using Orchard.ContentManagement.MetaData.Services;
|
||||
|
||||
namespace Orchard.Tests.ContentManagement.MetaData.Services {
|
||||
[TestFixture]
|
||||
public class ContentDefinitionReaderTests {
|
||||
private IContentDefinitionReader _reader;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_reader = new ContentDefinitionReader(new SettingsFormatter());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadingElementSetsName() {
|
||||
var builder = new ContentTypeDefinitionBuilder();
|
||||
_reader.Merge(new XElement("foo"), builder);
|
||||
var type = builder.Build();
|
||||
Assert.That(type.Name, Is.EqualTo("foo"));
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void AttributesAreAppliedAsSettings() {
|
||||
var builder = new ContentTypeDefinitionBuilder();
|
||||
_reader.Merge(new XElement("foo", new XAttribute("x", "1")), builder);
|
||||
var type = builder.Build();
|
||||
Assert.That(type.Settings["x"], Is.EqualTo("1"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChildElementsAreAddedAsPartsWithSettings() {
|
||||
var builder = new ContentTypeDefinitionBuilder();
|
||||
_reader.Merge(new XElement("foo", new XElement("bar", new XAttribute("y", "2"))), builder);
|
||||
var type = builder.Build();
|
||||
Assert.That(type.Parts.Single().PartDefinition.Name, Is.EqualTo("bar"));
|
||||
Assert.That(type.Parts.Single().Settings["y"], Is.EqualTo("2"));
|
||||
}
|
||||
|
||||
[Test, Ignore("Parts can be removed by name")]
|
||||
public void PartsCanBeRemovedByNameWhenImporting() {
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using NUnit.Framework;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
using Orchard.ContentManagement.MetaData.Services;
|
||||
|
||||
namespace Orchard.Tests.ContentManagement.MetaData.Services {
|
||||
[TestFixture]
|
||||
public class ContentDefinitionWriterTests {
|
||||
private ContentDefinitionWriter _writer;
|
||||
|
||||
[SetUp]
|
||||
public void Init() {
|
||||
_writer = new ContentDefinitionWriter(new SettingsFormatter());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CreatesElementWithEncodedContentTypeName() {
|
||||
var alphaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named("alpha").Build());
|
||||
var betaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named(":beta").Build());
|
||||
var gammaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named(" g a m m a ").Build());
|
||||
var deltaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named("del\r\nta").Build());
|
||||
|
||||
Assert.That(XmlConvert.DecodeName(alphaInfoset.Name.LocalName), Is.EqualTo("alpha"));
|
||||
Assert.That(XmlConvert.DecodeName(betaInfoset.Name.LocalName), Is.EqualTo(":beta"));
|
||||
Assert.That(XmlConvert.DecodeName(gammaInfoset.Name.LocalName), Is.EqualTo(" g a m m a "));
|
||||
Assert.That(XmlConvert.DecodeName(deltaInfoset.Name.LocalName), Is.EqualTo("del\r\nta"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ChildElementsArePartNames() {
|
||||
var alphaInfoset = _writer.Export(new ContentTypeDefinitionBuilder().Named("alpha").WithPart(":beta").WithPart("del\r\nta").Build());
|
||||
|
||||
Assert.That(XmlConvert.DecodeName(alphaInfoset.Name.LocalName), Is.EqualTo("alpha"));
|
||||
Assert.That(alphaInfoset.Elements().Count(), Is.EqualTo(2));
|
||||
Assert.That(alphaInfoset.Elements().Select(elt => elt.Name.LocalName), Has.Some.EqualTo(XmlConvert.EncodeLocalName(":beta")));
|
||||
Assert.That(alphaInfoset.Elements().Select(elt => elt.Name.LocalName), Has.Some.EqualTo(XmlConvert.EncodeLocalName("del\r\nta")));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TypeAndTypePartSettingsAreAttributes() {
|
||||
|
||||
var alpha = new ContentTypeDefinitionBuilder()
|
||||
.Named("alpha")
|
||||
.WithSetting("x", "1")
|
||||
.WithPart("beta", part => part.WithSetting(" y ", "2"))
|
||||
.Build();
|
||||
|
||||
var alphaInfoset = _writer.Export(alpha);
|
||||
Assert.That(alphaInfoset.Attributes("x").Single().Value, Is.EqualTo("1"));
|
||||
Assert.That(alphaInfoset.Elements("beta").Attributes(XmlConvert.EncodeLocalName(" y ")).Single().Value, Is.EqualTo("2"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -154,6 +154,8 @@
|
||||
<Compile Include="ContentManagement\Handlers\ContentHandlerTests.cs" />
|
||||
<Compile Include="ContentManagement\Handlers\ModelBuilderTests.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Builders\ContentTypeDefinitionBuilderTests.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionReaderTests.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriterTests.cs" />
|
||||
<Compile Include="ContentManagement\Models\Alpha.cs" />
|
||||
<Compile Include="ContentManagement\Models\AlphaHandler.cs" />
|
||||
<Compile Include="ContentManagement\Models\Beta.cs" />
|
||||
|
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.DevTools.ViewModels;
|
||||
|
||||
namespace Orchard.DevTools.Controllers {
|
||||
[ValidateInput(false)]
|
||||
public class MetadataController : Controller {
|
||||
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||
private readonly IContentDefinitionWriter _contentDefinitionWriter;
|
||||
private readonly IContentDefinitionReader _contentDefinitionReader;
|
||||
|
||||
public MetadataController(
|
||||
IContentDefinitionManager contentDefinitionManager,
|
||||
IContentDefinitionWriter contentDefinitionWriter,
|
||||
IContentDefinitionReader contentDefinitionReader) {
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
_contentDefinitionWriter = contentDefinitionWriter;
|
||||
_contentDefinitionReader = contentDefinitionReader;
|
||||
}
|
||||
|
||||
public ActionResult Index() {
|
||||
var model = new MetadataIndexViewModel {
|
||||
TypeDefinitions = _contentDefinitionManager.ListTypeDefinitions(),
|
||||
PartDefinitions = _contentDefinitionManager.ListPartDefinitions()
|
||||
};
|
||||
var types = new XElement("Types");
|
||||
foreach (var type in model.TypeDefinitions) {
|
||||
types.Add(_contentDefinitionWriter.Export(type));
|
||||
}
|
||||
|
||||
var parts = new XElement("Parts");
|
||||
foreach (var part in model.PartDefinitions) {
|
||||
parts.Add(_contentDefinitionWriter.Export(part));
|
||||
}
|
||||
|
||||
var stringWriter = new StringWriter();
|
||||
using (var xmlWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { Indent = true, IndentChars = " " })) {
|
||||
if (xmlWriter != null) {
|
||||
new XElement("Orchard", types, parts).WriteTo(xmlWriter);
|
||||
}
|
||||
}
|
||||
model.ExportText = stringWriter.ToString();
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public ActionResult Index(MetadataIndexViewModel model) {
|
||||
var root = XElement.Parse(model.ExportText);
|
||||
foreach (var element in root.Elements("Types").Elements()) {
|
||||
var typeElement = element;
|
||||
var typeName = XmlConvert.DecodeName(element.Name.LocalName);
|
||||
_contentDefinitionManager.AlterTypeDefinition(typeName, alteration => _contentDefinitionReader.Merge(typeElement, alteration));
|
||||
}
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
||||
}
|
@@ -73,6 +73,7 @@
|
||||
<Compile Include="Commands\ProfilingCommands.cs" />
|
||||
<Compile Include="Controllers\ContentController.cs" />
|
||||
<Compile Include="Controllers\HomeController.cs" />
|
||||
<Compile Include="Controllers\MetadataController.cs" />
|
||||
<Compile Include="Handlers\DebugLinkHandler.cs" />
|
||||
<Compile Include="Models\ShowDebugLink.cs" />
|
||||
<Compile Include="Models\Simple.cs" />
|
||||
@@ -80,6 +81,7 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="ViewModels\ContentIndexViewModel.cs" />
|
||||
<Compile Include="ViewModels\ContentDetailsViewModel.cs" />
|
||||
<Compile Include="ViewModels\MetadataIndexViewModel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Module.txt" />
|
||||
@@ -90,6 +92,7 @@
|
||||
<Content Include="Views\Home\Index.aspx" />
|
||||
<Content Include="Views\DisplayTemplates\Parts\DevTools.ShowDebugLink.ascx" />
|
||||
<Content Include="Views\EditorTemplates\Parts\DevTools.ShowDebugLink.ascx" />
|
||||
<Content Include="Views\Metadata\Index.aspx" />
|
||||
<Content Include="Web.config" />
|
||||
<Content Include="Views\Web.config" />
|
||||
</ItemGroup>
|
||||
|
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.Mvc.ViewModels;
|
||||
|
||||
namespace Orchard.DevTools.ViewModels {
|
||||
public class MetadataIndexViewModel : BaseViewModel {
|
||||
public IEnumerable<ContentTypeDefinition> TypeDefinitions { get; set; }
|
||||
public IEnumerable<ContentPartDefinition> PartDefinitions { get; set; }
|
||||
public string ExportText { get; set; }
|
||||
}
|
||||
}
|
@@ -2,4 +2,5 @@
|
||||
<%@ Import Namespace="Orchard.Mvc.ViewModels"%>
|
||||
<h1><%=Html.TitleForPage(T("Dev Tools").ToString()) %></h1>
|
||||
<p><%=Html.ActionLink(T("Contents").ToString(), "Index", "Content") %></p>
|
||||
<p><%=Html.ActionLink(T("Metadata").ToString(), "Index", "Metadata") %></p>
|
||||
<p><%=Html.ActionLink(T("Test Unauthorized Request").ToString(), "NotAuthorized", "Home")%></p>
|
||||
|
@@ -0,0 +1,44 @@
|
||||
<%@ Page Language="C#" Inherits="Orchard.Mvc.ViewPage<MetadataIndexViewModel>" %>
|
||||
|
||||
<%@ Import Namespace="Orchard.DevTools.ViewModels" %>
|
||||
<style title="text/css">
|
||||
ul
|
||||
{
|
||||
margin-left: 12px;
|
||||
}
|
||||
</style>
|
||||
<h1>
|
||||
Metadata</h1>
|
||||
<h2>
|
||||
Content Type Definitions</h2>
|
||||
<ul>
|
||||
<%foreach (var type in Model.TypeDefinitions) {%>
|
||||
<li>
|
||||
<%:type.Name %>
|
||||
<ul>
|
||||
<%foreach (var part in type.Parts) {%>
|
||||
<li>
|
||||
<%:part.PartDefinition.Name %></li>
|
||||
<%
|
||||
}%>
|
||||
</ul>
|
||||
</li>
|
||||
<%
|
||||
}%>
|
||||
</ul>
|
||||
<h2>
|
||||
Content Part Definitions</h2>
|
||||
<ul>
|
||||
<%foreach (var part in Model.PartDefinitions) {%>
|
||||
<li>
|
||||
<%:part.Name %></li>
|
||||
<%
|
||||
}%>
|
||||
</ul>
|
||||
<h2>
|
||||
Exported as xml</h2>
|
||||
<% using (Html.BeginFormAntiForgeryPost()) { %>
|
||||
<%:Html.TextAreaFor(m=>m.ExportText, new{style="width:100%;height:640px;"}) %>
|
||||
<br />
|
||||
<input class="button primaryAction" type="submit" value="<%=_Encoded("Merge Changes") %>" />
|
||||
<%} %>
|
@@ -96,6 +96,7 @@
|
||||
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
|
||||
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
|
||||
<Name>Orchard.Framework</Name>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
|
@@ -10,6 +10,7 @@ using Orchard.Users.Services;
|
||||
using Orchard.Users.ViewModels;
|
||||
|
||||
namespace Orchard.Users.Controllers {
|
||||
[ValidateInput(false)]
|
||||
public class AdminController : Controller, IUpdateModel {
|
||||
private readonly IMembershipService _membershipService;
|
||||
private readonly IUserService _userService;
|
||||
|
@@ -0,0 +1,17 @@
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData {
|
||||
public interface IContentDefinitionReader : IDependency {
|
||||
void Merge(XElement source, ContentTypeDefinitionBuilder builder);
|
||||
}
|
||||
|
||||
public static class ContentDefinitionReaderExtensions {
|
||||
public static ContentTypeDefinition Import(this IContentDefinitionReader reader, XElement source) {
|
||||
var target = new ContentTypeDefinitionBuilder();
|
||||
reader.Merge(source, target);
|
||||
return target.Build();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData {
|
||||
public interface IContentDefinitionWriter : IDependency{
|
||||
XElement Export(ContentTypeDefinition typeDefinition);
|
||||
XElement Export(ContentPartDefinition partDefinition);
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Services {
|
||||
public class ContentDefinitionReader : IContentDefinitionReader {
|
||||
private readonly IMapper<XElement, IDictionary<string, string>> _settingsReader;
|
||||
|
||||
public ContentDefinitionReader(IMapper<XElement, IDictionary<string, string>> settingsReader) {
|
||||
_settingsReader = settingsReader;
|
||||
}
|
||||
|
||||
public void Merge(XElement source, ContentTypeDefinitionBuilder builder) {
|
||||
builder.Named(XmlConvert.DecodeName(source.Name.LocalName));
|
||||
foreach (var setting in _settingsReader.Map(source)) {
|
||||
builder.WithSetting(setting.Key, setting.Value);
|
||||
}
|
||||
foreach (var iter in source.Elements()) {
|
||||
var partElement = iter;
|
||||
builder.WithPart(
|
||||
XmlConvert.DecodeName(partElement.Name.LocalName),
|
||||
partBuilder => {
|
||||
foreach (var setting in _settingsReader.Map(partElement)) {
|
||||
partBuilder.WithSetting(setting.Key, setting.Value);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Services {
|
||||
public class ContentDefinitionWriter : IContentDefinitionWriter {
|
||||
private readonly IMapper<IDictionary<string, string>, XElement> _settingsWriter;
|
||||
|
||||
public ContentDefinitionWriter(IMapper<IDictionary<string, string>, XElement> settingsWriter) {
|
||||
_settingsWriter = settingsWriter;
|
||||
}
|
||||
|
||||
public XElement Export(ContentTypeDefinition typeDefinition) {
|
||||
var typeElement = NewElement(typeDefinition.Name, typeDefinition.Settings);
|
||||
|
||||
foreach(var typePart in typeDefinition.Parts) {
|
||||
typeElement.Add(NewElement(typePart.PartDefinition.Name, typePart.Settings));
|
||||
}
|
||||
return typeElement;
|
||||
}
|
||||
|
||||
public XElement Export(ContentPartDefinition partDefinition) {
|
||||
var partElement = NewElement(partDefinition.Name, partDefinition.Settings);
|
||||
foreach(var partField in partDefinition.Fields) {
|
||||
var partFieldElement = NewElement(partField.Name, partField.Settings);
|
||||
partFieldElement.SetAttributeValue("FieldType", partField.FieldDefinition.Name);
|
||||
partElement.Add(partFieldElement);
|
||||
}
|
||||
return partElement;
|
||||
}
|
||||
|
||||
private XElement NewElement(string name, IDictionary<string, string> settings) {
|
||||
var element = new XElement(XmlConvert.EncodeLocalName(name));
|
||||
foreach(var settingAttribute in _settingsWriter.Map(settings).Attributes()) {
|
||||
element.Add(settingAttribute);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Orchard.ContentManagement.MetaData.Services {
|
||||
@@ -11,14 +12,14 @@ namespace Orchard.ContentManagement.MetaData.Services {
|
||||
if (source == null)
|
||||
return new Dictionary<string, string>();
|
||||
|
||||
return source.Attributes().ToDictionary(attr => attr.Name.LocalName, attr => attr.Value);
|
||||
return source.Attributes().ToDictionary(attr => XmlConvert.DecodeName(attr.Name.LocalName), attr => attr.Value);
|
||||
}
|
||||
|
||||
public XElement Map(IDictionary<string, string> source) {
|
||||
if (source == null)
|
||||
return new XElement("settings");
|
||||
|
||||
return new XElement("settings", source.Select(kv => new XAttribute(kv.Key, kv.Value)));
|
||||
return new XElement("settings", source.Select(kv => new XAttribute(XmlConvert.EncodeLocalName(kv.Key), kv.Value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -296,7 +296,10 @@
|
||||
<Compile Include="ContentManagement\MetaData\ContentPartInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionWriter.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\IContentDefinitionManager.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\IContentDefinitionReader.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\IContentDefinitionWriter.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Models\ContentFieldDefinition.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Models\ContentPartDefinition.cs">
|
||||
<SubType>Code</SubType>
|
||||
@@ -304,6 +307,7 @@
|
||||
<Compile Include="ContentManagement\MetaData\Models\ContentTypeDefinition.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ContentManagement\MetaData\Services\ContentDefinitionReader.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Services\SettingsFormatter.cs" />
|
||||
<Compile Include="ContentManagement\Records\ContentItemAlteration.cs">
|
||||
<SubType>Code</SubType>
|
||||
|
Reference in New Issue
Block a user