From c2b931a488ee5bc791b895f046a102b589017611 Mon Sep 17 00:00:00 2001 From: Cody Rodgers Date: Tue, 19 Dec 2023 12:36:00 -0500 Subject: [PATCH] V10.2.X-5 (#22) * Update the videos/playlists pull pipelines to automatically refresh the search index to prevent a race condition (#14) Co-authored-by: Cody Rodgers * v10.1.X-3.6 (#18) * V10.2.0.3 (#16) * Fixed broken DXF configuration content for labels/folders * Add more error handling to the folder and labels property value readers * Fix bug preventing new labels from being synced * Remove automatic re-indexing from the videos/playlists pipeline --------- Co-authored-by: Cody Rodgers * Add missing embed media buttons * Reorganize DEF files * Update the DEF GET pipelines to have better error handling and removed broken SetFolderSettings code * Update the DEF resolve pipelines to have better error handling * Updated the UPDATE DEF pipelines to have better logging and error handling * Update playlist/video pipelines to accuratly reflect video name changes made outside of Sitecore * Fix bug preventing deleted Brightcove items from being deleted in Sitecore * Fix broken standard values for experience items * Update the Brightcove services to trim account ids/secrets * Update logging levels on video/player pipelines * Update all pipelines to handle name changes * Update sitecore package creation script to include patching instructions * Update the pull pipelines to support creating items in languages other an "en" * Update all template fields to be shared * Update the push pipelines to support creating items in languages other than "en" * Update the folder/labels value readers to have better error handling * Add support for embedding medai links again. It was removed as part of the upgrade but returned on client request * Update the resolve asset item pipeline step to rename resolved items if the name has been changed since creation * Fix the brightcove settings config so it loads both html editor scripts correctly * Update sitecore package creation script --------- Co-authored-by: Cody Rodgers * Fix bug which prevents the user from embedding media in the Siteocre RTE in certain scenarios * Add support for syncing video scheduling/status information * Reserialize content * Add some help text to the new scheduling fields --------- Co-authored-by: Cody Rodgers --- Brightcove.Core/Brightcove.Core.csproj | 1 + .../BrightcoveEmbedGenerator.cs | 13 ++--- .../EmbedGenerator/Models/EmbedMarkup.cs | 2 - Brightcove.Core/Models/Video.cs | 3 ++ Brightcove.Core/Models/VideoSchedule.cs | 14 ++++++ Brightcove.Core/Services/BrightcoveService.cs | 4 +- .../Brightcove.DataExchangeFramework.csproj | 3 ++ .../DateTimePropertyValueAccessorConverter.cs | 49 ++++++++++++++++++ .../DateTimePropertyValueReader.cs | 44 ++++++++++++++++ .../DateTimePropertyValueWriter.cs | 39 +++++++++++++++ .../EmbedGenerator/SitecoreEmbedGenerator.cs | 4 ++ Brightcove.Web/UI/Wizards/EmbedMediaWizard.cs | 2 +- .../Web/Brightcove/Views/EmbedMedia.cshtml | 1 - .../Rich Text Editor/EmbedMedia/EmbedMedia.js | 17 ++++++- .../Schedule_StartsAt Property.yml | 22 ++++++++ .../ItemState Property.yml | 18 +++++++ .../Schedule_EndsAt Property.yml | 22 ++++++++ .../Video Item Fields/EndsAt Field.yml | 22 ++++++++ .../Video Item Fields/StartsAt Field.yml | 22 ++++++++ .../Video Item Fields/State Field.yml | 18 +++++++ .../Common/ISO Date Value Reader.yml | 18 +++++++ .../Common/ItemState Enum Value Reader.yml | 22 ++++++++ .../Pipeline Batches/Pull Pipeline Batch.yml | 2 +- .../EndsAt Field Mapping.yml | 33 ++++++++++++ .../StartsAt Field Mapping.yml | 33 ++++++++++++ .../State Field Mapping.yml | 25 ++++++++++ .../ItemState Property Mapping.yml | 22 ++++++++ .../Schedule_EndsAt Property Mappi.yml | 33 ++++++++++++ .../Schedule_StartsAt Property Map.yml | 33 ++++++++++++ .../DateTime Property Value Access.yml | 34 +++++++++++++ .../Property.yml | 18 +++++++ .../Property/PropertyName.yml | 29 +++++++++++ .../__Standard Values.yml | 22 ++++++++ .../Brightcove Mappings Applied Ac.yml | 10 ++-- .../__Standard Values.yml | 8 +-- ..._0b208341-474a-4ef0-b341-5fd09013b6d0.yml} | 10 ++-- .../__Standard Values.yml | 8 +-- .../BrightcoveAccount/__Standard Values.yml | 50 +++++++++---------- .../Brightcove/BrightcoveVideo/Scheduling.yml | 22 ++++++++ .../BrightcoveVideo/Scheduling/EndsAt.yml | 25 ++++++++++ .../BrightcoveVideo/Scheduling/StartsAt.yml | 25 ++++++++++ .../BrightcoveVideo/Scheduling/State.yml | 35 +++++++++++++ .../__Standard Values.yml | 6 +-- 43 files changed, 784 insertions(+), 59 deletions(-) create mode 100644 Brightcove.Core/Models/VideoSchedule.cs create mode 100644 Brightcove.DataExchangeFramework/Converters/ValueAccessor/DateTimePropertyValueAccessorConverter.cs create mode 100644 Brightcove.DataExchangeFramework/ValueReaders/DateTimePropertyValueReader.cs create mode 100644 Brightcove.DataExchangeFramework/ValueWriters/DateTimePropertyValueWriter.cs create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/9f623c7f-51f5-4091-8645-daad69627e67/Schedule_StartsAt Property.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Data Access/Value Accessor Sets/Providers/Brightcove/Video Model Properties/ItemState Property.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Data Access/Value Accessor Sets/Providers/Brightcove/Video Model Properties/Schedule_EndsAt Property.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Data Access/Value Accessor Sets/Providers/Sitecore/Video Item Fields/EndsAt Field.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Data Access/Value Accessor Sets/Providers/Sitecore/Video Item Fields/StartsAt Field.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Data Access/Value Accessor Sets/Providers/Sitecore/Video Item Fields/State Field.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Data Access/Value Readers/Common/ISO Date Value Reader.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Data Access/Value Readers/Common/ItemState Enum Value Reader.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Value Mapping Sets/Item Source Mapping Sets/Video Item Source Mapping Set/EndsAt Field Mapping.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Value Mapping Sets/Item Source Mapping Sets/Video Item Source Mapping Set/StartsAt Field Mapping.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/Brightcove Tenant/_name/Value Mapping Sets/Item Source Mapping Sets/Video Item Source Mapping Set/State Field Mapping.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/ef1e96bf-0500-4da4-a1ba-9ce1a318eda6/ItemState Property Mapping.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/ef1e96bf-0500-4da4-a1ba-9ce1a318eda6/Schedule_EndsAt Property Mappi.yml create mode 100644 Serialization/Brightcove.Template.Branches.DataExchangeFramework.Framework.Branches/ef1e96bf-0500-4da4-a1ba-9ce1a318eda6/Schedule_StartsAt Property Map.yml create mode 100644 Serialization/Brightcove.Template.DataExchangeFramework/Brightcove/Data Access/Value Accessors/DateTime Property Value Access.yml create mode 100644 Serialization/Brightcove.Template.DataExchangeFramework/Brightcove/Data Access/Value Accessors/DateTime Property Value Access/Property.yml create mode 100644 Serialization/Brightcove.Template.DataExchangeFramework/Brightcove/Data Access/Value Accessors/DateTime Property Value Access/Property/PropertyName.yml create mode 100644 Serialization/Brightcove.Template.DataExchangeFramework/Brightcove/Data Access/Value Accessors/DateTime Property Value Access/__Standard Values.yml rename Serialization/Brightcove.Template.DataExchangeFramework/Brightcove/Folders/{Brightcove Mappings Applied Ac_107f2e15-cdb9-40ab-ac04-9d60999f986a.yml => Brightcove Mappings Applied Ac_0b208341-474a-4ef0-b341-5fd09013b6d0.yml} (76%) rename Serialization/Brightcove.Template.DataExchangeFramework/Brightcove/Folders/{Brightcove Mappings Applied Ac_107f2e15-cdb9-40ab-ac04-9d60999f986a => Brightcove Mappings Applied Ac_0b208341-474a-4ef0-b341-5fd09013b6d0}/__Standard Values.yml (61%) create mode 100644 Serialization/Brightcove.Template/Brightcove/BrightcoveVideo/Scheduling.yml create mode 100644 Serialization/Brightcove.Template/Brightcove/BrightcoveVideo/Scheduling/EndsAt.yml create mode 100644 Serialization/Brightcove.Template/Brightcove/BrightcoveVideo/Scheduling/StartsAt.yml create mode 100644 Serialization/Brightcove.Template/Brightcove/BrightcoveVideo/Scheduling/State.yml diff --git a/Brightcove.Core/Brightcove.Core.csproj b/Brightcove.Core/Brightcove.Core.csproj index 3fe9b48b..f64df6d3 100644 --- a/Brightcove.Core/Brightcove.Core.csproj +++ b/Brightcove.Core/Brightcove.Core.csproj @@ -57,6 +57,7 @@ + diff --git a/Brightcove.Core/EmbedGenerator/BrightcoveEmbedGenerator.cs b/Brightcove.Core/EmbedGenerator/BrightcoveEmbedGenerator.cs index 5c3aa91a..e032f435 100644 --- a/Brightcove.Core/EmbedGenerator/BrightcoveEmbedGenerator.cs +++ b/Brightcove.Core/EmbedGenerator/BrightcoveEmbedGenerator.cs @@ -7,7 +7,7 @@ public class BrightcoveEmbedGenerator { protected string iframeBaseUrl = "https://players.brightcove.net/{0}/{1}_default/index.html?{3}={2}"; protected string iframeTemplate = "
"; - protected string iframeResponsiveTemplate = "
"; + protected string iframeResponsiveTemplate = "

"; protected string jsTemplate = "
{6}
"; protected string jsResponsiveTemplate = "
{6}
"; @@ -91,7 +91,7 @@ protected virtual EmbedMarkup GenerateJavaScript(EmbedModel model) EmbedMarkup result = new EmbedMarkup(); string videoId = ""; string playlistId = ""; - string playlistMarkup = ""; + string innerHtml = ""; string autoplay = ""; string muted = ""; string language = ""; @@ -103,7 +103,7 @@ protected virtual EmbedMarkup GenerateJavaScript(EmbedModel model) break; case MediaType.Playlist: playlistId = model.MediaId; - playlistMarkup = "
"; + innerHtml = "
"; break; default: throw new Exception("Invalid media type for javascript embed"); @@ -126,20 +126,21 @@ protected virtual EmbedMarkup GenerateJavaScript(EmbedModel model) language = $"lang='{model.Language}'"; } + innerHtml += string.Format(jsScriptTemplate, model.AccountId, model.PlayerId); + switch (model.MediaSizing) { case MediaSizing.Responsive: string aspectRatio = ((double)model.Height / model.Width * 100.0).ToString("F2"); - result.Markup = string.Format(jsResponsiveTemplate, model.AccountId, model.PlayerId, videoId, playlistId, model.Width, aspectRatio, playlistMarkup, autoplay, muted, language); + result.Markup = string.Format(jsResponsiveTemplate, model.AccountId, model.PlayerId, videoId, playlistId, model.Width, aspectRatio, innerHtml, autoplay, muted, language); break; case MediaSizing.Fixed: - result.Markup = string.Format(jsTemplate, model.AccountId, model.PlayerId, videoId, playlistId, model.Width, model.Height, playlistMarkup, autoplay, muted, language); + result.Markup = string.Format(jsTemplate, model.AccountId, model.PlayerId, videoId, playlistId, model.Width, model.Height, innerHtml, autoplay, muted, language); break; default: throw new Exception("Invalid media sizing for javascript embed"); } - result.ScriptTag = string.Format(jsScriptTemplate, model.AccountId, model.PlayerId); result.Model = model; return result; diff --git a/Brightcove.Core/EmbedGenerator/Models/EmbedMarkup.cs b/Brightcove.Core/EmbedGenerator/Models/EmbedMarkup.cs index b3864a81..207fa50b 100644 --- a/Brightcove.Core/EmbedGenerator/Models/EmbedMarkup.cs +++ b/Brightcove.Core/EmbedGenerator/Models/EmbedMarkup.cs @@ -11,7 +11,5 @@ public class EmbedMarkup public EmbedModel Model { get; set; } = new EmbedModel(); public string Markup { get; set; } = ""; - - public string ScriptTag { get; set; } = ""; } } diff --git a/Brightcove.Core/Models/Video.cs b/Brightcove.Core/Models/Video.cs index 48c2450b..d1cad2f3 100644 --- a/Brightcove.Core/Models/Video.cs +++ b/Brightcove.Core/Models/Video.cs @@ -59,6 +59,9 @@ public class Video : Asset [JsonIgnore] public bool IngestSuccessful { get; set; } + [JsonProperty("schedule", NullValueHandling = NullValueHandling.Ignore)] + public VideoSchedule Schedule { get; set; } + public Video ShallowCopy() { return (Video)this.MemberwiseClone(); diff --git a/Brightcove.Core/Models/VideoSchedule.cs b/Brightcove.Core/Models/VideoSchedule.cs new file mode 100644 index 00000000..3f6549d0 --- /dev/null +++ b/Brightcove.Core/Models/VideoSchedule.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using System; + +namespace Brightcove.Core.Models +{ + public class VideoSchedule + { + [JsonProperty("starts_at", NullValueHandling = NullValueHandling.Ignore)] + public DateTime? StartsAt { get; set; } + + [JsonProperty("ends_at", NullValueHandling = NullValueHandling.Ignore)] + public DateTime? EndsAt { get; set; } + } +} diff --git a/Brightcove.Core/Services/BrightcoveService.cs b/Brightcove.Core/Services/BrightcoveService.cs index ae40cc67..14b7f4f0 100644 --- a/Brightcove.Core/Services/BrightcoveService.cs +++ b/Brightcove.Core/Services/BrightcoveService.cs @@ -307,7 +307,9 @@ public Video UpdateVideo(Video video) newVideo.Id = null; newVideo.Images = null; - request.Content = new StringContent(JsonConvert.SerializeObject(newVideo), Encoding.UTF8, "application/json"); + string content = JsonConvert.SerializeObject(newVideo); + + request.Content = new StringContent(content, Encoding.UTF8, "application/json"); HttpResponseMessage response = SendRequest(request); diff --git a/Brightcove.DataExchangeFramework/Brightcove.DataExchangeFramework.csproj b/Brightcove.DataExchangeFramework/Brightcove.DataExchangeFramework.csproj index 28d8d7fa..ba1d3ea3 100644 --- a/Brightcove.DataExchangeFramework/Brightcove.DataExchangeFramework.csproj +++ b/Brightcove.DataExchangeFramework/Brightcove.DataExchangeFramework.csproj @@ -426,6 +426,7 @@ + @@ -465,6 +466,8 @@ + + diff --git a/Brightcove.DataExchangeFramework/Converters/ValueAccessor/DateTimePropertyValueAccessorConverter.cs b/Brightcove.DataExchangeFramework/Converters/ValueAccessor/DateTimePropertyValueAccessorConverter.cs new file mode 100644 index 00000000..6a6c26a5 --- /dev/null +++ b/Brightcove.DataExchangeFramework/Converters/ValueAccessor/DateTimePropertyValueAccessorConverter.cs @@ -0,0 +1,49 @@ +using Brightcove.DataExchangeFramework.ValueReaders; +using Brightcove.DataExchangeFramework.ValueWriters; +using Sitecore.DataExchange; +using Sitecore.DataExchange.Attributes; +using Sitecore.DataExchange.Converters.DataAccess.ValueAccessors; +using Sitecore.DataExchange.DataAccess; +using Sitecore.DataExchange.DataAccess.Readers; +using Sitecore.DataExchange.DataAccess.Writers; +using Sitecore.DataExchange.Repositories; +using Sitecore.Services.Core.Model; + +namespace Brightcove.DataExchangeFramework +{ + [SupportedIds(new string[] { "{CC5AC65C-ACAF-4D89-8811-43B2D8E8134A}" })] + public class DateTimePropertyValueAccessorConverter : ValueAccessorConverter + { + public const string FieldNamePropertyName = "PropertyName"; + + public DateTimePropertyValueAccessorConverter(IItemModelRepository repository) + : base(repository) + { + } + + protected override ConvertResult ConvertSupportedItem( + ItemModel source) + { + ConvertResult convertResult = base.ConvertSupportedItem(source); + if (!convertResult.WasConverted) + return convertResult; + string stringValue = this.GetStringValue(source, "PropertyName"); + if (string.IsNullOrWhiteSpace(stringValue)) + return this.NegativeResult(source, "The property name field must have a value specified.", "field: PropertyName"); + IValueAccessor convertedValue = convertResult.ConvertedValue; + if (convertedValue == null) + return this.NegativeResult(source, "A null value accessor was returned by the converter."); + if (convertedValue.ValueReader == null) + { + DateTimePropertyValueReader propertyValueReader = new DateTimePropertyValueReader(stringValue); + convertedValue.ValueReader = (IValueReader)propertyValueReader; + } + if (convertedValue.ValueWriter == null) + { + DateTimePropertyValueWriter propertyValueWriter = new DateTimePropertyValueWriter(stringValue); + convertedValue.ValueWriter = (IValueWriter)propertyValueWriter; + } + return this.PositiveResult(convertedValue); + } + } +} \ No newline at end of file diff --git a/Brightcove.DataExchangeFramework/ValueReaders/DateTimePropertyValueReader.cs b/Brightcove.DataExchangeFramework/ValueReaders/DateTimePropertyValueReader.cs new file mode 100644 index 00000000..6050e05f --- /dev/null +++ b/Brightcove.DataExchangeFramework/ValueReaders/DateTimePropertyValueReader.cs @@ -0,0 +1,44 @@ +using Sitecore.DataExchange.DataAccess; +using Sitecore.DataExchange.DataAccess.Readers; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; +using System.Web; + +namespace Brightcove.DataExchangeFramework.ValueReaders +{ + public class DateTimePropertyValueReader : ChainedPropertyValueReader + { + public DateTimePropertyValueReader(string propertyName) : base(propertyName) + { + } + + public override ReadResult Read(object source, DataAccessContext context) + { + if (context == null) + throw new ArgumentNullException(nameof(context)); + + var result = base.Read(source, context); + + bool wasValueRead = result.WasValueRead; + object obj = result.ReadValue; + + if(obj == null || !(obj is DateTime)) + { + obj = ""; + wasValueRead = true; + } + else + { + obj = ((DateTime)obj).ToString("yyyyMMddTHHmmss\\Z"); + } + + return new ReadResult(DateTime.UtcNow) + { + WasValueRead = wasValueRead, + ReadValue = obj + }; + } + } +} diff --git a/Brightcove.DataExchangeFramework/ValueWriters/DateTimePropertyValueWriter.cs b/Brightcove.DataExchangeFramework/ValueWriters/DateTimePropertyValueWriter.cs new file mode 100644 index 00000000..34e51f09 --- /dev/null +++ b/Brightcove.DataExchangeFramework/ValueWriters/DateTimePropertyValueWriter.cs @@ -0,0 +1,39 @@ +using Sitecore.DataExchange.DataAccess; +using System; +using System.Globalization; + +namespace Brightcove.DataExchangeFramework.ValueWriters +{ + public class DateTimePropertyValueWriter : ChainedPropertyValueWriter + { + public DateTimePropertyValueWriter(string propertyName) : base(propertyName) + { + + } + + public override bool Write(object target, object value, DataAccessContext context) + { + DateTime? returnValue = null; + + try + { + if ((value is string) && !string.IsNullOrWhiteSpace((string)value)) + { + string sourceValue = (string)value; + DateTime tmp; + + if (DateTime.TryParseExact(sourceValue, new string[2] { "yyyyMMddTHHmmss", "yyyyMMddTHHmmss\\Z" }, (IFormatProvider)CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out tmp)) + { + returnValue = tmp; + } + } + } + catch + { + returnValue = null; + } + + return base.Write(target, returnValue, context); + } + } +} \ No newline at end of file diff --git a/Brightcove.Web/EmbedGenerator/SitecoreEmbedGenerator.cs b/Brightcove.Web/EmbedGenerator/SitecoreEmbedGenerator.cs index 6f6d6ded..583d30db 100644 --- a/Brightcove.Web/EmbedGenerator/SitecoreEmbedGenerator.cs +++ b/Brightcove.Web/EmbedGenerator/SitecoreEmbedGenerator.cs @@ -13,6 +13,10 @@ public class SitecoreEmbedGenerator : BrightcoveEmbedGenerator { public SitecoreEmbedGenerator() : base() { + //1) We wrap the iframe in a paragraph tag so that the RTE handles it better + //2) We don't support using a resposive iframe in the RTE + iframeTemplate = "

"; + //1) The RTE does not like the tag and will try to incorrectly HTML encode it so we use standard