From 5677c4dba91157a53fe1f8592477587b5f571b58 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 27 May 2011 12:11:31 -0700 Subject: [PATCH] Changing CreatedUtc behavior to be also set the first time it is published. Relies on DateEditorPartDriver to be enabled. --HG-- branch : 1.x --- .../Core/Common/Drivers/CommonPartDriver.cs | 109 +----------------- .../Common/Drivers/DateEditorPartDriver.cs | 96 +++++++++++++++ .../Common/Drivers/OwnerEditorPartDriver.cs | 71 ++++++++++++ .../Common/Handlers/DateEditorPartHandler.cs | 43 +++++++ .../Common/Settings/CommonEditorsSettings.cs | 52 +++++++++ .../Core/Common/Settings/CommonSettings.cs | 38 ------ .../CommonEditorsSettings.cshtml | 15 +++ .../CommonTypePartSettings.cshtml | 12 -- src/Orchard.Web/Core/Orchard.Core.csproj | 12 +- 9 files changed, 289 insertions(+), 159 deletions(-) create mode 100644 src/Orchard.Web/Core/Common/Drivers/DateEditorPartDriver.cs create mode 100644 src/Orchard.Web/Core/Common/Drivers/OwnerEditorPartDriver.cs create mode 100644 src/Orchard.Web/Core/Common/Handlers/DateEditorPartHandler.cs create mode 100644 src/Orchard.Web/Core/Common/Settings/CommonEditorsSettings.cs delete mode 100644 src/Orchard.Web/Core/Common/Settings/CommonSettings.cs create mode 100644 src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonEditorsSettings.cshtml delete mode 100644 src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonTypePartSettings.cshtml diff --git a/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs b/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs index f0edec011..8c6c1ea31 100644 --- a/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs +++ b/src/Orchard.Web/Core/Common/Drivers/CommonPartDriver.cs @@ -1,16 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Xml; +using System.Xml; using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; using Orchard.ContentManagement.Handlers; using Orchard.Core.Common.Models; -using Orchard.Core.Common.Settings; using Orchard.Core.Common.ViewModels; using Orchard.Localization; using Orchard.Security; -using Orchard.Services; namespace Orchard.Core.Common.Drivers { public class CommonPartDriver : ContentPartDriver { @@ -18,23 +13,17 @@ namespace Orchard.Core.Common.Drivers { private readonly IAuthenticationService _authenticationService; private readonly IAuthorizationService _authorizationService; private readonly IMembershipService _membershipService; - private readonly IClock _clock; - - private const string DatePattern = "M/d/yyyy"; - private const string TimePattern = "h:mm tt"; public CommonPartDriver( IOrchardServices services, IContentManager contentManager, IAuthenticationService authenticationService, IAuthorizationService authorizationService, - IMembershipService membershipService, - IClock clock) { + IMembershipService membershipService) { _contentManager = contentManager; _authenticationService = authenticationService; _authorizationService = authorizationService; _membershipService = membershipService; - _clock = clock; T = NullLocalizer.Instance; Services = services; } @@ -58,95 +47,10 @@ namespace Orchard.Core.Common.Drivers { } protected override DriverResult Editor(CommonPart part, dynamic shapeHelper) { - return BuildEditor(part, null, shapeHelper); + return Editor(part, null, shapeHelper); } protected override DriverResult Editor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { - // this event is hooked so the modified timestamp is changed when an edit-post occurs - part.ModifiedUtc = _clock.UtcNow; - part.VersionModifiedUtc = _clock.UtcNow; - - return BuildEditor(part, updater, shapeHelper); - } - - private DriverResult BuildEditor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { - List parts = new List(); - CommonTypePartSettings commonTypePartSettings = GetTypeSettings(part); - - if (commonTypePartSettings.ShowOwnerEditor) { - parts.Add(OwnerEditor(part, updater, shapeHelper)); - } - - if (commonTypePartSettings.ShowCreatedUtcEditor) { - parts.Add(CreatedUtcEditor(part, updater, shapeHelper)); - } - - parts.Add(ContainerEditor(part, updater, shapeHelper)); - - return Combined(parts.ToArray()); - } - - DriverResult OwnerEditor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { - var currentUser = _authenticationService.GetAuthenticatedUser(); - if (!_authorizationService.TryCheckAccess(StandardPermissions.SiteOwner, currentUser, part)) { - return null; - } - - var model = new OwnerEditorViewModel(); - if (part.Owner != null) - model.Owner = part.Owner.UserName; - - if (updater != null) { - var priorOwner = model.Owner; - updater.TryUpdateModel(model, Prefix, null, null); - - if (model.Owner != null && model.Owner != priorOwner) { - var newOwner = _membershipService.GetUser(model.Owner); - if (newOwner == null) { - updater.AddModelError("CommonPart.Owner", T("Invalid user name")); - } - else { - part.Owner = newOwner; - } - } - } - - return ContentShape("Parts_Common_Owner_Edit", - () => shapeHelper.EditorTemplate(TemplateName: "Parts.Common.Owner", Model: model, Prefix: Prefix)); - } - - DriverResult CreatedUtcEditor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { - CreatedUtcEditorViewModel model = new CreatedUtcEditorViewModel(); - if (part.CreatedUtc != null) { - model.CreatedDate = part.CreatedUtc.Value.ToLocalTime().ToString(DatePattern, CultureInfo.InvariantCulture); - model.CreatedTime = part.CreatedUtc.Value.ToLocalTime().ToString(TimePattern, CultureInfo.InvariantCulture); - } - - if (updater != null) { - updater.TryUpdateModel(model, Prefix, null, null); - - if (!string.IsNullOrWhiteSpace(model.CreatedDate) && !string.IsNullOrWhiteSpace(model.CreatedTime)) { - DateTime createdUtc; - string parseDateTime = String.Concat(model.CreatedDate, " ", model.CreatedTime); - - // use an english culture as it is the one used by jQuery.datepicker by default - if (DateTime.TryParse(parseDateTime, CultureInfo.GetCultureInfo("en-US"), DateTimeStyles.AssumeLocal, out createdUtc)) { - part.CreatedUtc = createdUtc.ToUniversalTime(); - } - else { - updater.AddModelError(Prefix, T("{0} is an invalid date and time", parseDateTime)); - } - } - else { - updater.AddModelError(Prefix, T("Both the date and time need to be specified.")); - } - } - - return ContentShape("Parts_Common_CreatedUtc_Edit", - () => shapeHelper.EditorTemplate(TemplateName: "Parts.Common.CreatedUtc", Model: model, Prefix: Prefix)); - } - - DriverResult ContainerEditor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { var currentUser = _authenticationService.GetAuthenticatedUser(); if (!_authorizationService.TryCheckAccess(StandardPermissions.SiteOwner, currentUser, part)) { return null; @@ -164,8 +68,7 @@ namespace Orchard.Core.Common.Drivers { var newContainer = _contentManager.Get((int)model.ContainerId, VersionOptions.Latest); if (newContainer == null) { updater.AddModelError("CommonPart.ContainerId", T("Invalid container")); - } - else { + } else { part.Container = newContainer; } } @@ -175,10 +78,6 @@ namespace Orchard.Core.Common.Drivers { () => shapeHelper.EditorTemplate(TemplateName: "Parts.Common.Container", Model: model, Prefix: Prefix)); } - private static CommonTypePartSettings GetTypeSettings(CommonPart part) { - return part.Settings.GetModel(); - } - protected override void Importing(CommonPart part, ImportContentContext context) { var owner = context.Attribute(part.PartDefinition.Name, "Owner"); if (owner != null) { diff --git a/src/Orchard.Web/Core/Common/Drivers/DateEditorPartDriver.cs b/src/Orchard.Web/Core/Common/Drivers/DateEditorPartDriver.cs new file mode 100644 index 000000000..715995fa1 --- /dev/null +++ b/src/Orchard.Web/Core/Common/Drivers/DateEditorPartDriver.cs @@ -0,0 +1,96 @@ +using System; +using System.Globalization; +using System.Linq; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Drivers; +using Orchard.Core.Common.Models; +using Orchard.Core.Common.Settings; +using Orchard.Core.Common.ViewModels; +using Orchard.Data; +using Orchard.Localization; +using Orchard.Services; + +namespace Orchard.Core.Common.Drivers { + public class DateEditorPartDriver : ContentPartDriver { + private readonly IRepository _commonPartVersionRecordRepository; + private readonly IClock _clock; + + private const string DatePattern = "M/d/yyyy"; + private const string TimePattern = "h:mm tt"; + + public DateEditorPartDriver( + IOrchardServices services, + IRepository commonPartVersionRecordRepository, + IClock clock) { + _commonPartVersionRecordRepository = commonPartVersionRecordRepository; + _clock = clock; + T = NullLocalizer.Instance; + Services = services; + } + + public Localizer T { get; set; } + public IOrchardServices Services { get; set; } + + protected override string Prefix { + get { return "DateEditorPart"; } + } + + protected override DriverResult Editor(CommonPart part, dynamic shapeHelper) { + return Editor(part, null, shapeHelper); + } + + protected override DriverResult Editor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { + + var commonEditorsSettings = CommonEditorsSettings.Get(part.ContentItem); + if(!commonEditorsSettings.ShowDateEditor) { + return null; + } + + // this event is hooked so the modified timestamp is changed when an edit-post occurs + part.Record.ModifiedUtc = _clock.UtcNow; + + var model = new CreatedUtcEditorViewModel(); + + if (part.CreatedUtc != null) { + // fetch CommonPartVersionRecord of first version + var firstVersion = _commonPartVersionRecordRepository.Fetch( + civr => civr.ContentItemRecord == part.ContentItem.Record, + order => order.Asc(record => record.ContentItemVersionRecord.Number), + 0, 1).FirstOrDefault(); + + // show CreatedUtc only if is has been "touched", + // i.e. it has been published once, or CreatedUtc has been set + if (firstVersion != null && firstVersion.CreatedUtc != part.CreatedUtc) { + model.CreatedDate = part.CreatedUtc.Value.ToLocalTime().ToString(DatePattern, CultureInfo.InvariantCulture); + model.CreatedTime = part.CreatedUtc.Value.ToLocalTime().ToString(TimePattern, CultureInfo.InvariantCulture); + } + } + + if (updater != null) { + updater.TryUpdateModel(model, Prefix, null, null); + + if (!string.IsNullOrWhiteSpace(model.CreatedDate) && !string.IsNullOrWhiteSpace(model.CreatedTime)) { + DateTime createdUtc; + string parseDateTime = String.Concat(model.CreatedDate, " ", model.CreatedTime); + + // use an english culture as it is the one used by jQuery.datepicker by default + if (DateTime.TryParse(parseDateTime, CultureInfo.GetCultureInfo("en-US"), DateTimeStyles.AssumeLocal, out createdUtc)) { + part.CreatedUtc = createdUtc.ToUniversalTime(); + } + else { + updater.AddModelError(Prefix, T("{0} is an invalid date and time", parseDateTime)); + } + } + else if (!string.IsNullOrWhiteSpace(model.CreatedDate) || !string.IsNullOrWhiteSpace(model.CreatedTime)) { + // only one part is specified + updater.AddModelError(Prefix, T("Both the date and time need to be specified.")); + } + + // none date/time part is specified => do nothing + } + + return ContentShape("Parts_Common_CreatedUtc_Edit", + () => shapeHelper.EditorTemplate(TemplateName: "Parts.Common.CreatedUtc", Model: model, Prefix: Prefix)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Drivers/OwnerEditorPartDriver.cs b/src/Orchard.Web/Core/Common/Drivers/OwnerEditorPartDriver.cs new file mode 100644 index 000000000..b24092ffa --- /dev/null +++ b/src/Orchard.Web/Core/Common/Drivers/OwnerEditorPartDriver.cs @@ -0,0 +1,71 @@ +using Orchard.ContentManagement; +using Orchard.ContentManagement.Drivers; +using Orchard.Core.Common.Models; +using Orchard.Core.Common.Settings; +using Orchard.Core.Common.ViewModels; +using Orchard.Localization; +using Orchard.Security; + +namespace Orchard.Core.Common.Drivers { + public class OwnerEditorPartDriver : ContentPartDriver { + private readonly IAuthenticationService _authenticationService; + private readonly IAuthorizationService _authorizationService; + private readonly IMembershipService _membershipService; + + public OwnerEditorPartDriver( + IOrchardServices services, + IAuthenticationService authenticationService, + IAuthorizationService authorizationService, + IMembershipService membershipService) { + _authenticationService = authenticationService; + _authorizationService = authorizationService; + _membershipService = membershipService; + T = NullLocalizer.Instance; + Services = services; + } + + public Localizer T { get; set; } + public IOrchardServices Services { get; set; } + + protected override string Prefix { + get { return "OwnerEditorPart"; } + } + + protected override DriverResult Editor(CommonPart part, dynamic shapeHelper) { + return Editor(part, null, shapeHelper); + } + + protected override DriverResult Editor(CommonPart part, IUpdateModel updater, dynamic shapeHelper) { + var currentUser = _authenticationService.GetAuthenticatedUser(); + if (!_authorizationService.TryCheckAccess(StandardPermissions.SiteOwner, currentUser, part)) { + return null; + } + + var commonEditorsSettings = CommonEditorsSettings.Get(part.ContentItem); + if (!commonEditorsSettings.ShowOwnerEditor) { + return null; + } + + var model = new OwnerEditorViewModel(); + if (part.Owner != null) + model.Owner = part.Owner.UserName; + + if (updater != null) { + var priorOwner = model.Owner; + updater.TryUpdateModel(model, Prefix, null, null); + + if (model.Owner != null && model.Owner != priorOwner) { + var newOwner = _membershipService.GetUser(model.Owner); + if (newOwner == null) { + updater.AddModelError("CommonPart.Owner", T("Invalid user name")); + } else { + part.Owner = newOwner; + } + } + } + + return ContentShape("Parts_Common_Owner_Edit", + () => shapeHelper.EditorTemplate(TemplateName: "Parts.Common.Owner", Model: model, Prefix: Prefix)); + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Handlers/DateEditorPartHandler.cs b/src/Orchard.Web/Core/Common/Handlers/DateEditorPartHandler.cs new file mode 100644 index 000000000..49f484f74 --- /dev/null +++ b/src/Orchard.Web/Core/Common/Handlers/DateEditorPartHandler.cs @@ -0,0 +1,43 @@ +using System.Linq; +using JetBrains.Annotations; +using Orchard.Core.Common.Models; +using Orchard.Core.Common.Settings; +using Orchard.Data; +using Orchard.ContentManagement.Handlers; +using Orchard.Services; + +namespace Orchard.Core.Common.Handlers { + [UsedImplicitly] + public class DateEditorPartHandler : ContentHandler { + private readonly IRepository _commonPartVersionRepository; + private readonly IClock _clock; + + public DateEditorPartHandler( + IRepository commonPartVersionRepository, + IClock clock) { + _commonPartVersionRepository = commonPartVersionRepository; + _clock = clock; + + OnPublished(AssignCreatingDates); + + } + + protected void AssignCreatingDates(PublishContentContext context, CommonPart part) { + var commonEditorsSettings = CommonEditorsSettings.Get(part.ContentItem); + if (!commonEditorsSettings.ShowDateEditor) { + return; + } + + // fetch CommonPartVersionRecord of first version + var firstVersion = _commonPartVersionRepository.Fetch( + civr => civr.ContentItemRecord == part.ContentItem.Record, + order => order.Asc(record => record.ContentItemVersionRecord.Number), + 0, 1).FirstOrDefault(); + + if (firstVersion != null && firstVersion.CreatedUtc == part.CreatedUtc) { + // "touch" CreatedUtc in ContentItemRecord + part.Record.CreatedUtc = _clock.UtcNow; + } + } + } +} diff --git a/src/Orchard.Web/Core/Common/Settings/CommonEditorsSettings.cs b/src/Orchard.Web/Core/Common/Settings/CommonEditorsSettings.cs new file mode 100644 index 000000000..d42593397 --- /dev/null +++ b/src/Orchard.Web/Core/Common/Settings/CommonEditorsSettings.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Linq; +using Orchard.ContentManagement; +using Orchard.ContentManagement.MetaData; +using Orchard.ContentManagement.MetaData.Builders; +using Orchard.ContentManagement.MetaData.Models; +using Orchard.ContentManagement.ViewModels; +using Orchard.Core.Common.Models; + +namespace Orchard.Core.Common.Settings { + public class CommonEditorsSettings { + public CommonEditorsSettings() { + // defaults + ShowOwnerEditor = true; + ShowDateEditor = false; + } + + public bool ShowDateEditor { get; set; } + public bool ShowOwnerEditor { get; set; } + + public static CommonEditorsSettings Get(ContentItem contentItem) { + if (contentItem == null || + contentItem.TypeDefinition == null || + contentItem.TypeDefinition.Settings == null) { + return new CommonEditorsSettings(); + } + return contentItem.TypeDefinition.Settings.GetModel(); + } + } + + public class CommonEditorsEvents : ContentDefinitionEditorEventsBase { + public override IEnumerable TypeEditor(ContentTypeDefinition definition) { + if (!definition.Parts.Any(part => part.PartDefinition.Name == typeof(CommonPart).Name)) { + yield break; + } + + var model = definition.Settings.GetModel(); + yield return DefinitionTemplate(model); + } + + public override IEnumerable TypeEditorUpdate(ContentTypeDefinitionBuilder builder, IUpdateModel updateModel) { + var model = new CommonEditorsSettings(); + updateModel.TryUpdateModel(model, "CommonEditorsSettings", null, null); + + builder.WithSetting("CommonEditorsSettings.ShowDateEditor", model.ShowDateEditor.ToString()); + builder.WithSetting("CommonEditorsSettings.ShowOwnerEditor", model.ShowOwnerEditor.ToString()); + + yield return DefinitionTemplate(model); + } + } + +} diff --git a/src/Orchard.Web/Core/Common/Settings/CommonSettings.cs b/src/Orchard.Web/Core/Common/Settings/CommonSettings.cs deleted file mode 100644 index 20c3a334d..000000000 --- a/src/Orchard.Web/Core/Common/Settings/CommonSettings.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Collections.Generic; -using Orchard.ContentManagement; -using Orchard.ContentManagement.MetaData; -using Orchard.ContentManagement.MetaData.Builders; -using Orchard.ContentManagement.MetaData.Models; -using Orchard.ContentManagement.ViewModels; - -namespace Orchard.Core.Common.Settings { - public class CommonTypePartSettings { - public CommonTypePartSettings() { - ShowOwnerEditor = true; - } - - public bool ShowCreatedUtcEditor { get; set; } - public bool ShowOwnerEditor { get; set; } - } - - public class CommonSettingsHooks : ContentDefinitionEditorEventsBase { - public override IEnumerable TypePartEditor(ContentTypePartDefinition definition) { - if (definition.PartDefinition.Name != "CommonPart") - yield break; - - var model = definition.Settings.GetModel(); - yield return DefinitionTemplate(model); - } - - public override IEnumerable TypePartEditorUpdate(ContentTypePartDefinitionBuilder builder, IUpdateModel updateModel) { - if (builder.Name != "CommonPart") - yield break; - - var model = new CommonTypePartSettings(); - updateModel.TryUpdateModel(model, "CommonTypePartSettings", null, null); - builder.WithSetting("CommonTypePartSettings.ShowCreatedUtcEditor", model.ShowCreatedUtcEditor.ToString()); - builder.WithSetting("CommonTypePartSettings.ShowOwnerEditor", model.ShowOwnerEditor.ToString()); - yield return DefinitionTemplate(model); - } - } -} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonEditorsSettings.cshtml b/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonEditorsSettings.cshtml new file mode 100644 index 000000000..8806a8b1c --- /dev/null +++ b/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonEditorsSettings.cshtml @@ -0,0 +1,15 @@ +@model Orchard.Core.Common.Settings.CommonEditorsSettings + +
+
+ @Html.EditorFor(m=>m.ShowDateEditor) + + @Html.ValidationMessageFor(m => m.ShowDateEditor) +
+ +
+ @Html.EditorFor(m=>m.ShowOwnerEditor) + + @Html.ValidationMessageFor(m => m.ShowOwnerEditor) +
+
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonTypePartSettings.cshtml b/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonTypePartSettings.cshtml deleted file mode 100644 index b4d3ea916..000000000 --- a/src/Orchard.Web/Core/Common/Views/DefinitionTemplates/CommonTypePartSettings.cshtml +++ /dev/null @@ -1,12 +0,0 @@ -@model Orchard.Core.Common.Settings.CommonTypePartSettings -
- @Html.CheckBoxFor(m => m.ShowCreatedUtcEditor) - - @Html.ValidationMessageFor(m => m.ShowCreatedUtcEditor) -
- -
- @Html.CheckBoxFor(m => m.ShowOwnerEditor) - - @Html.ValidationMessageFor(m => m.ShowOwnerEditor) -
\ No newline at end of file diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index 86abf950d..600ef490e 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -18,6 +18,7 @@ 3.5 + false true @@ -61,14 +62,17 @@ + + + - + @@ -430,9 +434,6 @@ - - - @@ -441,6 +442,9 @@ Designer + + +