Implementing "Imported" audit trail event for content items and types.

This commit is contained in:
Sipke Schoorstra
2014-08-07 02:47:26 -07:00
parent 6cc6ffc252
commit 8555f1ae40
32 changed files with 451 additions and 80 deletions

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
namespace Orchard.AuditTrail.Helpers {
public static class EventDataExtensions {
@@ -11,5 +12,19 @@ namespace Orchard.AuditTrail.Helpers {
return (T) Convert.ChangeType(value, typeof (T));
}
public static XElement GetXml(this IDictionary<string, object> eventData, string key) {
var data = eventData.Get<string>(key);
if (String.IsNullOrWhiteSpace(data))
return null;
try {
return XElement.Parse(data);
}
catch (Exception) {
return null;
}
}
}
}

View File

@@ -1,5 +1,8 @@
using Orchard.AuditTrail.Services.Models;
using System;
using System.Xml.Linq;
using Orchard.AuditTrail.Services.Models;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.MetaData.Services;
namespace Orchard.AuditTrail.Helpers {
public static class SettingsDictionaryExtensions {
@@ -17,6 +20,17 @@ namespace Orchard.AuditTrail.Helpers {
return dictionary;
}
public static bool IsEqualTo(this SettingsDictionary a, SettingsDictionary b, ISettingsFormatter settingsFormatter) {
var xml1 = ToXml(a, settingsFormatter);
var xml2 = ToXml(b, settingsFormatter);
return String.Equals(xml1, xml2, StringComparison.OrdinalIgnoreCase);
}
public static string ToXml(this SettingsDictionary settings, ISettingsFormatter settingsFormatter) {
return settingsFormatter.Map(settings).ToString(SaveOptions.DisableFormatting);
}
private static void BuildDiff(DiffDictionary<string, string> dictionary, SettingsDictionary settingsA, SettingsDictionary settingsB) {
foreach (var settingA in settingsA) {

View File

@@ -142,6 +142,10 @@
<Content Include="Views\AuditTrailEvent-Role-UserRemoved.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentPart-DescriptionChanged.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentPart-FieldSettingsUpdated.SummaryAdmin.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentType-Imported.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentPart-Imported.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentPart-Imported.SummaryAdmin.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentType-Imported.SummaryAdmin.cshtml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
@@ -193,6 +197,8 @@
<Compile Include="Models\AuditTrailTrimmingSettingsPart.cs" />
<Compile Include="Providers\AuditTrail\AuditTrailTrimmingSettingsEventProvider.cs" />
<Compile Include="Providers\AuditTrail\AuditTrailSettingsEventProvider.cs" />
<Compile Include="Providers\ContentDefinition\Shapes\ContentPartImportedEventShape.cs" />
<Compile Include="Providers\ContentDefinition\Shapes\ContentTypeImportedEventShape.cs" />
<Compile Include="Services\Models\AuditTrailSettingsContext.cs" />
<Compile Include="Services\CommonAuditTrailEventHandler.cs" />
<Compile Include="Services\AuditTrailEventHandlerBase.cs" />
@@ -200,11 +206,11 @@
<Compile Include="Services\Models\DisplayFilterContext.cs" />
<Compile Include="Services\Models\QueryFilterContext.cs" />
<Compile Include="Providers\Content\ContentAuditTrailEventShapes.cs" />
<Compile Include="Providers\Content\DiffGramAnalyzer.cs" />
<Compile Include="Providers\Content\DiffNode.cs" />
<Compile Include="Providers\Content\DiffType.cs" />
<Compile Include="Services\DiffGramAnalyzer.cs" />
<Compile Include="Services\Models\DiffNode.cs" />
<Compile Include="Services\Models\DiffType.cs" />
<Compile Include="Services\Models\Filters.cs" />
<Compile Include="Providers\Content\IDiffGramAnalyzer.cs" />
<Compile Include="Services\IDiffGramAnalyzer.cs" />
<Compile Include="Services\AuditTrailTrimmingBackgroundTask.cs" />
<Compile Include="Providers\AuditTrail\AuditTrailFilterShapes.cs" />
<Compile Include="Shapes\AuditTrailEventShapeAlteration.cs" />

View File

@@ -17,6 +17,8 @@ namespace Orchard.AuditTrail.Providers.Content {
public const string Published = "Published";
public const string Unpublished = "Unpublished";
public const string Removed = "Removed";
public const string Imported = "Imported";
public const string Exported = "Exported";
public static Filters CreateFilters(int contentId, IUpdateModel updateModel) {
return new Filters(updateModel) {
@@ -30,7 +32,9 @@ namespace Orchard.AuditTrail.Providers.Content {
.Event(this, Saved, T("Saved"), T("A content item was saved."), enableByDefault: true)
.Event(this, Published, T("Published"), T("A content item was published."), enableByDefault: true)
.Event(this, Unpublished, T("Unpublished"), T("A content item was unpublished."), enableByDefault: true)
.Event(this, Removed, T("Removed"), T("A content item was deleted."), enableByDefault: true);
.Event(this, Removed, T("Removed"), T("A content item was deleted."), enableByDefault: true)
.Event(this, Imported, T("Imported"), T("A content item was imported."), enableByDefault: true)
.Event(this, Exported, T("Exported"), T("A content item was exported."), enableByDefault: false);
context.QueryFilter(QueryFilter);
context.DisplayFilter(DisplayFilter);

View File

@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.AuditTrail.Helpers;
using Orchard.AuditTrail.Models;
using Orchard.AuditTrail.Services;
using Orchard.ContentManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment;
@@ -28,8 +27,8 @@ namespace Orchard.AuditTrail.Providers.Content {
var eventData = (IDictionary<string, object>)context.Shape.EventData;
var contentItemId = eventData.Get<int>("ContentId");
var previousContentItemVersionId = eventData.Get<int>("PreviousVersionId");
var previousVersionXml = GetXml(eventData, "PreviousVersionXml");
var diffGram = GetXml(eventData, "DiffGram");
var previousVersionXml = eventData.GetXml("PreviousVersionXml");
var diffGram = eventData.GetXml("DiffGram");
var contentItem = _contentManager.Value.Get(contentItemId, VersionOptions.AllVersions);
var previousVersion = previousContentItemVersionId > 0 ? _contentManager.Value.Get(contentItemId, VersionOptions.VersionRecord(previousContentItemVersionId)) : default(ContentItem);
@@ -43,19 +42,5 @@ namespace Orchard.AuditTrail.Providers.Content {
context.Shape.PreviousVersion = previousVersion;
});
}
private static XElement GetXml(IDictionary<string, object> eventData, string key) {
var data = eventData.Get<string>(key);
if (String.IsNullOrWhiteSpace(data))
return null;
try {
return XElement.Parse(data);
}
catch (Exception) {
return null;
}
}
}
}

View File

@@ -15,6 +15,7 @@ namespace Orchard.AuditTrail.Providers.Content {
private XElement _previousVersionXml;
private readonly IDiffGramAnalyzer _analyzer;
private bool _contentItemCreated = false;
private ContentItem _ignoreExportHandlerFor;
public GlobalContentHandler(IAuditTrailManager auditTrailManager, IWorkContextAccessor wca, IContentManager contentManager, IDiffGramAnalyzer analyzer) {
_auditTrailManager = auditTrailManager;
@@ -44,7 +45,10 @@ namespace Orchard.AuditTrail.Providers.Content {
RecordAuditTrailEvent(ContentAuditTrailEventProvider.Created, context.ContentItem);
}
else {
_ignoreExportHandlerFor = contentItem;
var newVersionXml = _contentManager.Export(contentItem);
_ignoreExportHandlerFor = null;
var diffGram = _analyzer.GenerateDiffGram(_previousVersionXml, newVersionXml);
RecordAuditTrailEvent(ContentAuditTrailEventProvider.Saved, context.ContentItem, diffGram: diffGram, previousVersionXml: _previousVersionXml);
}
@@ -63,6 +67,17 @@ namespace Orchard.AuditTrail.Providers.Content {
RecordAuditTrailEvent(ContentAuditTrailEventProvider.Removed, context.ContentItem);
}
protected override void Imported(ImportContentContext context) {
RecordAuditTrailEvent(ContentAuditTrailEventProvider.Imported, context.ContentItem);
}
protected override void Exported(ExportContentContext context) {
if (context.ContentItem == _ignoreExportHandlerFor)
return;
RecordAuditTrailEvent(ContentAuditTrailEventProvider.Exported, context.ContentItem);
}
private void RecordAuditTrailEvent(string eventName, IContent content, ContentItemVersionRecord previousContentItemVersion = null, XElement diffGram = null, XElement previousVersionXml = null) {
var blackList = new[] {"Site"};

View File

@@ -1,18 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.AuditTrail.Services;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentTypes.Events;
using Orchard.Environment.Extensions;
using Orchard.ImportExport.Services;
namespace Orchard.AuditTrail.Providers.ContentDefinition {
[OrchardFeature("Orchard.AuditTrail.ContentDefinition")]
public class ContentDefinitionEventHandler : IContentDefinitionEventHandler {
private readonly IAuditTrailManager _auditTrailManager;
private readonly IWorkContextAccessor _wca;
private readonly IImportExportService _importExportService;
private readonly IContentDefinitionWriter _contentDefinitionWriter;
private XElement _previousContentTypeXml;
private XElement _previousContentPartXml;
private readonly IDiffGramAnalyzer _analyzer;
public ContentDefinitionEventHandler(
IAuditTrailManager auditTrailManager,
IWorkContextAccessor wca,
IContentDefinitionWriter contentDefinitionWriter,
IDiffGramAnalyzer analyzer) {
public ContentDefinitionEventHandler(IAuditTrailManager auditTrailManager, IWorkContextAccessor wca) {
_auditTrailManager = auditTrailManager;
_wca = wca;
_contentDefinitionWriter = contentDefinitionWriter;
_analyzer = analyzer;
}
public void ContentTypeCreated(ContentTypeCreatedContext context) {
@@ -23,6 +39,15 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
RecordContentTypeAuditTrailEvent(ContentTypeAuditTrailEventProvider.Removed, context.ContentTypeDefinition);
}
public void ContentTypeImporting(ContentTypeImportingContext context) {
_previousContentTypeXml = context.ContentTypeDefinition != null ? _contentDefinitionWriter.Export(context.ContentTypeDefinition) : default(XElement);
}
public void ContentTypeImported(ContentTypeImportedContext context) {
var newContentTypeXml = _contentDefinitionWriter.Export(context.ContentTypeDefinition);
RecordContentTypeAuditTrailEvent(ContentTypeAuditTrailEventProvider.Imported, context.ContentTypeDefinition, _previousContentTypeXml, newContentTypeXml);
}
public void ContentPartCreated(ContentPartCreatedContext context) {
RecordContentPartAuditTrailEvent(ContentPartAuditTrailEventProvider.Created, context.ContentPartDefinition);
}
@@ -39,6 +64,15 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
RecordContentTypePartAuditTrailEvent(ContentTypeAuditTrailEventProvider.PartRemoved, context.ContentTypeName, context.ContentPartName);
}
public void ContentPartImporting(ContentPartImportingContext context) {
_previousContentPartXml = context.ContentPartDefinition != null ? _contentDefinitionWriter.Export(context.ContentPartDefinition) : default(XElement);
}
public void ContentPartImported(ContentPartImportedContext context) {
var newContentPartXml = _contentDefinitionWriter.Export(context.ContentPartDefinition);
RecordContentPartAuditTrailEvent(ContentPartAuditTrailEventProvider.Imported, context.ContentPartDefinition, _previousContentPartXml, newContentPartXml);
}
public void ContentFieldAttached(ContentFieldAttachedContext context) {
var eventData = new Dictionary<string, object> {
{"ContentPartName", context.ContentPartName},
@@ -57,19 +91,65 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
_auditTrailManager.CreateRecord<ContentPartAuditTrailEventProvider>(ContentPartAuditTrailEventProvider.FieldRemoved, _wca.GetContext().CurrentUser, properties: null, eventData: eventData, eventFilterKey: "contentpart", eventFilterData: context.ContentPartName);
}
private void RecordContentTypeAuditTrailEvent(string eventName, ContentTypeDefinition contentTypeDefinition) {
private void RecordContentTypeAuditTrailEvent(string eventName, ContentTypeDefinition contentTypeDefinition, XElement previousContentTypeXml = null, XElement newContentTypeXml = null) {
var record = true;
var eventData = new Dictionary<string, object> {
{"ContentTypeName", contentTypeDefinition.Name},
{"ContentTypeDisplayName", contentTypeDefinition.DisplayName},
};
_auditTrailManager.CreateRecord<ContentTypeAuditTrailEventProvider>(eventName, _wca.GetContext().CurrentUser, properties: null, eventData: eventData, eventFilterKey: "contenttype", eventFilterData: contentTypeDefinition.Name);
if (previousContentTypeXml != null || newContentTypeXml != null) {
var previousXml = previousContentTypeXml != null ? previousContentTypeXml.ToString(SaveOptions.DisableFormatting) : default(string);
var newXml = newContentTypeXml != null ? newContentTypeXml.ToString(SaveOptions.DisableFormatting) : default(string);
if (previousXml != null) {
if (previousXml != newXml) {
var diffGram = _analyzer.GenerateDiffGram(previousContentTypeXml, newContentTypeXml);
eventData["PreviousDefinition"] = previousXml;
eventData["NewDefinition"] = newXml;
eventData["DiffGram"] = diffGram.ToString(SaveOptions.DisableFormatting);
}
else {
record = false;
}
}
else {
eventData["NewDefinition"] = newXml;
}
}
if (record)
_auditTrailManager.CreateRecord<ContentTypeAuditTrailEventProvider>(eventName, _wca.GetContext().CurrentUser, properties: null, eventData: eventData, eventFilterKey: "contenttype", eventFilterData: contentTypeDefinition.Name);
}
private void RecordContentPartAuditTrailEvent(string eventName, ContentPartDefinition contentPartDefinition) {
private void RecordContentPartAuditTrailEvent(string eventName, ContentPartDefinition contentPartDefinition, XElement previousContentPartXml = null, XElement newContentPartXml = null) {
var record = true;
var eventData = new Dictionary<string, object> {
{"ContentPartName", contentPartDefinition.Name}
};
_auditTrailManager.CreateRecord<ContentPartAuditTrailEventProvider>(eventName, _wca.GetContext().CurrentUser, properties: null, eventData: eventData, eventFilterKey: "contentpart", eventFilterData: contentPartDefinition.Name);
if (previousContentPartXml != null || newContentPartXml != null) {
var previousXml = previousContentPartXml != null ?previousContentPartXml.ToString(SaveOptions.DisableFormatting) : default(string);
var newXml = newContentPartXml != null ? newContentPartXml.ToString(SaveOptions.DisableFormatting) : default(string);
if (previousXml != null) {
if (previousXml != newXml) {
var diffGram = _analyzer.GenerateDiffGram(previousContentPartXml, newContentPartXml);
eventData["PreviousDefinition"] = previousXml;
eventData["NewDefinition"] = newXml;
eventData["DiffGram"] = diffGram.ToString(SaveOptions.DisableFormatting);
}
else {
record = false;
}
}
else {
eventData["NewDefinition"] = newXml;
}
}
if (record)
_auditTrailManager.CreateRecord<ContentPartAuditTrailEventProvider>(eventName, _wca.GetContext().CurrentUser, properties: null, eventData: eventData, eventFilterKey: "contentpart", eventFilterData: contentPartDefinition.Name);
}
private void RecordContentTypePartAuditTrailEvent(string eventName, string contentTypeName, string contentPartName) {

View File

@@ -7,6 +7,7 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
public class ContentPartAuditTrailEventProvider : AuditTrailEventProviderBase {
public const string Created = "Created";
public const string Removed = "Removed";
public const string Imported = "Imported";
public const string DescriptionChanged = "DescriptionChanged";
public const string FieldAdded = "FieldAdded";
public const string FieldRemoved = "FieldRemoved";
@@ -17,6 +18,7 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
context.For("ContentPart", T("Content Parts"))
.Event(this, Created, T("Created"), T("A content part was created."), enableByDefault: true)
.Event(this, Removed, T("Removed"), T("A content part was removed."), enableByDefault: true)
.Event(this, Imported, T("Imported"), T("A content part was imported."), enableByDefault: true)
.Event(this, DescriptionChanged, T("Description changed"), T("A content part description was changed."), enableByDefault: true)
.Event(this, FieldAdded, T("Field added"), T("A field was added to a content part."), enableByDefault: true)
.Event(this, FieldRemoved, T("Field removed"), T("A field was removed from a content part."), enableByDefault: true)

View File

@@ -17,6 +17,7 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
public const string Created = "Created";
public const string Removed = "Removed";
public const string Imported = "Imported";
public const string PartAdded = "PartAdded";
public const string PartRemoved = "PartRemoved";
public const string TypeDisplayNameUpdated = "TypeDisplayNameUpdated";
@@ -28,6 +29,7 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
context.For("ContentType", T("Content Type"))
.Event(this, Created, T("Created"), T("A content type was created."), enableByDefault: true)
.Event(this, Removed, T("Removed"), T("A content type was removed."), enableByDefault: true)
.Event(this, Imported, T("Imported"), T("A content type was imported."), enableByDefault: true)
.Event(this, PartAdded, T("Part added"), T("A content part was added to a content type."), enableByDefault: true)
.Event(this, PartRemoved, T("Part removed"), T("A content part was removed from a content type."), enableByDefault: true)
.Event(this, TypeDisplayNameUpdated, T("Type display name updated"), T("The display name of a content type was updated."), enableByDefault: true)

View File

@@ -9,7 +9,6 @@ using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.MetaData.Services;
using Orchard.ContentTypes.Services;
using Orchard.ContentTypes.ViewModels;
using Orchard.Environment.Extensions;
namespace Orchard.AuditTrail.Providers.ContentDefinition {
@@ -21,7 +20,6 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
private readonly IContentDefinitionService _contentDefinitionService;
private readonly ISettingsFormatter _settingsFormatter;
private string _oldContentTypeDisplayName;
private EditTypeViewModel _currentContentType;
private SettingsDictionary _oldContentTypeSettings;
private SettingsDictionary _oldContentTypePartSettings;
private SettingsDictionary _oldContentPartFieldSettings;
@@ -41,7 +39,6 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
public override void TypeEditorUpdating(ContentTypeDefinitionBuilder definition) {
var contentType = _contentDefinitionService.GetType(definition.Name);
_currentContentType = contentType;
_oldContentTypeDisplayName = contentType.DisplayName;
_oldContentTypeSettings = new SettingsDictionary(contentType.Settings);
}
@@ -157,14 +154,11 @@ namespace Orchard.AuditTrail.Providers.ContentDefinition {
}
private string ToXml(SettingsDictionary settings) {
return _settingsFormatter.Map(settings).ToString(SaveOptions.DisableFormatting);
return settings.ToXml(_settingsFormatter);
}
private bool AreEqual(SettingsDictionary a, SettingsDictionary b) {
var xml1 = ToXml(a);
var xml2 = ToXml(b);
return String.Equals(xml1, xml2, StringComparison.OrdinalIgnoreCase);
return a.IsEqualTo(b, _settingsFormatter);
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.AuditTrail.Helpers;
using Orchard.AuditTrail.Services;
using Orchard.AuditTrail.Shapes;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
namespace Orchard.AuditTrail.Providers.ContentDefinition.Shapes {
[OrchardFeature("Orchard.AuditTrail.ContentDefinition")]
public class ContentPartImportedEventShape : AuditTrailEventShapeAlteration<ContentPartAuditTrailEventProvider> {
private readonly IDiffGramAnalyzer _analyzer;
public ContentPartImportedEventShape(IDiffGramAnalyzer analyzer) {
_analyzer = analyzer;
}
protected override string EventName {
get { return ContentPartAuditTrailEventProvider.Imported; }
}
protected override void OnAlterShape(ShapeDisplayingContext context) {
var eventData = (IDictionary<string, object>)context.Shape.EventData;
var previousDefinitionXml = eventData.GetXml("PreviousDefinition");
var newDefinitionXml = eventData.GetXml("NewDefinition");
var diffGram = eventData.GetXml("DiffGram");
context.Shape.NewDefinitionXml = newDefinitionXml;
if (diffGram != null) {
var diffNodes = _analyzer.Analyze(previousDefinitionXml, diffGram).ToArray();
context.Shape.DiffNodes = diffNodes;
}
}
}
}

View File

@@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Linq;
using Orchard.AuditTrail.Helpers;
using Orchard.AuditTrail.Services;
using Orchard.AuditTrail.Shapes;
using Orchard.DisplayManagement.Implementation;
using Orchard.Environment.Extensions;
namespace Orchard.AuditTrail.Providers.ContentDefinition.Shapes {
[OrchardFeature("Orchard.AuditTrail.ContentDefinition")]
public class ContentTypeImportedEventShape : AuditTrailEventShapeAlteration<ContentTypeAuditTrailEventProvider> {
private readonly IDiffGramAnalyzer _analyzer;
public ContentTypeImportedEventShape(IDiffGramAnalyzer analyzer) {
_analyzer = analyzer;
}
protected override string EventName {
get { return ContentTypeAuditTrailEventProvider.Imported; }
}
protected override void OnAlterShape(ShapeDisplayingContext context) {
var eventData = (IDictionary<string, object>)context.Shape.EventData;
var previousDefinitionXml = eventData.GetXml("PreviousDefinition");
var newDefinitionXml = eventData.GetXml("NewDefinition");
var diffGram = eventData.GetXml("DiffGram");
context.Shape.NewDefinitionXml = newDefinitionXml;
if (diffGram != null) {
var diffNodes = _analyzer.Analyze(previousDefinitionXml, diffGram).ToArray();
context.Shape.DiffNodes = diffNodes;
}
}
}
}

View File

@@ -4,8 +4,9 @@ using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.XmlDiffPatch;
using Orchard.AuditTrail.Services.Models;
namespace Orchard.AuditTrail.Providers.Content {
namespace Orchard.AuditTrail.Services {
public class DiffGramAnalyzer : IDiffGramAnalyzer {
public XElement GenerateDiffGram(XElement element1, XElement element2) {
using (var node1Reader = element1.CreateReader())
@@ -95,7 +96,8 @@ namespace Orchard.AuditTrail.Providers.Content {
}
break;
case XmlNodeType.EndElement:
stack.Pop();
if(stack.Any())
stack.Pop();
break;
}
if (readNext)

View File

@@ -1,7 +1,8 @@
using System.Collections.Generic;
using System.Xml.Linq;
using Orchard.AuditTrail.Services.Models;
namespace Orchard.AuditTrail.Providers.Content {
namespace Orchard.AuditTrail.Services {
public interface IDiffGramAnalyzer : IDependency {
/// <summary>
/// Compares the specified XML elements and returns a DiffGram XML element.

View File

@@ -1,4 +1,4 @@
namespace Orchard.AuditTrail.Providers.Content {
namespace Orchard.AuditTrail.Services.Models {
public class DiffNode {
public DiffType Type { get; set; }
public string Context { get; set; }

View File

@@ -1,4 +1,4 @@
namespace Orchard.AuditTrail.Providers.Content {
namespace Orchard.AuditTrail.Services.Models {
public enum DiffType {
Change,
Addition

View File

@@ -1,4 +1,14 @@
section.audittrail-contenttype-eventsummary table.items,
section.audittrail-contenttype-eventsummary,
section.audittrail-contentpart-eventsummary {
margin-bottom: 1em;
}
section.audittrail-contenttype-eventsummary p.code,
section.audittrail-contentpart-eventsummary p.code {
font-family: Consolas;
}
section.audittrail-contenttype-eventsummary table.items,
section.audittrail-contentpart-eventsummary table.items {
width: auto;
min-width: 600px;

View File

@@ -1,6 +1,7 @@
@using Orchard.AuditTrail.Helpers
@using Orchard.AuditTrail.Models
@using Orchard.AuditTrail.Providers.Content
@using Orchard.AuditTrail.Services.Models
@using Orchard.ContentManagement
@{
Style.Include("audittrail-content-event.css");

View File

@@ -0,0 +1,10 @@
@using Orchard.AuditTrail.Helpers
@using Orchard.AuditTrail.Services.Models
@{
var eventData = (IDictionary<string, object>) Model.EventData;
var contentPartName = eventData.Get<string>("ContentPartName");
var diffNodes = (IList<DiffNode>)Model.DiffNodes;
}
<section class="audittrail-contentpart-eventsummary">
@T(diffNodes != null ? "The content part {0} was altered during an import." : "The content part {0} was added during an import.", Html.ContentPartEditLink(contentPartName))
</section>

View File

@@ -0,0 +1,53 @@
@using System.Xml.Linq
@using Orchard.AuditTrail.Helpers
@using Orchard.AuditTrail.Services.Models
@{
Style.Include("audittrail-contentdefinition-event.css");
}
@{
var eventData = (IDictionary<string, object>) Model.EventData;
var contentPartName = eventData.Get<string>("ContentPartName");
var diffNodes = (IList<DiffNode>)Model.DiffNodes;
var newDefinitionXml = (XElement)Model.NewDefinitionXml;
}
<section class="audittrail-contentpart-eventsummary">
@T(diffNodes != null ? "The content part {0} was altered during an import." : "The content part {0} was added during an import.", Html.ContentPartEditLink(contentPartName))
</section>
@if (diffNodes != null) {
<section class="audittrail-contentpart-eventsummary">
<table class="items">
<thead>
<tr>
<th>@T("Action")</th>
<th>@T("Context")</th>
<th>@T("Before")</th>
<th>@T("After")</th>
</tr>
</thead>
<tbody>
@if (!diffNodes.Any()) {
<tr>
<td colspan="4">@T("")</td>
</tr>
}
else {
foreach (var node in diffNodes) {
<tr>
<td>@T(node.Type.ToString())</td>
<td>@node.Context</td>
<td>@node.Previous.OrIfEmpty(T("[Empty]"))</td>
<td>@node.Current.OrIfEmpty(T("[Empty]"))</td>
</tr>
}
}
</tbody>
</table>
</section>
}
else {
<p class="code">
@Html.Raw(Html.Encode(newDefinitionXml.ToString(SaveOptions.None)).Replace("\r\n", "<br/>"))
</p>
}

View File

@@ -0,0 +1,10 @@
@using Orchard.AuditTrail.Helpers
@using Orchard.AuditTrail.Services.Models
@{
var eventData = (IDictionary<string, object>) Model.EventData;
var contentTypeName = eventData.Get<string>("ContentTypeName");
var diffNodes = (IList<DiffNode>)Model.DiffNodes;
}
<section class="audittrail-contenttype-eventsummary">
@T(diffNodes != null ? "The content type {0} was altered during an import." : "The content type {0} was added during an import.", Html.ContentTypeEditLink(contentTypeName))
</section>

View File

@@ -0,0 +1,53 @@
@using System.Xml.Linq
@using Orchard.AuditTrail.Helpers
@using Orchard.AuditTrail.Services.Models
@{
Style.Include("audittrail-contentdefinition-event.css");
}
@{
var eventData = (IDictionary<string, object>) Model.EventData;
var contentTypeName = eventData.Get<string>("ContentTypeName");
var diffNodes = (IList<DiffNode>)Model.DiffNodes;
var newDefinitionXml = (XElement) Model.NewDefinitionXml;
}
<section class="audittrail-contenttype-eventsummary">
@T(diffNodes != null ? "The content type {0} was altered during an import." : "The content type {0} was added during an import.", Html.ContentTypeEditLink(contentTypeName))
</section>
@if (diffNodes != null) {
<section class="audittrail-contenttype-eventsummary">
<table class="items">
<thead>
<tr>
<th>@T("Action")</th>
<th>@T("Context")</th>
<th>@T("Before")</th>
<th>@T("After")</th>
</tr>
</thead>
<tbody>
@if (!diffNodes.Any()) {
<tr>
<td colspan="4">@T("")</td>
</tr>
}
else {
foreach (var node in diffNodes) {
<tr>
<td>@T(node.Type.ToString())</td>
<td>@node.Context</td>
<td>@node.Previous.OrIfEmpty(T("[Empty]"))</td>
<td>@node.Current.OrIfEmpty(T("[Empty]"))</td>
</tr>
}
}
</tbody>
</table>
</section>
}
else {
<p class="code">
@Html.Raw(Html.Encode(newDefinitionXml.ToString(SaveOptions.None)).Replace("\r\n", "<br/>"))
</p>
}

View File

@@ -1,41 +1,42 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<remove name="host" />
<remove name="pages" />
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<remove name="host" />
<remove name="pages" />
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="System.Linq"/>
<add namespace="System.Collections.Generic"/>
<add namespace="Orchard.Mvc.Html"/>
</namespaces>
</pages>
</system.web.webPages.razor>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<pages pageBaseType="Orchard.Mvc.ViewEngines.Razor.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="System.Linq"/>
<add namespace="System.Collections.Generic"/>
<add namespace="Orchard.Mvc.Html"/>
</namespaces>
</pages>
</system.web.webPages.razor>
<system.web>
<compilation targetFramework="4.5">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</assemblies>
</compilation>
</system.web>
<system.web>
<compilation targetFramework="4.5">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Mvc, Version=5.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</assemblies>
</compilation>
</system.web>
</configuration>

View File

@@ -0,0 +1,3 @@
namespace Orchard.ContentTypes.Events {
public class ContentPartImportedContext : ContentPartContext { }
}

View File

@@ -0,0 +1,5 @@
namespace Orchard.ContentTypes.Events {
public class ContentPartImportingContext : ContentPartContext {
public string ContentPartName { get; set; }
}
}

View File

@@ -0,0 +1,3 @@
namespace Orchard.ContentTypes.Events {
public class ContentTypeImportedContext : ContentTypeContext { }
}

View File

@@ -0,0 +1,5 @@
namespace Orchard.ContentTypes.Events {
public class ContentTypeImportingContext : ContentTypeContext {
public string ContentTypeName { get; set; }
}
}

View File

@@ -4,10 +4,14 @@ namespace Orchard.ContentTypes.Events {
public interface IContentDefinitionEventHandler : IEventHandler {
void ContentTypeCreated(ContentTypeCreatedContext context);
void ContentTypeRemoved(ContentTypeRemovedContext context);
void ContentTypeImporting(ContentTypeImportingContext context);
void ContentTypeImported(ContentTypeImportedContext context);
void ContentPartCreated(ContentPartCreatedContext context);
void ContentPartRemoved(ContentPartRemovedContext context);
void ContentPartAttached(ContentPartAttachedContext context);
void ContentPartDetached(ContentPartDetachedContext context);
void ContentPartImporting(ContentPartImportingContext context);
void ContentPartImported(ContentPartImportedContext context);
void ContentFieldAttached(ContentFieldAttachedContext context);
void ContentFieldDetached(ContentFieldDetachedContext context);
}

View File

@@ -72,9 +72,13 @@
<Compile Include="Events\ContentPartCreatedContext.cs" />
<Compile Include="Events\ContentPartDetachedContext.cs" />
<Compile Include="Events\ContentPartFieldContext.cs" />
<Compile Include="Events\ContentPartImportedContext.cs" />
<Compile Include="Events\ContentPartImportingContext.cs" />
<Compile Include="Events\ContentPartRemovedContext.cs" />
<Compile Include="Events\ContentTypeContext.cs" />
<Compile Include="Events\ContentTypeCreatedContext.cs" />
<Compile Include="Events\ContentTypeImportedContext.cs" />
<Compile Include="Events\ContentTypeImportingContext.cs" />
<Compile Include="Events\ContentTypePartContext.cs" />
<Compile Include="Events\ContentTypeRemovedContext.cs" />
<Compile Include="Events\IContentDefinitionEventHandler.cs" />

View File

@@ -11,7 +11,7 @@ namespace Orchard.Lists.Handlers {
if (container == null)
return;
// containers link to their contents in admin screens
// Containers link to their contents in admin screens.
context.Metadata.AdminRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Lists"},
{"Controller", "Admin"},

View File

@@ -94,6 +94,10 @@
<Project>{2D1D92BB-4555-4CBE-8D0E-63563D6CE4C6}</Project>
<Name>Orchard.Framework</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.ContentTypes\Orchard.ContentTypes.csproj">
<Project>{0e7646e8-fe8f-43c1-8799-d97860925ec4}</Project>
<Name>Orchard.ContentTypes</Name>
</ProjectReference>
<ProjectReference Include="..\Orchard.Packaging\Orchard.Packaging.csproj">
<Project>{DFD137A2-DDB5-4D22-BE0D-FA9AD4C8B059}</Project>
<Name>Orchard.Packaging</Name>

View File

@@ -1,6 +1,7 @@
using System;
using System.Xml;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentTypes.Events;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Recipes.Models;
@@ -10,10 +11,16 @@ namespace Orchard.Recipes.RecipeHandlers {
public class MetadataRecipeHandler : IRecipeHandler {
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IContentDefinitionReader _contentDefinitionReader;
private readonly IContentDefinitionEventHandler _contentDefinitonEventHandlers;
public MetadataRecipeHandler(
IContentDefinitionManager contentDefinitionManager,
IContentDefinitionReader contentDefinitionReader,
IContentDefinitionEventHandler contentDefinitonEventHandlers) {
public MetadataRecipeHandler(IContentDefinitionManager contentDefinitionManager, IContentDefinitionReader contentDefinitionReader) {
_contentDefinitionManager = contentDefinitionManager;
_contentDefinitionReader = contentDefinitionReader;
_contentDefinitonEventHandlers = contentDefinitonEventHandlers;
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
}
@@ -45,7 +52,10 @@ namespace Orchard.Recipes.RecipeHandlers {
foreach (var element in metadataElement.Elements()) {
var typeElement = element;
var typeName = XmlConvert.DecodeName(element.Name.LocalName);
_contentDefinitonEventHandlers.ContentTypeImporting(new ContentTypeImportingContext { ContentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(typeName), ContentTypeName = typeName });
_contentDefinitionManager.AlterTypeDefinition(typeName, alteration => _contentDefinitionReader.Merge(typeElement, alteration));
_contentDefinitonEventHandlers.ContentTypeImported(new ContentTypeImportedContext { ContentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(typeName) });
}
break;
case "Parts":
@@ -53,7 +63,10 @@ namespace Orchard.Recipes.RecipeHandlers {
foreach (var element in metadataElement.Elements()) {
var partElement = element;
var partName = XmlConvert.DecodeName(element.Name.LocalName);
_contentDefinitonEventHandlers.ContentPartImporting(new ContentPartImportingContext { ContentPartDefinition = _contentDefinitionManager.GetPartDefinition(partName), ContentPartName = partName });
_contentDefinitionManager.AlterPartDefinition(partName, alteration => _contentDefinitionReader.Merge(partElement, alteration));
_contentDefinitonEventHandlers.ContentPartImported(new ContentPartImportedContext { ContentPartDefinition = _contentDefinitionManager.GetPartDefinition(partName)});
}
break;
default: