Skip to content

Commit 215fc43

Browse files
authored
Merge pull request #16652 from umbraco/v14/feature/merge-2024-06-25
Code changes from V13.4
2 parents 2a57af8 + 9ad67e2 commit 215fc43

30 files changed

+277
-115
lines changed

src/Umbraco.Core/DeliveryApi/ApiMediaUrlProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ public string GetUrl(IPublishedContent media)
1717
throw new ArgumentException("Media URLs can only be generated from Media items.", nameof(media));
1818
}
1919

20-
return _publishedUrlProvider.GetMediaUrl(media, UrlMode.Relative);
20+
return _publishedUrlProvider.GetMediaUrl(media);
2121
}
2222
}

src/Umbraco.Core/Routing/IPublishedRouter.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,37 @@ public interface IPublishedRouter
4747
/// </para>
4848
/// </remarks>
4949
Task<IPublishedRequest> UpdateRequestAsync(IPublishedRequest request, IPublishedContent? publishedContent);
50+
51+
/// <summary>
52+
/// Finds the site root (if any) matching the http request, and updates the PublishedRequest and VariationContext accordingly.
53+
/// <remarks>
54+
/// <para>
55+
/// This method is used for VirtualPage routing.
56+
/// </para>
57+
/// <para>
58+
/// In this case we do not want to run the entire routing pipeline since ContentFinders are not needed here.
59+
/// However, we do want to set the culture on VariationContext and PublishedRequest to the values specified by the domains.
60+
/// </para>
61+
/// </remarks>
62+
/// </summary>
63+
/// <param name="request">The request to update the culture on domain on</param>
64+
/// <returns>True if a domain was found otherwise false.</returns>
65+
bool RouteDomain(IPublishedRequestBuilder request) => false;
66+
67+
/// <summary>
68+
/// Finds the site root (if any) matching the http request, and updates the VariationContext accordingly.
69+
/// </summary>
70+
/// <remarks>
71+
/// <para>
72+
/// This is used for VirtualPage routing.
73+
/// </para>
74+
/// <para>
75+
/// This is required to set the culture on VariationContext to the values specified by the domains, before the FindContent method is called.
76+
/// In order to allow the FindContent implementer to correctly find content based off the culture. Before the PublishedRequest is built.
77+
/// </para>
78+
/// </remarks>
79+
/// <param name="uri">The URI to resolve the domain from.</param>
80+
/// <returns>True if a domain was found, otherwise false.</returns>
81+
bool UpdateVariationContext(Uri uri) => false;
82+
5083
}

src/Umbraco.Core/Routing/PublishedRouter.cs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public async Task<IPublishedRequest> RouteRequestAsync(
108108
// find domain
109109
if (builder.Domain == null)
110110
{
111-
FindDomain(builder);
111+
FindAndSetDomain(builder);
112112
}
113113

114114
await RouteRequestInternalAsync(builder);
@@ -185,7 +185,7 @@ internal IPublishedRequest BuildRequest(IPublishedRequestBuilder builder)
185185

186186
private async Task<IPublishedRequest> TryRouteRequest(IPublishedRequestBuilder request)
187187
{
188-
FindDomain(request);
188+
FindAndSetDomain(request);
189189

190190
if (request.IsRedirect())
191191
{
@@ -270,18 +270,31 @@ private async Task RouteRequestInternalAsync(IPublishedRequestBuilder builder, b
270270
// to find out the appropriate template
271271
}
272272

273-
/// <summary>
274-
/// Finds the site root (if any) matching the http request, and updates the PublishedRequest accordingly.
275-
/// </summary>
276-
/// <returns>A value indicating whether a domain was found.</returns>
277-
internal bool FindDomain(IPublishedRequestBuilder request)
273+
/// <inheritdoc />
274+
public bool RouteDomain(IPublishedRequestBuilder request)
275+
{
276+
var found = FindAndSetDomain(request);
277+
HandleWildcardDomains(request);
278+
SetVariationContext(request.Culture);
279+
return found;
280+
}
281+
282+
/// <inheritdoc />
283+
public bool UpdateVariationContext(Uri uri)
284+
{
285+
DomainAndUri? domain = FindDomain(uri, out _);
286+
SetVariationContext(domain?.Culture);
287+
return domain?.Culture is not null;
288+
}
289+
290+
private DomainAndUri? FindDomain(Uri uri, out string? defaultCulture)
278291
{
279292
const string tracePrefix = "FindDomain: ";
280293

281294
// note - we are not handling schemes nor ports here.
282295
if (_logger.IsEnabled(LogLevel.Debug))
283296
{
284-
_logger.LogDebug("{TracePrefix}Uri={RequestUri}", tracePrefix, request.Uri);
297+
_logger.LogDebug("{TracePrefix}Uri={RequestUri}", tracePrefix, uri);
285298
}
286299

287300
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();
@@ -315,10 +328,20 @@ bool IsPublishedContentDomain(Domain domain)
315328

316329
domains = domains?.Where(IsPublishedContentDomain).ToList();
317330

318-
var defaultCulture = domainsCache?.DefaultCulture;
331+
defaultCulture = domainsCache?.DefaultCulture;
319332

333+
return DomainUtilities.SelectDomain(domains, uri, defaultCulture: defaultCulture);
334+
}
335+
336+
/// <summary>
337+
/// Finds the site root (if any) matching the http request, and updates the PublishedRequest accordingly.
338+
/// </summary>
339+
/// <returns>A value indicating whether a domain was found.</returns>
340+
internal bool FindAndSetDomain(IPublishedRequestBuilder request)
341+
{
342+
const string tracePrefix = "FindDomain: ";
320343
// try to find a domain matching the current request
321-
DomainAndUri? domainAndUri = DomainUtilities.SelectDomain(domains, request.Uri, defaultCulture: defaultCulture);
344+
DomainAndUri? domainAndUri = FindDomain(request.Uri, out var defaultCulture);
322345

323346
// handle domain - always has a contentId and a culture
324347
if (domainAndUri != null)

src/Umbraco.Core/Services/ContentService.cs

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,8 @@ public PublishResult Publish(IContent content, string[] cultures, int userId = C
11401140
throw new ArgumentException("Cultures cannot be null or whitespace", nameof(cultures));
11411141
}
11421142

1143+
EventMessages evtMsgs = EventMessagesFactory.Get();
1144+
11431145
// we need to guard against unsaved changes before proceeding; the content will be saved, but we're not firing any saved notifications
11441146
if (HasUnsavedChanges(content))
11451147
{
@@ -1186,8 +1188,6 @@ public PublishResult Publish(IContent content, string[] cultures, int userId = C
11861188

11871189
var allLangs = _languageRepository.GetMany().ToList();
11881190

1189-
EventMessages evtMsgs = EventMessagesFactory.Get();
1190-
11911191
// this will create the correct culture impact even if culture is * or null
11921192
IEnumerable<CultureImpact?> impacts =
11931193
cultures.Select(culture => _cultureImpactFactory.Create(culture, IsDefaultCulture(allLangs, culture), content));
@@ -1199,7 +1199,15 @@ public PublishResult Publish(IContent content, string[] cultures, int userId = C
11991199
content.PublishCulture(impact);
12001200
}
12011201

1202-
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, userId, out _);
1202+
// Change state to publishing
1203+
content.PublishedState = PublishedState.Publishing;
1204+
var publishingNotification = new ContentPublishingNotification(content, evtMsgs);
1205+
if (scope.Notifications.PublishCancelable(publishingNotification))
1206+
{
1207+
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content);
1208+
}
1209+
1210+
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, publishingNotification.State, userId);
12031211
scope.Complete();
12041212
return result;
12051213
}
@@ -1254,6 +1262,12 @@ public PublishResult Unpublish(IContent content, string? culture = "*", int user
12541262

12551263
var allLangs = _languageRepository.GetMany().ToList();
12561264

1265+
var savingNotification = new ContentSavingNotification(content, evtMsgs);
1266+
if (scope.Notifications.PublishCancelable(savingNotification))
1267+
{
1268+
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content);
1269+
}
1270+
12571271
// all cultures = unpublish whole
12581272
if (culture == "*" || (!content.ContentType.VariesByCulture() && culture == null))
12591273
{
@@ -1262,7 +1276,7 @@ public PublishResult Unpublish(IContent content, string? culture = "*", int user
12621276
// We are however unpublishing all cultures, so we will set this to unpublishing.
12631277
content.UnpublishCulture(culture);
12641278
content.PublishedState = PublishedState.Unpublishing;
1265-
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, userId, out _);
1279+
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, savingNotification.State, userId);
12661280
scope.Complete();
12671281
return result;
12681282
}
@@ -1276,7 +1290,7 @@ public PublishResult Unpublish(IContent content, string? culture = "*", int user
12761290
var removed = content.UnpublishCulture(culture);
12771291

12781292
// Save and publish any changes
1279-
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, userId, out _);
1293+
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, savingNotification.State, userId);
12801294

12811295
scope.Complete();
12821296

@@ -1327,9 +1341,15 @@ internal PublishResult CommitDocumentChanges(IContent content, int userId = Cons
13271341

13281342
scope.WriteLock(Constants.Locks.ContentTree);
13291343

1344+
var savingNotification = new ContentSavingNotification(content, evtMsgs);
1345+
if (scope.Notifications.PublishCancelable(savingNotification))
1346+
{
1347+
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content);
1348+
}
1349+
13301350
var allLangs = _languageRepository.GetMany().ToList();
13311351

1332-
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, userId, out _);
1352+
PublishResult result = CommitDocumentChangesInternal(scope, content, evtMsgs, allLangs, savingNotification.State, userId);
13331353
scope.Complete();
13341354
return result;
13351355
}
@@ -1359,8 +1379,8 @@ private PublishResult CommitDocumentChangesInternal(
13591379
IContent content,
13601380
EventMessages eventMessages,
13611381
IReadOnlyCollection<ILanguage> allLangs,
1382+
IDictionary<string, object?>? notificationState,
13621383
int userId,
1363-
out IDictionary<string, object?>? initialNotificationState,
13641384
bool branchOne = false,
13651385
bool branchRoot = false)
13661386
{
@@ -1422,7 +1442,6 @@ void SaveDocument(IContent c)
14221442
_documentRepository.Save(c);
14231443
}
14241444

1425-
initialNotificationState = null;
14261445
if (publishing)
14271446
{
14281447
// Determine cultures publishing/unpublishing which will be based on previous calls to content.PublishCulture and ClearPublishInfo
@@ -1440,9 +1459,18 @@ void SaveDocument(IContent c)
14401459
culturesUnpublishing,
14411460
eventMessages,
14421461
allLangs,
1443-
out initialNotificationState);
1462+
notificationState);
1463+
14441464
if (publishResult.Success)
14451465
{
1466+
// raise Publishing notification
1467+
if (scope.Notifications.PublishCancelable(
1468+
new ContentPublishingNotification(content, eventMessages).WithState(notificationState)))
1469+
{
1470+
_logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "publishing was cancelled");
1471+
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, eventMessages, content);
1472+
}
1473+
14461474
// note: StrategyPublish flips the PublishedState to Publishing!
14471475
publishResult = StrategyPublish(content, culturesPublishing, culturesUnpublishing, eventMessages);
14481476

@@ -1503,7 +1531,7 @@ void SaveDocument(IContent c)
15031531
// handling events, business rules, etc
15041532
// note: StrategyUnpublish flips the PublishedState to Unpublishing!
15051533
// note: This unpublishes the entire document (not different variants)
1506-
unpublishResult = StrategyCanUnpublish(scope, content, eventMessages, out initialNotificationState);
1534+
unpublishResult = StrategyCanUnpublish(scope, content, eventMessages, notificationState);
15071535
if (unpublishResult.Success)
15081536
{
15091537
unpublishResult = StrategyUnpublish(content, eventMessages);
@@ -1539,7 +1567,7 @@ void SaveDocument(IContent c)
15391567
{
15401568
// events and audit
15411569
scope.Notifications.Publish(
1542-
new ContentUnpublishedNotification(content, eventMessages).WithState(initialNotificationState));
1570+
new ContentUnpublishedNotification(content, eventMessages).WithState(notificationState));
15431571
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshBranch, eventMessages));
15441572

15451573
if (culturesUnpublishing != null)
@@ -1601,7 +1629,7 @@ void SaveDocument(IContent c)
16011629
scope.Notifications.Publish(
16021630
new ContentTreeChangeNotification(content, changeType, eventMessages));
16031631
scope.Notifications.Publish(
1604-
new ContentPublishedNotification(content, eventMessages).WithState(initialNotificationState));
1632+
new ContentPublishedNotification(content, eventMessages).WithState(notificationState));
16051633
}
16061634

16071635
// it was not published and now is... descendants that were 'published' (but
@@ -1611,7 +1639,7 @@ void SaveDocument(IContent c)
16111639
{
16121640
IContent[] descendants = GetPublishedDescendantsLocked(content).ToArray();
16131641
scope.Notifications.Publish(
1614-
new ContentPublishedNotification(descendants, eventMessages).WithState(initialNotificationState));
1642+
new ContentPublishedNotification(descendants, eventMessages).WithState(notificationState));
16151643
}
16161644

16171645
switch (publishResult.Result)
@@ -1711,6 +1739,13 @@ private void PerformScheduledPublishingExpiration(DateTime date, List<PublishRes
17111739
continue; // shouldn't happen but no point in processing this document if there's nothing there
17121740
}
17131741

1742+
var savingNotification = new ContentSavingNotification(d, evtMsgs);
1743+
if (scope.Notifications.PublishCancelable(savingNotification))
1744+
{
1745+
results.Add(new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, d));
1746+
continue;
1747+
}
1748+
17141749
foreach (var c in pendingCultures)
17151750
{
17161751
// Clear this schedule for this culture
@@ -1721,7 +1756,7 @@ private void PerformScheduledPublishingExpiration(DateTime date, List<PublishRes
17211756
}
17221757

17231758
_documentRepository.PersistContentSchedule(d, contentSchedule);
1724-
PublishResult result = CommitDocumentChangesInternal(scope, d, evtMsgs, allLangs.Value, d.WriterId, out _);
1759+
PublishResult result = CommitDocumentChangesInternal(scope, d, evtMsgs, allLangs.Value, savingNotification.State, d.WriterId);
17251760
if (result.Success == false)
17261761
{
17271762
_logger.LogError(null, "Failed to publish document id={DocumentId}, reason={Reason}.", d.Id, result.Result);
@@ -1775,6 +1810,13 @@ private void PerformScheduledPublishingRelease(DateTime date, List<PublishResult
17751810
{
17761811
continue; // shouldn't happen but no point in processing this document if there's nothing there
17771812
}
1813+
var savingNotification = new ContentSavingNotification(d, evtMsgs);
1814+
if (scope.Notifications.PublishCancelable(savingNotification))
1815+
{
1816+
results.Add(new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, d));
1817+
continue;
1818+
}
1819+
17781820

17791821
var publishing = true;
17801822
foreach (var culture in pendingCultures)
@@ -1820,7 +1862,7 @@ private void PerformScheduledPublishingRelease(DateTime date, List<PublishResult
18201862
else
18211863
{
18221864
_documentRepository.PersistContentSchedule(d, contentSchedule);
1823-
result = CommitDocumentChangesInternal(scope, d, evtMsgs, allLangs.Value, d.WriterId, out _);
1865+
result = CommitDocumentChangesInternal(scope, d, evtMsgs, allLangs.Value, savingNotification.State, d.WriterId);
18241866
}
18251867

18261868
if (result.Success == false)
@@ -2162,14 +2204,20 @@ internal IEnumerable<PublishResult> PublishBranch(
21622204
return new PublishResult(PublishResultType.SuccessPublishAlready, evtMsgs, document);
21632205
}
21642206

2207+
var savingNotification = new ContentSavingNotification(document, evtMsgs);
2208+
if (scope.Notifications.PublishCancelable(savingNotification))
2209+
{
2210+
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, document);
2211+
}
2212+
21652213
// publish & check if values are valid
21662214
if (!publishCultures(document, culturesToPublish, allLangs))
21672215
{
21682216
// TODO: Based on this callback behavior there is no way to know which properties may have been invalid if this failed, see other results of FailedPublishContentInvalid
21692217
return new PublishResult(PublishResultType.FailedPublishContentInvalid, evtMsgs, document);
21702218
}
21712219

2172-
PublishResult result = CommitDocumentChangesInternal(scope, document, evtMsgs, allLangs, userId, out initialNotificationState, true, isRoot);
2220+
PublishResult result = CommitDocumentChangesInternal(scope, document, evtMsgs, allLangs, savingNotification.State, userId, true, isRoot);
21732221
if (result.Success)
21742222
{
21752223
publishedDocuments.Add(document);
@@ -3018,19 +3066,8 @@ private PublishResult StrategyCanPublish(
30183066
IReadOnlyCollection<string>? culturesUnpublishing,
30193067
EventMessages evtMsgs,
30203068
IReadOnlyCollection<ILanguage> allLangs,
3021-
out IDictionary<string, object?>? initialNotificationState)
3069+
IDictionary<string, object?>? notificationState)
30223070
{
3023-
// raise Publishing notification
3024-
var notification = new ContentPublishingNotification(content, evtMsgs);
3025-
var notificationResult = scope.Notifications.PublishCancelable(notification);
3026-
initialNotificationState = notification.State;
3027-
3028-
if (notificationResult)
3029-
{
3030-
_logger.LogInformation("Document {ContentName} (id={ContentId}) cannot be published: {Reason}", content.Name, content.Id, "publishing was cancelled");
3031-
return new PublishResult(PublishResultType.FailedPublishCancelledByEvent, evtMsgs, content);
3032-
}
3033-
30343071
var variesByCulture = content.ContentType.VariesByCulture();
30353072

30363073
// If it's null it's invariant
@@ -3268,12 +3305,11 @@ private PublishResult StrategyCanUnpublish(
32683305
ICoreScope scope,
32693306
IContent content,
32703307
EventMessages evtMsgs,
3271-
out IDictionary<string, object?>? initialNotificationState)
3308+
IDictionary<string, object?>? notificationState)
32723309
{
32733310
// raise Unpublishing notification
3274-
var notification = new ContentUnpublishingNotification(content, evtMsgs);
3311+
var notification = new ContentUnpublishingNotification(content, evtMsgs).WithState(notificationState);
32753312
var notificationResult = scope.Notifications.PublishCancelable(notification);
3276-
initialNotificationState = notification.State;
32773313

32783314
if (notificationResult)
32793315
{

0 commit comments

Comments
 (0)