Implementing audit trail site settings.

This commit is contained in:
sfmskywalker
2014-05-28 00:39:52 +02:00
parent 5cf7a7e42f
commit 83602896b1
12 changed files with 271 additions and 5 deletions

View File

@@ -0,0 +1,64 @@
using System.Linq;
using Orchard.AuditTrail.Models;
using Orchard.AuditTrail.Services;
using Orchard.AuditTrail.ViewModels;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
namespace Orchard.AuditTrail.Drivers {
public class AuditTrailSiteSettingsPartDriver : ContentPartDriver<AuditTrailSiteSettingsPart> {
private readonly IAuditTrailManager _auditTrailManager;
public AuditTrailSiteSettingsPartDriver(IAuditTrailManager auditTrailManager) {
_auditTrailManager = auditTrailManager;
}
protected override DriverResult Editor(AuditTrailSiteSettingsPart part, dynamic shapeHelper) {
return Editor(part, null, shapeHelper);
}
protected override DriverResult Editor(AuditTrailSiteSettingsPart part, IUpdateModel updater, dynamic shapeHelper) {
return ContentShape("Parts_AuditTrailSiteSettings_Edit", () => {
var descriptors = _auditTrailManager.Describe();
var eventSettings = part.EventSettings.ToList();
var viewModel = new AuditTrailSiteSettingsViewModel {
AutoTrim = part.AutoTrim,
AutoTrimThreshold = part.AutoTrimThreshold,
Categories = (from categoryDescriptor in descriptors
select new AuditTrailCategorySettingsViewModel {
Category = categoryDescriptor.Category,
Name = categoryDescriptor.Name,
Events = (from eventDescriptor in categoryDescriptor.Events
let eventSetting = eventSettings.FirstOrDefault(x => x.EventName == eventDescriptor.Event)
select new AuditTrailEventSettingsViewModel {
Event = eventDescriptor.Event,
Name = eventDescriptor.Name,
Description = eventDescriptor.Description,
IsEnabled = eventSetting != null ? eventSetting.IsEnabled : eventDescriptor.IsEnabledByDefault
}).ToList()
}).ToList()
};
if (updater != null) {
if (updater.TryUpdateModel(viewModel, Prefix, null, null)) {
foreach (var eventSettingViewModel in viewModel.Categories.SelectMany(x => x.Events)) {
var eventSetting = eventSettings.FirstOrDefault(x => x.EventName == eventSettingViewModel.Event);
if (eventSetting == null) {
eventSetting = new AuditTrailEventSetting { EventName = eventSettingViewModel.Event};
eventSettings.Add(eventSetting);
}
eventSetting.IsEnabled = eventSettingViewModel.IsEnabled;
}
part.EventSettings = eventSettings;
part.AutoTrim = viewModel.AutoTrim;
part.AutoTrimThreshold = viewModel.AutoTrimThreshold;
}
}
return shapeHelper.EditorTemplate(TemplateName: "Parts.AuditTrailSiteSettings", Model: viewModel, Prefix: Prefix);
}).OnGroup("Audit Trail");
}
}
}

View File

@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Orchard.AuditTrail.Models;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Localization;
using Orchard.Logging;
namespace Orchard.AuditTrail.Handlers {
public class AuditTrailSiteSettingsPartHandler : ContentHandler {
public AuditTrailSiteSettingsPartHandler() {
OnActivated<AuditTrailSiteSettingsPart>(SetupLazyFields);
OnGetContentItemMetadata<AuditTrailSiteSettingsPart>(GetMetadata);
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
private void GetMetadata(GetContentItemMetadataContext context, AuditTrailSiteSettingsPart part) {
context.Metadata.EditorGroupInfo.Add(new GroupInfo(T("Audit Trail")));
}
private void SetupLazyFields(ActivatedContentContext context, AuditTrailSiteSettingsPart part) {
part._eventProviderSettingsField.Loader(() => DeserializeProviderConfiguration(part.Retrieve<string>("Events")));
part._eventProviderSettingsField.Setter(value => {
part.Store("Events", SerializeProviderConfiguration(value));
return value;
});
}
private IEnumerable<AuditTrailEventSetting> DeserializeProviderConfiguration(string data) {
if (String.IsNullOrWhiteSpace(data))
return Enumerable.Empty<AuditTrailEventSetting>();
try {
var doc = XDocument.Parse(data);
return doc.Element("Events").Elements("Event").Select(x => new AuditTrailEventSetting {
EventName = x.Attr<string>("Name"),
IsEnabled = x.Attr<bool>("IsEnabled")
}).ToArray();
}
catch (Exception ex) {
Logger.Error(ex, "Error occurred during deserialization of audit trail settings.");
}
return Enumerable.Empty<AuditTrailEventSetting>();
}
private string SerializeProviderConfiguration(IEnumerable<AuditTrailEventSetting> settings) {
var doc = new XDocument(
new XElement("Events",
settings.Select(x =>
new XElement("Event",
new XAttribute("Name", x.EventName),
new XAttribute("IsEnabled", x.IsEnabled)))));
return doc.ToString(SaveOptions.DisableFormatting);
}
}
}

View File

@@ -22,6 +22,12 @@ namespace Orchard.AuditTrail {
.Attachable()
.WithDescription("Enables the user to enter a comment about the change when saving a content item."));
ContentDefinitionManager.AlterPartDefinition("AuditTrailSiteSettingsPart", part => part
.Attachable(false)
.WithDescription("Stores the audit trail settings."));
ContentDefinitionManager.AlterTypeDefinition("Site", type => type.WithPart("AuditTrailSiteSettingsPart"));
return 1;
}
}

View File

@@ -0,0 +1,6 @@
namespace Orchard.AuditTrail.Models {
public class AuditTrailEventSetting {
public string EventName { get; set; }
public bool IsEnabled { get; set; }
}
}

View File

@@ -0,0 +1,27 @@
using System.Collections.Generic;
using Orchard.ContentManagement;
using Orchard.Core.Common.Utilities;
namespace Orchard.AuditTrail.Models {
public class AuditTrailSiteSettingsPart : ContentPart {
internal LazyField<IEnumerable<AuditTrailEventSetting>> _eventProviderSettingsField = new LazyField<IEnumerable<AuditTrailEventSetting>>();
public bool AutoTrim {
get { return this.Retrieve(x => x.AutoTrim, defaultValue: false); }
set { this.Store(x => x.AutoTrim, value); }
}
/// <summary>
/// Threshold in days.
/// </summary>
public int AutoTrimThreshold {
get { return this.Retrieve(x => x.AutoTrimThreshold, defaultValue: 10); }
set { this.Store(x => x.AutoTrimThreshold, value); }
}
public IEnumerable<AuditTrailEventSetting> EventSettings {
get { return _eventProviderSettingsField.Value; }
set { _eventProviderSettingsField.Value = value; }
}
}
}

View File

@@ -103,6 +103,7 @@
<Content Include="Views\AuditTrailEvent-ContentPart-FieldRemoved.SummaryAdmin.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentType-PartSettingsUpdated.SummaryAdmin.cshtml" />
<Content Include="Views\AuditTrailEvent-ContentPart-FieldSettingsUpdated.SummaryAdmin.cshtml" />
<Content Include="Views\EditorTemplates\Parts.AuditTrailSiteSettings.cshtml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Orchard\Orchard.Framework.csproj">
@@ -117,7 +118,14 @@
<ItemGroup>
<Compile Include="AdminMenu.cs" />
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Drivers\AuditTrailSiteSettingsPartDriver.cs" />
<Compile Include="ViewModels\AuditTrailCategorySettingsViewModel.cs" />
<Compile Include="ViewModels\AuditTrailEventSettingsViewModel.cs" />
<Compile Include="ViewModels\AuditTrailSiteSettingsViewModel.cs" />
<Compile Include="Drivers\ContentsDriver.cs" />
<Compile Include="Handlers\AuditTrailSiteSettingsPartHandler.cs" />
<Compile Include="Models\AuditTrailEventSetting.cs" />
<Compile Include="Models\AuditTrailSiteSettingsPart.cs" />
<Compile Include="Providers\ContentDefinition\ContentDefinitionEventHandler.cs" />
<Compile Include="Providers\ContentDefinition\GlobalContentDefinitionEditorEvents.cs" />
<Compile Include="Providers\ContentDefinition\ContentPartAuditTrailEventProvider.cs" />

View File

@@ -1,8 +1,9 @@
<Placement>
<Place Parts_AuditTrail_Comment="Content:after.1"
Parts_AuditTrail_Link="Content:after.2"
Parts_AuditTrail="Content:after.3"/>
Parts_AuditTrail="Content:after.3"
Parts_AuditTrailSiteSettings_Edit="Content:0"/>
<Match DisplayType="SummaryAdmin">
<Place Parts_Contents_AuditTrail_SummaryAdmin="Actions:7"/>
</Match>

View File

@@ -10,9 +10,14 @@
font-size: 0.8em;
}
.audit-trail-list .audit-trail-record .event-details {
}
.audit-trail-record-details fieldset legend span {
font-size: 0.8em;
}
.audit-trail-site-settings table th.event-name {
width: 250px;
}
.audit-trail-site-settings table th.event-enabled {
width: 60px;
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using Orchard.Localization;
namespace Orchard.AuditTrail.ViewModels {
public class AuditTrailCategorySettingsViewModel {
public string Category { get; set; }
public LocalizedString Name { get; set; }
public IList<AuditTrailEventSettingsViewModel> Events { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
using System.Collections;
using Orchard.Localization;
namespace Orchard.AuditTrail.ViewModels {
public class AuditTrailEventSettingsViewModel {
public string Event { get; set; }
public LocalizedString Name { get; set; }
public LocalizedString Description { get; set; }
public bool IsEnabled { get; set; }
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections;
using System.Collections.Generic;
namespace Orchard.AuditTrail.ViewModels {
public class AuditTrailSiteSettingsViewModel {
public bool AutoTrim { get; set; }
public int AutoTrimThreshold { get; set; }
public IList<AuditTrailCategorySettingsViewModel> Categories { get; set; }
}
}

View File

@@ -0,0 +1,56 @@
@model Orchard.AuditTrail.ViewModels.AuditTrailSiteSettingsViewModel
@{
Style.Include("admin.css");
}
<div class="audit-trail-site-settings">
<fieldset>
<legend>@T("Auto Trim Settings")</legend>
<div>
@Html.CheckBoxFor(m => m.AutoTrim)
@Html.LabelFor(m => m.AutoTrim, T("Automatically trim the audit trail for this site").Text, new { @class = "forcheckbox" })
<span class="hint">@T("Check this option to automatically trim the audit trail.")</span>
</div>
<div id="auditTrailAutoTrimthresholdSetting">
@Html.LabelFor(m => m.AutoTrimThreshold, T("Auto-trim threshold"))
@Html.TextBoxFor(m => m.AutoTrimThreshold, new { @class = "text small" })
<span class="hint">@T("Specify the number of days of audit log data to retain.")</span>
</div>
</fieldset>
<fieldset>
<legend>@T("Specify the events to audit")</legend>
@{
var i = 0;
}
@foreach (var category in Model.Categories) {
<fieldset>
<legend>@category.Name</legend>
<input type="hidden" name="AuditTrailSiteSettingsPart.Categories[@i].Category" value="@category.Category" />
<table class="items">
<thead>
<tr>
<th class="event-name">@T("Event")</th>
<th>@T("Description")</th>
<th class="event-enabled">@T("Enabled")</th>
</tr>
</thead>
@{ var j = 0; }
@foreach (var evnt in category.Events) {
var checkboxId = String.Format("Event{0}{1}", i, j);
<tr>
<td>
<input type="hidden" name="AuditTrailSiteSettingsPart.Categories[@i].Events[@j].Event" value="@evnt.Event" />
@evnt.Name
</td>
<td>@evnt.Description</td>
<td>
<input type="checkbox" id="@checkboxId" name="AuditTrailSiteSettingsPart.Categories[@i].Events[@j].IsEnabled" value="@Boolean.TrueString" @if(evnt.IsEnabled){<text>checked="checked"</text>} />
</td>
</tr>
j++;
}
</table>
</fieldset>
i++;
}
</fieldset>
</div>