From fe9d33e489033d8040c63b146d8531153b643707 Mon Sep 17 00:00:00 2001 From: Levi Zitting Date: Thu, 20 Aug 2026 21:12:54 -0500 Subject: [PATCH 1/2] fix: avoid redundant session imports --- .../ImportedPresenterBlockBuilderTests.cs | 15 +++++++++ .../ImportedPresenterBlockBuilder.cs | 21 +++++++++++- .../EventSync/SessionizeEventSyncService.cs | 32 ++++++++----------- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs b/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs index b293ebd..b4efbc6 100644 --- a/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs +++ b/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs @@ -45,4 +45,19 @@ public void Build_CreatesBlockListPayloadForNonMemberPresenters() Assert.Equal("Dinesh Chugtai", secondValues[0].GetProperty("value").GetString()); Assert.Equal(string.Empty, secondValues[1].GetProperty("value").GetString()); } + + [Fact] + public void Build_ReturnsSamePayloadForSamePresenters() + { + var presenters = new[] + { + new ImportedPresenterPlan("speaker-1", "Bertram Gilfoyle", null, MatchedMemberKey: new Guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")), + new ImportedPresenterPlan("speaker-2", "Dinesh Chugtai", null) + }; + + var first = _builder.Build(presenters); + var second = _builder.Build(presenters); + + Assert.Equal(first, second); + } } diff --git a/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs b/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs index 6b0ac72..eeaaf7d 100644 --- a/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs +++ b/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs @@ -2,6 +2,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Security.Cryptography; +using System.Text; using System.Text.Json; using SgfDevs.Dev.EventSync.Sessionize; using Umbraco.Cms.Core; @@ -45,7 +47,7 @@ public string Build(IReadOnlyList presenters) var blocks = presenters.Select(presenter => { - var key = Guid.NewGuid(); + var key = BuildBlockKey(presenter); var isMatchedMember = presenter.MatchedMemberKey.HasValue; return new @@ -114,4 +116,21 @@ public string Build(IReadOnlyList presenters) return JsonSerializer.Serialize(payload); } + + private static Guid BuildBlockKey(ImportedPresenterPlan presenter) + { + if (presenter.MatchedMemberKey.HasValue) + { + return presenter.MatchedMemberKey.Value; + } + + if (Guid.TryParse(presenter.SessionizeSpeakerId, out var sessionizeSpeakerKey)) + { + return sessionizeSpeakerKey; + } + + var identity = $"{presenter.SessionizeSpeakerId}\n{presenter.Name}"; + var hash = SHA256.HashData(Encoding.UTF8.GetBytes(identity)); + return new Guid(hash.AsSpan(0, 16)); + } } diff --git a/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs b/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs index 95e72b5..c79ba93 100644 --- a/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs +++ b/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs @@ -112,8 +112,7 @@ public async Task SyncAsync(CancellationToken cancellationToken = default) var eventContent = GetOrCreateEvent(existingEvents, references.EventsContainerId, eventPlan); SaveEventContent(eventContent, eventPlan); - _contentService.Save(eventContent, SystemUserId); - var presentationsToPublish = new List(); + SaveAndPublishContent(eventContent, "event", clearSchedule: true); var existingPresentations = GetChildren(eventContent.Id) .Where(content => string.Equals(content.ContentType.Alias, PresentationAlias, StringComparison.Ordinal)) @@ -136,14 +135,7 @@ public async Task SyncAsync(CancellationToken cancellationToken = default) var presentationContent = GetOrCreatePresentation(existingPresentations, eventContent.Id, presentationPlan); SavePresentationContent(presentationContent, references.SpringfieldDevsGroupKey, enrichedPresentationPlan, meetupMatch?.EventUrl); - _contentService.Save(presentationContent, SystemUserId); - presentationsToPublish.Add(presentationContent); - } - - PublishContent(eventContent, "event", clearSchedule: true); - foreach (var presentationContent in presentationsToPublish) - { - PublishContent(presentationContent, "presentation"); + SaveAndPublishContent(presentationContent, "presentation"); } } } @@ -262,29 +254,31 @@ private async Task> ImportPresenterImagesAs return enrichedPresenters; } - private void PublishContent(IContent content, string contentKind, bool clearSchedule = false) + private void SaveAndPublishContent(IContent content, string contentKind, bool clearSchedule = false) { - if (clearSchedule) + if (content.IsDirty() == false && content.IsCultureEdited(null!) == false) + { + return; + } + + if (clearSchedule && content.HasIdentity) { _contentService.PersistContentSchedule(content, new ContentScheduleCollection()); } - var publishResult = _contentService.Publish(content, ["*"], SystemUserId); + var publishResult = _contentService.SaveAndPublish(content, [], SystemUserId); if (publishResult.Success) { _logger.LogInformation( - "Published {ContentKind} {ContentName} with result {PublishResult}.", + "Saved and published {ContentKind} {ContentName} with result {PublishResult}.", contentKind, content.Name, publishResult.Result); return; } - _logger.LogWarning( - "Failed to publish {ContentKind} {ContentName}. Publish result was {PublishResult}.", - contentKind, - content.Name, - publishResult.Result); + throw new InvalidOperationException( + $"Failed to save and publish {contentKind} {content.Name}. Publish result was {publishResult.Result}."); } private IReadOnlyList GetChildren(int parentId) From e801d1ac35b956f26c167a14619710b7d270d239 Mon Sep 17 00:00:00 2001 From: Levi Zitting Date: Thu, 20 Aug 2026 21:15:46 -0500 Subject: [PATCH 2/2] fix: scope presenter blocks to presentations --- .../ImportedPresenterBlockBuilderTests.cs | 37 +++++++++++++++---- .../ImportedPresenterBlockBuilder.cs | 20 +++------- .../EventSync/SessionizeEventSyncService.cs | 2 +- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs b/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs index b4efbc6..f027ffc 100644 --- a/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs +++ b/SgfDevs.Tests/ImportedPresenterBlockBuilderTests.cs @@ -8,6 +8,8 @@ namespace SgfDevs.Tests; public class ImportedPresenterBlockBuilderTests { + private static readonly Guid PresentationKey = new("11111111-1111-1111-1111-111111111111"); + private readonly ImportedPresenterBlockBuilder _builder = new( new Guid("1bdea08d-8393-4e70-85a9-2ca27bef54f1"), new Guid("5ff3a2c3-9dc3-4131-8f07-99c2c0a38be5")); @@ -15,7 +17,7 @@ public class ImportedPresenterBlockBuilderTests [Fact] public void Build_ReturnsEmptyStringWhenNoPresentersExist() { - var result = _builder.Build([]); + var result = _builder.Build(PresentationKey, []); Assert.Equal(string.Empty, result); } @@ -24,10 +26,11 @@ public void Build_ReturnsEmptyStringWhenNoPresentersExist() public void Build_CreatesBlockListPayloadForNonMemberPresenters() { var result = _builder.Build( - [ - new ImportedPresenterPlan("speaker-1", "Bertram Gilfoyle", null, MatchedMemberKey: new Guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")), - new ImportedPresenterPlan("speaker-2", "Dinesh Chugtai", null) - ]); + PresentationKey, + [ + new ImportedPresenterPlan("speaker-1", "Bertram Gilfoyle", null, MatchedMemberKey: new Guid("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")), + new ImportedPresenterPlan("speaker-2", "Dinesh Chugtai", null) + ]); using var document = JsonDocument.Parse(result); var root = document.RootElement; @@ -55,9 +58,29 @@ public void Build_ReturnsSamePayloadForSamePresenters() new ImportedPresenterPlan("speaker-2", "Dinesh Chugtai", null) }; - var first = _builder.Build(presenters); - var second = _builder.Build(presenters); + var first = _builder.Build(PresentationKey, presenters); + var second = _builder.Build(PresentationKey, presenters); Assert.Equal(first, second); } + + [Fact] + public void Build_ReturnsDifferentBlockKeysForDifferentPresentations() + { + var presenters = new[] + { + new ImportedPresenterPlan("speaker-1", "Bertram Gilfoyle", null) + }; + + var first = GetFirstBlockKey(_builder.Build(PresentationKey, presenters)); + var second = GetFirstBlockKey(_builder.Build(new Guid("22222222-2222-2222-2222-222222222222"), presenters)); + + Assert.NotEqual(first, second); + } + + private static Guid GetFirstBlockKey(string payload) + { + using var document = JsonDocument.Parse(payload); + return document.RootElement.GetProperty("contentData")[0].GetProperty("key").GetGuid(); + } } diff --git a/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs b/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs index eeaaf7d..414ab8f 100644 --- a/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs +++ b/SgfDevs/Dev/EventSync/ImportedPresenterBlockBuilder.cs @@ -31,7 +31,7 @@ internal ImportedPresenterBlockBuilder(Guid presenterPickerTypeKey, Guid nonMemb _nonMemberPresenterTypeKey = nonMemberPresenterTypeKey; } - public string Build(IReadOnlyList presenters) + public string Build(Guid presentationKey, IReadOnlyList presenters) { if (presenters.Count == 0) { @@ -47,7 +47,7 @@ public string Build(IReadOnlyList presenters) var blocks = presenters.Select(presenter => { - var key = BuildBlockKey(presenter); + var key = BuildBlockKey(presentationKey, presenter); var isMatchedMember = presenter.MatchedMemberKey.HasValue; return new @@ -117,19 +117,11 @@ public string Build(IReadOnlyList presenters) return JsonSerializer.Serialize(payload); } - private static Guid BuildBlockKey(ImportedPresenterPlan presenter) + private static Guid BuildBlockKey(Guid presentationKey, ImportedPresenterPlan presenter) { - if (presenter.MatchedMemberKey.HasValue) - { - return presenter.MatchedMemberKey.Value; - } - - if (Guid.TryParse(presenter.SessionizeSpeakerId, out var sessionizeSpeakerKey)) - { - return sessionizeSpeakerKey; - } - - var identity = $"{presenter.SessionizeSpeakerId}\n{presenter.Name}"; + var presenterIdentity = presenter.MatchedMemberKey?.ToString("N") + ?? (string.IsNullOrWhiteSpace(presenter.SessionizeSpeakerId) ? presenter.Name : presenter.SessionizeSpeakerId); + var identity = $"{presentationKey:N}\n{presenterIdentity}"; var hash = SHA256.HashData(Encoding.UTF8.GetBytes(identity)); return new Guid(hash.AsSpan(0, 16)); } diff --git a/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs b/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs index c79ba93..1a4676c 100644 --- a/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs +++ b/SgfDevs/Dev/EventSync/SessionizeEventSyncService.cs @@ -222,7 +222,7 @@ private void SavePresentationContent( presentationContent.SetValue(MeetupUrlPropertyAlias, meetupUrl); } - presentationContent.SetValue(PresentersPropertyAlias, _presenterBlockBuilder.Build(presentationPlan.Presenters)); + presentationContent.SetValue(PresentersPropertyAlias, _presenterBlockBuilder.Build(presentationContent.Key, presentationPlan.Presenters)); } private async Task> ImportPresenterImagesAsync(