mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
#21091: Fixing audit trail bug.
This fixes an issue causing a YSOD on the AuditTrail screen by recording all relevant data for the AuditTrailSettings event provider, such that the event providers themselves can be disabled without breaking the recorded events (which relied on the Event Descriptor to be available when rendering the event, which is unavailable if its providing feature is disabled). Work Item: 21091
This commit is contained in:
@@ -10,9 +10,9 @@ using Orchard.Localization;
|
||||
namespace Orchard.AuditTrail.Handlers {
|
||||
public class AuditTrailSettingsPartHandler : ContentHandler {
|
||||
private readonly ISignals _signals;
|
||||
private string _oldEventSettings;
|
||||
private readonly IAuditTrailManager _auditTrailManager;
|
||||
private readonly IWorkContextAccessor _wca;
|
||||
private string _oldEventSettings;
|
||||
|
||||
public AuditTrailSettingsPartHandler(ISignals signals, IAuditTrailManager auditTrailManager, IWorkContextAccessor wca) {
|
||||
_signals = signals;
|
||||
@@ -54,8 +54,8 @@ namespace Orchard.AuditTrail.Handlers {
|
||||
_auditTrailManager.CreateRecord<AuditTrailSettingsEventProvider>(
|
||||
eventName: AuditTrailSettingsEventProvider.EventsChanged,
|
||||
eventData: new Dictionary<string, object> {
|
||||
{"OldSettings", _oldEventSettings},
|
||||
{"NewSettings", newEventSettings}
|
||||
{"OldSettings", _auditTrailManager.ToEventData(_oldEventSettings)},
|
||||
{"NewSettings", _auditTrailManager.ToEventData(newEventSettings)}
|
||||
},
|
||||
user: _wca.GetContext().CurrentUser);
|
||||
}
|
||||
|
@@ -189,6 +189,8 @@
|
||||
<ItemGroup>
|
||||
<Compile Include="Menus\AuditTrailAdminMenu.cs" />
|
||||
<Compile Include="Menus\RecycleBinAdminMenu.cs" />
|
||||
<Compile Include="Providers\AuditTrail\AuditTrailEventSettingEventData.cs" />
|
||||
<Compile Include="Providers\AuditTrail\AuditTrailManagerExtensions.cs" />
|
||||
<Compile Include="ViewModels\RecycleBinCommand.cs" />
|
||||
<Compile Include="Controllers\RecycleBinController.cs" />
|
||||
<Compile Include="Controllers\ContentController.cs" />
|
||||
|
@@ -0,0 +1,9 @@
|
||||
namespace Orchard.AuditTrail.Providers.AuditTrail {
|
||||
public class AuditTrailEventSettingEventData
|
||||
{
|
||||
public string EventName { get; set; }
|
||||
public string EventDisplayName { get; set; }
|
||||
public string EventCategory { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Orchard.AuditTrail.Services;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.AuditTrail.Providers.AuditTrail {
|
||||
public static class AuditTrailManagerExtensions {
|
||||
public static string ToEventData(this IAuditTrailManager auditTrailManager, string settingsData) {
|
||||
var settings = auditTrailManager.DeserializeProviderConfiguration(settingsData);
|
||||
var query =
|
||||
from setting in settings
|
||||
let descriptor = auditTrailManager.DescribeEvent(setting.EventName)
|
||||
select new AuditTrailEventSettingEventData {
|
||||
EventName = setting.EventName,
|
||||
IsEnabled = setting.IsEnabled,
|
||||
EventCategory = descriptor.CategoryDescriptor.Name.TextHint,
|
||||
EventDisplayName = descriptor.Name.TextHint
|
||||
};
|
||||
|
||||
return SerializeEventData(query);
|
||||
}
|
||||
|
||||
public static string SerializeEventData(IEnumerable<AuditTrailEventSettingEventData> settings) {
|
||||
var doc = new XDocument(
|
||||
new XElement("Events",
|
||||
settings.Select(x =>
|
||||
new XElement("Event",
|
||||
new XAttribute("Name", x.EventName),
|
||||
new XAttribute("IsEnabled", x.IsEnabled),
|
||||
new XAttribute("DisplayName", x.EventDisplayName),
|
||||
new XAttribute("Category", x.EventCategory)))));
|
||||
|
||||
return doc.ToString(SaveOptions.DisableFormatting);
|
||||
}
|
||||
|
||||
public static IEnumerable<AuditTrailEventSettingEventData> DeserializeEventData(string data, ILogger logger) {
|
||||
if (String.IsNullOrWhiteSpace(data))
|
||||
return Enumerable.Empty<AuditTrailEventSettingEventData>();
|
||||
|
||||
try {
|
||||
var doc = XDocument.Parse(data);
|
||||
return doc.Element("Events").Elements("Event").Select(x => new AuditTrailEventSettingEventData {
|
||||
EventName = x.Attr<string>("Name"),
|
||||
IsEnabled = x.Attr<bool>("IsEnabled"),
|
||||
EventDisplayName = x.Attr<string>("DisplayName"),
|
||||
EventCategory = x.Attr<string>("Category")
|
||||
}).ToArray();
|
||||
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.Error(ex, "Error occurred during deserialization of audit trail settings.");
|
||||
}
|
||||
return Enumerable.Empty<AuditTrailEventSettingEventData>();
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.AuditTrail.Models;
|
||||
using Orchard.AuditTrail.Services;
|
||||
using Orchard.AuditTrail.Shapes;
|
||||
using Orchard.AuditTrail.ViewModels;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Environment;
|
||||
using Orchard.Logging;
|
||||
|
||||
namespace Orchard.AuditTrail.Providers.AuditTrail {
|
||||
public class AuditTrailSettingsEventShape : AuditTrailEventShapeAlteration<AuditTrailSettingsEventProvider> {
|
||||
@@ -13,16 +13,19 @@ namespace Orchard.AuditTrail.Providers.AuditTrail {
|
||||
|
||||
public AuditTrailSettingsEventShape(Work<IAuditTrailManager> auditTrailManager) {
|
||||
_auditTrailManager = auditTrailManager;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
protected override string EventName {
|
||||
get { return AuditTrailSettingsEventProvider.EventsChanged; }
|
||||
}
|
||||
|
||||
protected override void OnAlterShape(ShapeDisplayingContext context) {
|
||||
var eventData = (IDictionary<string, object>)context.Shape.EventData;
|
||||
var oldSettings = _auditTrailManager.Value.DeserializeProviderConfiguration((string)eventData["OldSettings"]);
|
||||
var newSettings = _auditTrailManager.Value.DeserializeProviderConfiguration((string)eventData["NewSettings"]);
|
||||
var oldSettings = AuditTrailManagerExtensions.DeserializeEventData((string)eventData["OldSettings"], Logger);
|
||||
var newSettings = AuditTrailManagerExtensions.DeserializeEventData((string)eventData["NewSettings"], Logger);
|
||||
var diff = GetDiffQuery(oldSettings, newSettings).ToArray();
|
||||
|
||||
context.Shape.OldSettings = oldSettings;
|
||||
@@ -30,16 +33,17 @@ namespace Orchard.AuditTrail.Providers.AuditTrail {
|
||||
context.Shape.Diff = diff;
|
||||
}
|
||||
|
||||
private IEnumerable<AuditTrailEventDescriptorSettingViewModel> GetDiffQuery(IEnumerable<AuditTrailEventSetting> oldSettings, IEnumerable<AuditTrailEventSetting> newSettings) {
|
||||
private IEnumerable<AuditTrailEventDescriptorSettingViewModel> GetDiffQuery(IEnumerable<AuditTrailEventSettingEventData> oldSettings, IEnumerable<AuditTrailEventSettingEventData> newSettings) {
|
||||
var oldDictionary = oldSettings.ToDictionary(x => x.EventName);
|
||||
|
||||
return
|
||||
from newSetting in newSettings
|
||||
let oldSetting = oldDictionary.ContainsKey(newSetting.EventName) ? oldDictionary[newSetting.EventName] : default(AuditTrailEventSetting)
|
||||
let oldSetting = oldDictionary.ContainsKey(newSetting.EventName) ? oldDictionary[newSetting.EventName] : default(AuditTrailEventSettingEventData)
|
||||
where oldSetting == null || oldSetting.IsEnabled != newSetting.IsEnabled
|
||||
let descriptor = _auditTrailManager.Value.DescribeEvent(newSetting.EventName)
|
||||
select new AuditTrailEventDescriptorSettingViewModel {
|
||||
Setting = newSetting,
|
||||
Descriptor = _auditTrailManager.Value.DescribeEvent(newSetting.EventName)
|
||||
Descriptor = descriptor
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@@ -1,9 +1,32 @@
|
||||
using Orchard.AuditTrail.Models;
|
||||
using System;
|
||||
using Orchard.AuditTrail.Helpers;
|
||||
using Orchard.AuditTrail.Providers.AuditTrail;
|
||||
using Orchard.AuditTrail.Services.Models;
|
||||
|
||||
namespace Orchard.AuditTrail.ViewModels {
|
||||
public class AuditTrailEventDescriptorSettingViewModel {
|
||||
public AuditTrailEventDescriptor Descriptor { get; set; }
|
||||
public AuditTrailEventSetting Setting { get; set; }
|
||||
public AuditTrailEventSettingEventData Setting { get; set; }
|
||||
|
||||
public string EventDisplayName {
|
||||
get { return
|
||||
!String.IsNullOrWhiteSpace(Setting.EventDisplayName)
|
||||
? Setting.EventDisplayName
|
||||
: Descriptor != null
|
||||
? Descriptor.Name.Text
|
||||
: EventNameExtensions.GetShortEventName(Setting.EventName);
|
||||
}
|
||||
}
|
||||
|
||||
public string EventCategory {
|
||||
get {
|
||||
return
|
||||
!String.IsNullOrWhiteSpace(Setting.EventCategory)
|
||||
? Setting.EventCategory
|
||||
: Descriptor != null
|
||||
? Descriptor.CategoryDescriptor.Name.Text
|
||||
: Setting.EventCategory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,7 +1,13 @@
|
||||
@using Orchard.AuditTrail.ViewModels
|
||||
@{
|
||||
var diff = (IList<AuditTrailEventDescriptorSettingViewModel>)Model.Diff;
|
||||
var descriptions = String.Join("<br/>", diff.Select(x => T("The <strong>{0}</strong> event in category <strong>{1}</strong> was <strong>{2}</strong>.", x.Descriptor.Name, x.Descriptor.CategoryDescriptor.Name, x.Setting.IsEnabled ? "enabled" : "disabled").Text));
|
||||
var descriptions = String.Join("<br/>", diff.Select(x => {
|
||||
var template = String.IsNullOrWhiteSpace(x.EventCategory)
|
||||
? "The <strong>{0}</strong> event was <strong>{2}</strong>."
|
||||
: "The <strong>{0}</strong> event in category <strong>{1}</strong> was <strong>{2}</strong>.";
|
||||
|
||||
return T(template, x.EventDisplayName, T(x.EventCategory), x.Setting.IsEnabled ? "enabled" : "disabled").Text;
|
||||
}));
|
||||
}
|
||||
<section class="audittrail-settings-eventsummary">
|
||||
@Html.Raw(descriptions)
|
||||
|
Reference in New Issue
Block a user