From da72fc980988953cadc980f630c55c998debdb03 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Thu, 27 Nov 2014 16:55:18 -0800 Subject: [PATCH] #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 --- .../Handlers/AuditTrailSettingsPartHandler.cs | 6 +- .../Orchard.AuditTrail.csproj | 2 + .../AuditTrailEventSettingEventData.cs | 9 +++ .../AuditTrail/AuditTrailManagerExtensions.cs | 59 +++++++++++++++++++ .../AuditTrailSettingsEventShape.cs | 16 +++-- ...ditTrailEventDescriptorSettingViewModel.cs | 27 ++++++++- ...Settings-EventsChanged.SummaryAdmin.cshtml | 8 ++- 7 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailEventSettingEventData.cs create mode 100644 src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailManagerExtensions.cs diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Handlers/AuditTrailSettingsPartHandler.cs b/src/Orchard.Web/Modules/Orchard.AuditTrail/Handlers/AuditTrailSettingsPartHandler.cs index 657de865e..2c659e92e 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Handlers/AuditTrailSettingsPartHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Handlers/AuditTrailSettingsPartHandler.cs @@ -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( eventName: AuditTrailSettingsEventProvider.EventsChanged, eventData: new Dictionary { - {"OldSettings", _oldEventSettings}, - {"NewSettings", newEventSettings} + {"OldSettings", _auditTrailManager.ToEventData(_oldEventSettings)}, + {"NewSettings", _auditTrailManager.ToEventData(newEventSettings)} }, user: _wca.GetContext().CurrentUser); } diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Orchard.AuditTrail.csproj b/src/Orchard.Web/Modules/Orchard.AuditTrail/Orchard.AuditTrail.csproj index f0626ffd4..7d9b5d8fe 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Orchard.AuditTrail.csproj +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Orchard.AuditTrail.csproj @@ -189,6 +189,8 @@ + + diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailEventSettingEventData.cs b/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailEventSettingEventData.cs new file mode 100644 index 000000000..7e6be2c76 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailEventSettingEventData.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; } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailManagerExtensions.cs b/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailManagerExtensions.cs new file mode 100644 index 000000000..36eb7813c --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailManagerExtensions.cs @@ -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 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 DeserializeEventData(string data, ILogger logger) { + if (String.IsNullOrWhiteSpace(data)) + return Enumerable.Empty(); + + try { + var doc = XDocument.Parse(data); + return doc.Element("Events").Elements("Event").Select(x => new AuditTrailEventSettingEventData { + EventName = x.Attr("Name"), + IsEnabled = x.Attr("IsEnabled"), + EventDisplayName = x.Attr("DisplayName"), + EventCategory = x.Attr("Category") + }).ToArray(); + + } + catch (Exception ex) { + logger.Error(ex, "Error occurred during deserialization of audit trail settings."); + } + return Enumerable.Empty(); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailSettingsEventShape.cs b/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailSettingsEventShape.cs index 201519c3a..0b54ec6d6 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailSettingsEventShape.cs +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Providers/AuditTrail/AuditTrailSettingsEventShape.cs @@ -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 { @@ -13,16 +13,19 @@ namespace Orchard.AuditTrail.Providers.AuditTrail { public AuditTrailSettingsEventShape(Work 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)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 GetDiffQuery(IEnumerable oldSettings, IEnumerable newSettings) { + private IEnumerable GetDiffQuery(IEnumerable oldSettings, IEnumerable 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 }; } } diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/ViewModels/AuditTrailEventDescriptorSettingViewModel.cs b/src/Orchard.Web/Modules/Orchard.AuditTrail/ViewModels/AuditTrailEventDescriptorSettingViewModel.cs index d8652e987..3aaa15d05 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/ViewModels/AuditTrailEventDescriptorSettingViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/ViewModels/AuditTrailEventDescriptorSettingViewModel.cs @@ -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; + } + } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEvent-AuditTrailSettings-EventsChanged.SummaryAdmin.cshtml b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEvent-AuditTrailSettings-EventsChanged.SummaryAdmin.cshtml index bc8f0f3fe..b12c7b343 100644 --- a/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEvent-AuditTrailSettings-EventsChanged.SummaryAdmin.cshtml +++ b/src/Orchard.Web/Modules/Orchard.AuditTrail/Views/AuditTrailEvent-AuditTrailSettings-EventsChanged.SummaryAdmin.cshtml @@ -1,7 +1,13 @@ @using Orchard.AuditTrail.ViewModels @{ var diff = (IList)Model.Diff; - var descriptions = String.Join("
", diff.Select(x => T("The {0} event in category {1} was {2}.", x.Descriptor.Name, x.Descriptor.CategoryDescriptor.Name, x.Setting.IsEnabled ? "enabled" : "disabled").Text)); + var descriptions = String.Join("
", diff.Select(x => { + var template = String.IsNullOrWhiteSpace(x.EventCategory) + ? "The {0} event was {2}." + : "The {0} event in category {1} was {2}."; + + return T(template, x.EventDisplayName, T(x.EventCategory), x.Setting.IsEnabled ? "enabled" : "disabled").Text; + })); }
@Html.Raw(descriptions)