From 21b5a1b2ac51437391c3a052724fd8a15a978e0e Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 16 Sep 2014 17:03:04 -0700 Subject: [PATCH] Fixing PublishLater/CreatedUtc behaviors --- .../Common/DateEditor/DateEditorDriver.cs | 9 +++- .../Common/DateEditor/DateEditorHandler.cs | 3 +- .../Core/Common/Handlers/CommonPartHandler.cs | 15 ++++--- .../Core/Common/Utilities/DateUtils.cs | 44 +++++++++++++++++++ src/Orchard.Web/Core/Orchard.Core.csproj | 1 + .../EditorTemplates/Parts/PublishLater.cshtml | 2 + .../Data/Conventions/UtcDateTimeConvention.cs | 27 ++++++++++++ .../Providers/AbstractDataServicesProvider.cs | 1 + src/Orchard/Data/SessionConfigurationCache.cs | 4 ++ src/Orchard/Orchard.Framework.csproj | 1 + 10 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 src/Orchard.Web/Core/Common/Utilities/DateUtils.cs create mode 100644 src/Orchard/Data/Conventions/UtcDateTimeConvention.cs diff --git a/src/Orchard.Web/Core/Common/DateEditor/DateEditorDriver.cs b/src/Orchard.Web/Core/Common/DateEditor/DateEditorDriver.cs index bcb6740e3..7d17d1d48 100644 --- a/src/Orchard.Web/Core/Common/DateEditor/DateEditorDriver.cs +++ b/src/Orchard.Web/Core/Common/DateEditor/DateEditorDriver.cs @@ -2,6 +2,7 @@ using Orchard.ContentManagement; using Orchard.ContentManagement.Drivers; using Orchard.Core.Common.Models; +using Orchard.Core.Common.Utilities; using Orchard.Core.Common.ViewModels; using Orchard.Localization; using Orchard.Localization.Services; @@ -51,7 +52,11 @@ namespace Orchard.Core.Common.DateEditor { var itemHasNeverBeenPublished = part.PublishedUtc == null; var thisIsTheInitialVersionRecord = part.ContentItem.Version < 2; - var theDatesHaveNotBeenModified = part.CreatedUtc == part.VersionCreatedUtc; + + // Dates are assumed the same if the millisecond part is the only difference. + // This is because SqlCe doesn't support high precision times (Datetime2) and the infoset does + // implying some discrepancies between values read from different storage mechanism. + var theDatesHaveNotBeenModified = DateUtils.DatesAreEquivalent(part.CreatedUtc, part.VersionCreatedUtc); var theEditorShouldBeBlank = itemHasNeverBeenPublished && @@ -71,7 +76,6 @@ namespace Orchard.Core.Common.DateEditor { try { var utcDateTime = _dateServices.ConvertFromLocalString(model.Editor.Date, model.Editor.Time); part.CreatedUtc = utcDateTime; - part.VersionCreatedUtc = utcDateTime; } catch (FormatException) { updater.AddModelError(Prefix, T("'{0} {1}' could not be parsed as a valid date and time.", model.Editor.Date, model.Editor.Time)); @@ -87,5 +91,6 @@ namespace Orchard.Core.Common.DateEditor { return model; }); } + } } \ No newline at end of file diff --git a/src/Orchard.Web/Core/Common/DateEditor/DateEditorHandler.cs b/src/Orchard.Web/Core/Common/DateEditor/DateEditorHandler.cs index f31bebdcd..bc5480fd2 100644 --- a/src/Orchard.Web/Core/Common/DateEditor/DateEditorHandler.cs +++ b/src/Orchard.Web/Core/Common/DateEditor/DateEditorHandler.cs @@ -1,6 +1,7 @@ using JetBrains.Annotations; using Orchard.Core.Common.Models; using Orchard.ContentManagement.Handlers; +using Orchard.Core.Common.Utilities; namespace Orchard.Core.Common.DateEditor { [UsedImplicitly] @@ -13,7 +14,7 @@ namespace Orchard.Core.Common.DateEditor { } var thisIsTheInitialVersionRecord = part.ContentItem.Version < 2; - var theDatesHaveNotBeenModified = part.CreatedUtc == part.VersionCreatedUtc; + var theDatesHaveNotBeenModified = DateUtils.DatesAreEquivalent(part.CreatedUtc, part.VersionCreatedUtc); var theContentDateShouldBeUpdated = thisIsTheInitialVersionRecord && theDatesHaveNotBeenModified; if (theContentDateShouldBeUpdated) { diff --git a/src/Orchard.Web/Core/Common/Handlers/CommonPartHandler.cs b/src/Orchard.Web/Core/Common/Handlers/CommonPartHandler.cs index f5b057af8..2731d8625 100644 --- a/src/Orchard.Web/Core/Common/Handlers/CommonPartHandler.cs +++ b/src/Orchard.Web/Core/Common/Handlers/CommonPartHandler.cs @@ -49,11 +49,13 @@ namespace Orchard.Core.Common.Handlers { OnPublishing(AssignPublishingDates); OnIndexing((context, commonPart) => { + var utcNow = _clock.UtcNow; + context.DocumentIndex .Add("type", commonPart.ContentItem.ContentType).Store() - .Add("created", commonPart.CreatedUtc ?? _clock.UtcNow).Store() - .Add("published", commonPart.PublishedUtc ?? _clock.UtcNow).Store() - .Add("modified", commonPart.ModifiedUtc ?? _clock.UtcNow).Store(); + .Add("created", commonPart.CreatedUtc ?? utcNow).Store() + .Add("published", commonPart.PublishedUtc ?? utcNow).Store() + .Add("modified", commonPart.ModifiedUtc ?? utcNow).Store(); if (commonPart.Container != null) { context.DocumentIndex.Add("container-id", commonPart.Container.Id).Store(); @@ -93,6 +95,7 @@ namespace Orchard.Core.Common.Handlers { protected void AssignCreatingDates(InitializingContentContext context, CommonPart part) { // assign default create/modified dates var utcNow = _clock.UtcNow; + part.CreatedUtc = utcNow; part.ModifiedUtc = utcNow; part.VersionCreatedUtc = utcNow; @@ -101,6 +104,7 @@ namespace Orchard.Core.Common.Handlers { private void AssignUpdateDates(UpdateEditorContext context, CommonPart part) { var utcNow = _clock.UtcNow; + part.ModifiedUtc = utcNow; part.VersionModifiedUtc = utcNow; } @@ -116,16 +120,17 @@ namespace Orchard.Core.Common.Handlers { building.VersionPublishedUtc = null; // assign the created - building.CreatedUtc = existing.CreatedUtc ?? _clock.UtcNow; + building.CreatedUtc = existing.CreatedUtc ?? utcNow; // persist any published dates building.PublishedUtc = existing.PublishedUtc; // assign modified date for the new version - building.ModifiedUtc = _clock.UtcNow; + building.ModifiedUtc = utcNow; } protected void AssignPublishingDates(PublishContentContext context, CommonPart part) { var utcNow = _clock.UtcNow; + part.PublishedUtc = utcNow; part.VersionPublishedUtc = utcNow; } diff --git a/src/Orchard.Web/Core/Common/Utilities/DateUtils.cs b/src/Orchard.Web/Core/Common/Utilities/DateUtils.cs new file mode 100644 index 000000000..8df52083c --- /dev/null +++ b/src/Orchard.Web/Core/Common/Utilities/DateUtils.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Orchard.Core.Common.Utilities { + public class DateUtils { + + /// + /// Compares two instance without their milliseconds portion. + /// + /// The first to compare. + /// The second to compare. + /// True if the two instances are in the same second, False otherwise. + public static bool DatesAreEquivalent(DateTime a, DateTime b) { + a = a.ToUniversalTime(); + b = b.ToUniversalTime(); + + return + new DateTime(a.Year, a.Month, a.Day, a.Hour, a.Minute, a.Second) == + new DateTime(b.Year, b.Month, b.Day, b.Hour, b.Minute, b.Second); + + } + + /// + /// Compares two instance without their milliseconds portion. + /// + /// The first to compare. + /// The second to compare. + /// True if the two instances are in the same second, False otherwise. + public static bool DatesAreEquivalent(DateTime? a, DateTime? b) { + if (!a.HasValue && !b.HasValue) { + return true; + } + + if (a.HasValue != b.HasValue) { + return false; + } + + return DatesAreEquivalent(a.Value, b.Value); + } + + } +} \ 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 ec0d287c4..62b7b698a 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -92,6 +92,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml index 22018f768..c93d3ece9 100644 --- a/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml +++ b/src/Orchard.Web/Modules/Orchard.PublishLater/Views/EditorTemplates/Parts/PublishLater.cshtml @@ -27,6 +27,8 @@
@T("Publish") + @Html.HiddenFor(m => m.Editor.ShowDate) + @Html.HiddenFor(m => m.Editor.ShowTime) @Html.EditorFor(m => m.Editor)
diff --git a/src/Orchard/Data/Conventions/UtcDateTimeConvention.cs b/src/Orchard/Data/Conventions/UtcDateTimeConvention.cs new file mode 100644 index 000000000..6c30405e1 --- /dev/null +++ b/src/Orchard/Data/Conventions/UtcDateTimeConvention.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FluentNHibernate.Conventions; +using FluentNHibernate.Conventions.AcceptanceCriteria; +using FluentNHibernate.Conventions.Inspections; +using FluentNHibernate.Conventions.Instances; +using NHibernate.Type; + +namespace Orchard.Data.Conventions { + public class UtcDateTimeConvention : IPropertyConvention, IPropertyConventionAcceptance { + public void Apply(IPropertyInstance instance) { + instance.CustomType(); + } + + public void Accept(IAcceptanceCriteria criteria) { + criteria.Expect(x => + x.Property.Name.EndsWith("Utc", StringComparison.OrdinalIgnoreCase) && ( + x.Property.PropertyType.Equals(typeof(DateTime)) || + x.Property.PropertyType.Equals(typeof(DateTime?)) + ) + ); + } + } +} diff --git a/src/Orchard/Data/Providers/AbstractDataServicesProvider.cs b/src/Orchard/Data/Providers/AbstractDataServicesProvider.cs index 7114783b6..fd1e40c23 100644 --- a/src/Orchard/Data/Providers/AbstractDataServicesProvider.cs +++ b/src/Orchard/Data/Providers/AbstractDataServicesProvider.cs @@ -91,6 +91,7 @@ namespace Orchard.Data.Providers { .Conventions.Setup(x => x.Add(AutoImport.Never())) .Conventions.Add(new RecordTableNameConvention(recordDescriptors)) .Conventions.Add(new CacheConventions(recordDescriptors)) + .Conventions.Add(new UtcDateTimeConvention()) .Alterations(alt => { foreach (var recordAssembly in recordDescriptors.Select(x => x.Type.Assembly).Distinct()) { alt.Add(new AutoMappingOverrideAlteration(recordAssembly)); diff --git a/src/Orchard/Data/SessionConfigurationCache.cs b/src/Orchard/Data/SessionConfigurationCache.cs index abe43262b..f83024905 100644 --- a/src/Orchard/Data/SessionConfigurationCache.cs +++ b/src/Orchard/Data/SessionConfigurationCache.cs @@ -142,6 +142,10 @@ namespace Orchard.Data { var pathName = GetPathName(_shellSettings.Name); hash.AddString(_appDataFolder.MapPath(pathName).ToLowerInvariant()); + // Orchard version, to rebuild the mappings for each new version + var orchardVersion = new System.Reflection.AssemblyName(typeof(Orchard.ContentManagement.ContentItem).Assembly.FullName).Version.ToString(); + hash.AddString(orchardVersion); + // Shell settings data hash.AddString(_shellSettings.DataProvider); hash.AddString(_shellSettings.DataTablePrefix); diff --git a/src/Orchard/Orchard.Framework.csproj b/src/Orchard/Orchard.Framework.csproj index c53b93f26..83b68dd76 100644 --- a/src/Orchard/Orchard.Framework.csproj +++ b/src/Orchard/Orchard.Framework.csproj @@ -175,6 +175,7 @@ +