mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Implementing "Imported" audit trail event for content items and types.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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) {
|
||||
|
@@ -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" />
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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"};
|
||||
|
||||
|
@@ -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,18 +91,64 @@ 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},
|
||||
};
|
||||
|
||||
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}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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,6 +96,7 @@ namespace Orchard.AuditTrail.Providers.Content {
|
||||
}
|
||||
break;
|
||||
case XmlNodeType.EndElement:
|
||||
if(stack.Any())
|
||||
stack.Pop();
|
||||
break;
|
||||
}
|
@@ -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.
|
@@ -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; }
|
@@ -1,4 +1,4 @@
|
||||
namespace Orchard.AuditTrail.Providers.Content {
|
||||
namespace Orchard.AuditTrail.Services.Models {
|
||||
public enum DiffType {
|
||||
Change,
|
||||
Addition
|
@@ -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;
|
||||
|
@@ -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");
|
||||
|
@@ -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>
|
@@ -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>
|
||||
}
|
@@ -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>
|
@@ -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>
|
||||
}
|
@@ -34,6 +34,7 @@
|
||||
<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>
|
||||
|
@@ -0,0 +1,3 @@
|
||||
namespace Orchard.ContentTypes.Events {
|
||||
public class ContentPartImportedContext : ContentPartContext { }
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.ContentTypes.Events {
|
||||
public class ContentPartImportingContext : ContentPartContext {
|
||||
public string ContentPartName { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
namespace Orchard.ContentTypes.Events {
|
||||
public class ContentTypeImportedContext : ContentTypeContext { }
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.ContentTypes.Events {
|
||||
public class ContentTypeImportingContext : ContentTypeContext {
|
||||
public string ContentTypeName { get; set; }
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
@@ -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" />
|
||||
|
@@ -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"},
|
||||
|
@@ -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>
|
||||
|
@@ -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:
|
||||
|
Reference in New Issue
Block a user