Migrate TreeChanged to notification in ContentService
This commit is contained in:
@@ -44,7 +44,8 @@ namespace Umbraco.Cms.Core.Cache
|
||||
INotificationHandler<DomainSavedNotification>,
|
||||
INotificationHandler<MacroSavedNotification>,
|
||||
INotificationHandler<MacroDeletedNotification>,
|
||||
INotificationHandler<MediaTreeChangeNotification>
|
||||
INotificationHandler<MediaTreeChangeNotification>,
|
||||
INotificationHandler<ContentTreeChangeNotification>
|
||||
{
|
||||
private List<Action> _unbinders;
|
||||
|
||||
@@ -83,10 +84,6 @@ namespace Umbraco.Cms.Core.Cache
|
||||
Bind(() => MemberTypeService.Changed += MemberTypeService_Changed,
|
||||
() => MemberTypeService.Changed -= MemberTypeService_Changed);
|
||||
|
||||
// bind to content events
|
||||
Bind(() => ContentService.TreeChanged += ContentService_TreeChanged,// handles all content changes
|
||||
() => ContentService.TreeChanged -= ContentService_TreeChanged);
|
||||
|
||||
// TreeChanged should also deal with this
|
||||
//Bind(() => ContentService.SavedBlueprint += ContentService_SavedBlueprint,
|
||||
// () => ContentService.SavedBlueprint -= ContentService_SavedBlueprint);
|
||||
@@ -124,9 +121,10 @@ namespace Umbraco.Cms.Core.Cache
|
||||
{
|
||||
}
|
||||
|
||||
private void ContentService_TreeChanged(IContentService sender, TreeChange<IContent>.EventArgs args)
|
||||
|
||||
public void Handle(ContentTreeChangeNotification notification)
|
||||
{
|
||||
_distributedCache.RefreshContentCache(args.Changes.ToArray());
|
||||
_distributedCache.RefreshContentCache(notification.Changes.ToArray());
|
||||
}
|
||||
|
||||
//private void ContentService_SavedBlueprint(IContentService sender, SaveEventArgs<IContent> e)
|
||||
|
||||
@@ -90,6 +90,7 @@ namespace Umbraco.Cms.Core.Compose
|
||||
.AddNotificationHandler<MacroSavedNotification, DistributedCacheBinder>()
|
||||
.AddNotificationHandler<MacroDeletedNotification, DistributedCacheBinder>()
|
||||
.AddNotificationHandler<MediaTreeChangeNotification, DistributedCacheBinder>()
|
||||
.AddNotificationHandler<ContentTreeChangeNotification, DistributedCacheBinder>()
|
||||
;
|
||||
// add notification handlers for auditing
|
||||
builder
|
||||
|
||||
@@ -735,34 +735,39 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <inheritdoc />
|
||||
public OperationResult Save(IContent content, int userId = Cms.Core.Constants.Security.SuperUserId, bool raiseEvents = true)
|
||||
{
|
||||
var publishedState = content.PublishedState;
|
||||
PublishedState publishedState = content.PublishedState;
|
||||
if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot save (un)publishing content with name: {content.Name} - and state: {content.PublishedState}, use the dedicated SavePublished method.");
|
||||
}
|
||||
|
||||
if (content.Name != null && content.Name.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException($"Content with the name {content.Name} cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var savingNotification = new ContentSavingNotification(content, evtMsgs);
|
||||
var savingNotification = new ContentSavingNotification(content, eventMessages);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Cancel(evtMsgs);
|
||||
return OperationResult.Cancel(eventMessages);
|
||||
}
|
||||
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
|
||||
if (content.HasIdentity == false)
|
||||
{
|
||||
content.CreatorId = userId;
|
||||
}
|
||||
|
||||
content.WriterId = userId;
|
||||
|
||||
//track the cultures that have changed
|
||||
var culturesChanging = content.ContentType.VariesByCulture()
|
||||
List<string> culturesChanging = content.ContentType.VariesByCulture()
|
||||
? content.CultureInfos.Values.Where(x => x.IsDirty()).Select(x => x.Culture).ToList()
|
||||
: null;
|
||||
// TODO: Currently there's no way to change track which variant properties have changed, we only have change
|
||||
@@ -774,10 +779,9 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
scope.Notifications.Publish(new ContentSavedNotification(content, evtMsgs).WithStateFrom(savingNotification));
|
||||
scope.Notifications.Publish(new ContentSavedNotification(content, eventMessages).WithStateFrom(savingNotification));
|
||||
}
|
||||
var changeType = TreeChangeTypes.RefreshNode;
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, changeType).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshNode, eventMessages));
|
||||
|
||||
if (culturesChanging != null)
|
||||
{
|
||||
@@ -792,31 +796,32 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
return OperationResult.Succeed(evtMsgs);
|
||||
return OperationResult.Succeed(eventMessages);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public OperationResult Save(IEnumerable<IContent> contents, int userId = Cms.Core.Constants.Security.SuperUserId, bool raiseEvents = true)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var contentsA = contents.ToArray();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
IContent[] contentsA = contents.ToArray();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var savingNotification = new ContentSavingNotification(contentsA, evtMsgs);
|
||||
var savingNotification = new ContentSavingNotification(contentsA, eventMessages);
|
||||
if (raiseEvents && scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Cancel(evtMsgs);
|
||||
return OperationResult.Cancel(eventMessages);
|
||||
}
|
||||
|
||||
var treeChanges = contentsA.Select(x => new TreeChange<IContent>(x, TreeChangeTypes.RefreshNode));
|
||||
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
foreach (var content in contentsA)
|
||||
foreach (IContent content in contentsA)
|
||||
{
|
||||
if (content.HasIdentity == false)
|
||||
{
|
||||
content.CreatorId = userId;
|
||||
}
|
||||
|
||||
content.WriterId = userId;
|
||||
|
||||
_documentRepository.Save(content);
|
||||
@@ -824,15 +829,15 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
if (raiseEvents)
|
||||
{
|
||||
scope.Notifications.Publish(new ContentSavedNotification(contentsA, evtMsgs).WithStateFrom(savingNotification));
|
||||
scope.Notifications.Publish(new ContentSavedNotification(contentsA, eventMessages).WithStateFrom(savingNotification));
|
||||
}
|
||||
scope.Events.Dispatch(TreeChanged, this, treeChanges.ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(contentsA, TreeChangeTypes.RefreshNode, eventMessages));
|
||||
Audit(AuditType.Save, userId == -1 ? 0 : userId, Cms.Core.Constants.System.Root, "Saved multiple content");
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
return OperationResult.Succeed(evtMsgs);
|
||||
return OperationResult.Succeed(eventMessages);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1066,11 +1071,13 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// </summary>
|
||||
/// <param name="scope"></param>
|
||||
/// <param name="content"></param>
|
||||
/// <param name="allLangs"></param>
|
||||
/// <param name="notificationState"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="raiseEvents"></param>
|
||||
/// <param name="branchOne"></param>
|
||||
/// <param name="branchRoot"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
@@ -1079,21 +1086,34 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
private PublishResult CommitDocumentChangesInternal(IScope scope, IContent content,
|
||||
EventMessages evtMsgs, IReadOnlyCollection<ILanguage> allLangs,
|
||||
EventMessages eventMessages, IReadOnlyCollection<ILanguage> allLangs,
|
||||
IDictionary<string, object> notificationState,
|
||||
int userId = Cms.Core.Constants.Security.SuperUserId,
|
||||
bool raiseEvents = true, bool branchOne = false, bool branchRoot = false)
|
||||
{
|
||||
if (scope == null) throw new ArgumentNullException(nameof(scope));
|
||||
if (content == null) throw new ArgumentNullException(nameof(content));
|
||||
if (evtMsgs == null) throw new ArgumentNullException(nameof(evtMsgs));
|
||||
if (scope == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(scope));
|
||||
}
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
if (eventMessages == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(eventMessages));
|
||||
}
|
||||
|
||||
PublishResult publishResult = null;
|
||||
PublishResult unpublishResult = null;
|
||||
|
||||
// nothing set = republish it all
|
||||
if (content.PublishedState != PublishedState.Publishing && content.PublishedState != PublishedState.Unpublishing)
|
||||
{
|
||||
content.PublishedState = PublishedState.Publishing;
|
||||
}
|
||||
|
||||
// State here is either Publishing or Unpublishing
|
||||
// Publishing to unpublish a culture may end up unpublishing everything so these flags can be flipped later
|
||||
@@ -1110,7 +1130,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
: null;
|
||||
|
||||
var isNew = !content.HasIdentity;
|
||||
var changeType = isNew ? TreeChangeTypes.RefreshNode : TreeChangeTypes.RefreshBranch;
|
||||
TreeChangeTypes changeType = isNew ? TreeChangeTypes.RefreshNode : TreeChangeTypes.RefreshBranch;
|
||||
var previouslyPublished = content.HasIdentity && content.Published;
|
||||
|
||||
//inline method to persist the document with the documentRepository since this logic could be called a couple times below
|
||||
@@ -1118,7 +1138,10 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
// save, always
|
||||
if (c.HasIdentity == false)
|
||||
{
|
||||
c.CreatorId = userId;
|
||||
}
|
||||
|
||||
c.WriterId = userId;
|
||||
|
||||
// saving does NOT change the published version, unless PublishedState is Publishing or Unpublishing
|
||||
@@ -1134,11 +1157,11 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
: null;
|
||||
|
||||
// ensure that the document can be published, and publish handling events, business rules, etc
|
||||
publishResult = StrategyCanPublish(scope, content, /*checkPath:*/ (!branchOne || branchRoot), culturesPublishing, culturesUnpublishing, evtMsgs, allLangs, notificationState);
|
||||
publishResult = StrategyCanPublish(scope, content, /*checkPath:*/ (!branchOne || branchRoot), culturesPublishing, culturesUnpublishing, eventMessages, allLangs, notificationState);
|
||||
if (publishResult.Success)
|
||||
{
|
||||
// note: StrategyPublish flips the PublishedState to Publishing!
|
||||
publishResult = StrategyPublish(content, culturesPublishing, culturesUnpublishing, evtMsgs);
|
||||
publishResult = StrategyPublish(content, culturesPublishing, culturesUnpublishing, eventMessages);
|
||||
|
||||
//check if a culture has been unpublished and if there are no cultures left, and then unpublish document as a whole
|
||||
if (publishResult.Result == PublishResultType.SuccessUnpublishCulture && content.PublishCultureInfos.Count == 0)
|
||||
@@ -1158,7 +1181,9 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
{
|
||||
// in a branch, just give up
|
||||
if (branchOne && !branchRoot)
|
||||
{
|
||||
return publishResult;
|
||||
}
|
||||
|
||||
//check for mandatory culture missing, and then unpublish document as a whole
|
||||
if (publishResult.Result == PublishResultType.FailedPublishMandatoryCultureMissing)
|
||||
@@ -1181,9 +1206,11 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
if (unpublishing) // won't happen in a branch
|
||||
{
|
||||
var newest = GetById(content.Id); // ensure we have the newest version - in scope
|
||||
IContent newest = GetById(content.Id); // ensure we have the newest version - in scope
|
||||
if (content.VersionId != newest.VersionId)
|
||||
return new PublishResult(PublishResultType.FailedPublishConcurrencyViolation, evtMsgs, content);
|
||||
{
|
||||
return new PublishResult(PublishResultType.FailedPublishConcurrencyViolation, eventMessages, content);
|
||||
}
|
||||
|
||||
if (content.Published)
|
||||
{
|
||||
@@ -1191,9 +1218,11 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// handling events, business rules, etc
|
||||
// note: StrategyUnpublish flips the PublishedState to Unpublishing!
|
||||
// note: This unpublishes the entire document (not different variants)
|
||||
unpublishResult = StrategyCanUnpublish(scope, content, evtMsgs);
|
||||
unpublishResult = StrategyCanUnpublish(scope, content, eventMessages);
|
||||
if (unpublishResult.Success)
|
||||
unpublishResult = StrategyUnpublish(content, evtMsgs);
|
||||
{
|
||||
unpublishResult = StrategyUnpublish(content, eventMessages);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset published state from temp values (publishing, unpublishing) to original value
|
||||
@@ -1219,7 +1248,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// raise the Saved event, always
|
||||
if (raiseEvents)
|
||||
{
|
||||
scope.Notifications.Publish(new ContentSavedNotification(content, evtMsgs).WithState(notificationState));
|
||||
scope.Notifications.Publish(new ContentSavedNotification(content, eventMessages).WithState(notificationState));
|
||||
}
|
||||
|
||||
if (unpublishing) // we have tried to unpublish - won't happen in a branch
|
||||
@@ -1227,8 +1256,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
if (unpublishResult.Success) // and succeeded, trigger events
|
||||
{
|
||||
// events and audit
|
||||
scope.Notifications.Publish(new ContentUnpublishedNotification(content, evtMsgs).WithState(notificationState));
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.RefreshBranch).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentUnpublishedNotification(content, eventMessages).WithState(notificationState));
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshBranch, eventMessages));
|
||||
|
||||
if (culturesUnpublishing != null)
|
||||
{
|
||||
@@ -1249,23 +1278,23 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
//log that the whole content item has been unpublished due to mandatory culture unpublished
|
||||
Audit(AuditType.Unpublish, userId, content.Id, "Unpublished (mandatory language unpublished)");
|
||||
return new PublishResult(PublishResultType.SuccessUnpublishMandatoryCulture, evtMsgs, content);
|
||||
return new PublishResult(PublishResultType.SuccessUnpublishMandatoryCulture, eventMessages, content);
|
||||
case PublishResultType.SuccessUnpublishCulture:
|
||||
//occurs when the last culture is unpublished
|
||||
|
||||
Audit(AuditType.Unpublish, userId, content.Id, "Unpublished (last language unpublished)");
|
||||
return new PublishResult(PublishResultType.SuccessUnpublishLastCulture, evtMsgs, content);
|
||||
return new PublishResult(PublishResultType.SuccessUnpublishLastCulture, eventMessages, content);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Audit(AuditType.Unpublish, userId, content.Id);
|
||||
return new PublishResult(PublishResultType.SuccessUnpublish, evtMsgs, content);
|
||||
return new PublishResult(PublishResultType.SuccessUnpublish, eventMessages, content);
|
||||
}
|
||||
|
||||
// or, failed
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, changeType).ToEventArgs());
|
||||
return new PublishResult(PublishResultType.FailedUnpublish, evtMsgs, content); // bah
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, changeType, eventMessages));
|
||||
return new PublishResult(PublishResultType.FailedUnpublish, eventMessages, content); // bah
|
||||
}
|
||||
|
||||
if (publishing) // we have tried to publish
|
||||
@@ -1273,16 +1302,20 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
if (publishResult.Success) // and succeeded, trigger events
|
||||
{
|
||||
if (isNew == false && previouslyPublished == false)
|
||||
{
|
||||
changeType = TreeChangeTypes.RefreshBranch; // whole branch
|
||||
}
|
||||
else if (isNew == false && previouslyPublished)
|
||||
{
|
||||
changeType = TreeChangeTypes.RefreshNode; // single node
|
||||
}
|
||||
|
||||
|
||||
// invalidate the node/branch
|
||||
if (!branchOne) // for branches, handled by SaveAndPublishBranch
|
||||
{
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, changeType).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(content, evtMsgs).WithState(notificationState));
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, changeType, eventMessages));
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(content, eventMessages).WithState(notificationState));
|
||||
}
|
||||
|
||||
// it was not published and now is... descendants that were 'published' (but
|
||||
@@ -1290,8 +1323,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// but back as 'published' nevertheless
|
||||
if (!branchOne && isNew == false && previouslyPublished == false && HasChildren(content.Id))
|
||||
{
|
||||
var descendants = GetPublishedDescendantsLocked(content).ToArray();
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(descendants, evtMsgs).WithState(notificationState));
|
||||
IContent[] descendants = GetPublishedDescendantsLocked(content).ToArray();
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(descendants, eventMessages).WithState(notificationState));
|
||||
}
|
||||
|
||||
switch (publishResult.Result)
|
||||
@@ -1325,7 +1358,9 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
// should not happen
|
||||
if (branchOne && !branchRoot)
|
||||
{
|
||||
throw new PanicException("branchOne && !branchRoot - should not happen");
|
||||
}
|
||||
|
||||
//if publishing didn't happen or if it has failed, we still need to log which cultures were saved
|
||||
if (!branchOne && (publishResult == null || !publishResult.Success))
|
||||
@@ -1344,7 +1379,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
}
|
||||
|
||||
// or, failed
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, changeType).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, changeType, eventMessages));
|
||||
return publishResult;
|
||||
}
|
||||
|
||||
@@ -1632,32 +1667,46 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
Func<IContent, HashSet<string>, IReadOnlyCollection<ILanguage>, bool> publishCultures,
|
||||
int userId = Cms.Core.Constants.Security.SuperUserId)
|
||||
{
|
||||
if (shouldPublish == null) throw new ArgumentNullException(nameof(shouldPublish));
|
||||
if (publishCultures == null) throw new ArgumentNullException(nameof(publishCultures));
|
||||
if (shouldPublish == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(shouldPublish));
|
||||
}
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
if (publishCultures == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(publishCultures));
|
||||
}
|
||||
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
var results = new List<PublishResult>();
|
||||
var publishedDocuments = new List<IContent>();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
|
||||
var allLangs = _languageRepository.GetMany().ToList();
|
||||
|
||||
if (!document.HasIdentity)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot not branch-publish a new document.");
|
||||
}
|
||||
|
||||
var publishedState = document.PublishedState;
|
||||
PublishedState publishedState = document.PublishedState;
|
||||
if (publishedState == PublishedState.Publishing)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot mix PublishCulture and SaveAndPublishBranch.");
|
||||
}
|
||||
|
||||
// deal with the branch root - if it fails, abort
|
||||
var result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, evtMsgs, userId, allLangs);
|
||||
PublishResult result = SaveAndPublishBranchItem(scope, document, shouldPublish, publishCultures, true, publishedDocuments, eventMessages, userId, allLangs);
|
||||
if (result != null)
|
||||
{
|
||||
results.Add(result);
|
||||
if (!result.Success) return results;
|
||||
if (!result.Success)
|
||||
{
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
// deal with descendants
|
||||
@@ -1672,7 +1721,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
count = 0;
|
||||
// important to order by Path ASC so make it explicit in case defaults change
|
||||
// ReSharper disable once RedundantArgumentDefaultValue
|
||||
foreach (var d in GetPagedDescendants(document.Id, page, pageSize, out _, ordering: Ordering.By("Path", Direction.Ascending)))
|
||||
foreach (IContent d in GetPagedDescendants(document.Id, page, pageSize, out _, ordering: Ordering.By("Path", Direction.Ascending)))
|
||||
{
|
||||
count++;
|
||||
|
||||
@@ -1684,11 +1733,14 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
}
|
||||
|
||||
// no need to check path here, parent has to be published here
|
||||
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, evtMsgs, userId, allLangs);
|
||||
result = SaveAndPublishBranchItem(scope, d, shouldPublish, publishCultures, false, publishedDocuments, eventMessages, userId, allLangs);
|
||||
if (result != null)
|
||||
{
|
||||
results.Add(result);
|
||||
if (result.Success) continue;
|
||||
if (result.Success)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if we could not publish the document, cut its branch
|
||||
@@ -1702,8 +1754,8 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
// trigger events for the entire branch
|
||||
// (SaveAndPublishBranchOne does *not* do it)
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(document, TreeChangeTypes.RefreshBranch).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(publishedDocuments, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(document, TreeChangeTypes.RefreshBranch, eventMessages));
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(publishedDocuments, eventMessages));
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
@@ -1753,14 +1805,14 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <inheritdoc />
|
||||
public OperationResult Delete(IContent content, int userId = Cms.Core.Constants.Security.SuperUserId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
if (scope.Notifications.PublishCancelable(new ContentDeletingNotification(content, evtMsgs)))
|
||||
if (scope.Notifications.PublishCancelable(new ContentDeletingNotification(content, eventMessages)))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Cancel(evtMsgs);
|
||||
return OperationResult.Cancel(eventMessages);
|
||||
}
|
||||
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
@@ -1770,18 +1822,18 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// just raise the event
|
||||
if (content.Trashed == false && content.Published)
|
||||
{
|
||||
scope.Notifications.Publish(new ContentUnpublishedNotification(content, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentUnpublishedNotification(content, eventMessages));
|
||||
}
|
||||
|
||||
DeleteLocked(scope, content, evtMsgs);
|
||||
DeleteLocked(scope, content, eventMessages);
|
||||
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.Remove).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.Remove, eventMessages));
|
||||
Audit(AuditType.Delete, userId, content.Id);
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
return OperationResult.Succeed(evtMsgs);
|
||||
return OperationResult.Succeed(eventMessages);
|
||||
}
|
||||
|
||||
private void DeleteLocked(IScope scope, IContent content, EventMessages evtMsgs)
|
||||
@@ -1887,21 +1939,21 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <inheritdoc />
|
||||
public OperationResult MoveToRecycleBin(IContent content, int userId = Cms.Core.Constants.Security.SuperUserId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
var moves = new List<(IContent, string)>();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
|
||||
var originalPath = content.Path;
|
||||
var moveEventInfo = new MoveEventInfo<IContent>(content, originalPath, Cms.Core.Constants.System.RecycleBinContent);
|
||||
|
||||
var movingToRecycleBinNotification = new ContentMovingToRecycleBinNotification(moveEventInfo, evtMsgs);
|
||||
var movingToRecycleBinNotification = new ContentMovingToRecycleBinNotification(moveEventInfo, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(movingToRecycleBinNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Cancel(evtMsgs); // causes rollback
|
||||
return OperationResult.Cancel(eventMessages); // causes rollback
|
||||
}
|
||||
|
||||
// if it's published we may want to force-unpublish it - that would be backward-compatible... but...
|
||||
@@ -1911,19 +1963,19 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
//{ }
|
||||
|
||||
PerformMoveLocked(content, Cms.Core.Constants.System.RecycleBinContent, null, userId, moves, true);
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.RefreshBranch).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshBranch, eventMessages));
|
||||
|
||||
var moveInfo = moves
|
||||
MoveEventInfo<IContent>[] moveInfo = moves
|
||||
.Select(x => new MoveEventInfo<IContent>(x.Item1, x.Item2, x.Item1.ParentId))
|
||||
.ToArray();
|
||||
|
||||
scope.Notifications.Publish(new ContentMovedToRecycleBinNotification(moveInfo, evtMsgs).WithStateFrom(movingToRecycleBinNotification));
|
||||
scope.Notifications.Publish(new ContentMovedToRecycleBinNotification(moveInfo, eventMessages).WithStateFrom(movingToRecycleBinNotification));
|
||||
Audit(AuditType.Move, userId, content.Id, "Moved to recycle bin");
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
return OperationResult.Succeed(evtMsgs);
|
||||
return OperationResult.Succeed(eventMessages);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1946,21 +1998,23 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
return;
|
||||
}
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
var moves = new List<(IContent, string)>();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
|
||||
var parent = parentId == Cms.Core.Constants.System.Root ? null : GetById(parentId);
|
||||
IContent parent = parentId == Cms.Core.Constants.System.Root ? null : GetById(parentId);
|
||||
if (parentId != Cms.Core.Constants.System.Root && (parent == null || parent.Trashed))
|
||||
{
|
||||
throw new InvalidOperationException("Parent does not exist or is trashed."); // causes rollback
|
||||
}
|
||||
|
||||
var moveEventInfo = new MoveEventInfo<IContent>(content, content.Path, parentId);
|
||||
|
||||
var movingNotification = new ContentMovingNotification(moveEventInfo, evtMsgs);
|
||||
var movingNotification = new ContentMovingNotification(moveEventInfo, eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(movingNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
@@ -1984,13 +2038,13 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
PerformMoveLocked(content, parentId, parent, userId, moves, trashed);
|
||||
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(content, TreeChangeTypes.RefreshBranch).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(content, TreeChangeTypes.RefreshBranch, eventMessages));
|
||||
|
||||
var moveInfo = moves //changes
|
||||
MoveEventInfo<IContent>[] moveInfo = moves //changes
|
||||
.Select(x => new MoveEventInfo<IContent>(x.Item1, x.Item2, x.Item1.ParentId))
|
||||
.ToArray();
|
||||
|
||||
scope.Notifications.Publish(new ContentMovedNotification(moveInfo, evtMsgs).WithStateFrom(movingNotification));
|
||||
scope.Notifications.Publish(new ContentMovedNotification(moveInfo, eventMessages).WithStateFrom(movingNotification));
|
||||
|
||||
Audit(AuditType.Move, userId, content.Id);
|
||||
|
||||
@@ -2064,9 +2118,9 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
public OperationResult EmptyRecycleBin(int userId = Cms.Core.Constants.Security.SuperUserId)
|
||||
{
|
||||
var deleted = new List<IContent>();
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
|
||||
@@ -2075,30 +2129,30 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// are managed by Delete, and not here.
|
||||
|
||||
// no idea what those events are for, keep a simplified version
|
||||
var emptyingRecycleBinNotification = new ContentEmptyingRecycleBinNotification(evtMsgs);
|
||||
var emptyingRecycleBinNotification = new ContentEmptyingRecycleBinNotification(eventMessages);
|
||||
if (scope.Notifications.PublishCancelable(emptyingRecycleBinNotification))
|
||||
{
|
||||
scope.Complete();
|
||||
return OperationResult.Cancel(evtMsgs);
|
||||
return OperationResult.Cancel(eventMessages);
|
||||
}
|
||||
|
||||
// emptying the recycle bin means deleting whatever is in there - do it properly!
|
||||
var query = Query<IContent>().Where(x => x.ParentId == Cms.Core.Constants.System.RecycleBinContent);
|
||||
var contents = _documentRepository.Get(query).ToArray();
|
||||
foreach (var content in contents)
|
||||
IQuery<IContent> query = Query<IContent>().Where(x => x.ParentId == Cms.Core.Constants.System.RecycleBinContent);
|
||||
IContent[] contents = _documentRepository.Get(query).ToArray();
|
||||
foreach (IContent content in contents)
|
||||
{
|
||||
DeleteLocked(scope, content, evtMsgs);
|
||||
DeleteLocked(scope, content, eventMessages);
|
||||
deleted.Add(content);
|
||||
}
|
||||
|
||||
scope.Notifications.Publish(new ContentEmptiedRecycleBinNotification(evtMsgs).WithStateFrom(emptyingRecycleBinNotification));
|
||||
scope.Events.Dispatch(TreeChanged, this, deleted.Select(x => new TreeChange<IContent>(x, TreeChangeTypes.Remove)).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentEmptiedRecycleBinNotification(eventMessages).WithStateFrom(emptyingRecycleBinNotification));
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(deleted, TreeChangeTypes.Remove, eventMessages));
|
||||
Audit(AuditType.Delete, userId, Cms.Core.Constants.System.RecycleBinContent, "Recycle bin emptied");
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
return OperationResult.Succeed(evtMsgs);
|
||||
return OperationResult.Succeed(eventMessages);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -2131,14 +2185,14 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
/// <returns>The newly created <see cref="IContent"/> object</returns>
|
||||
public IContent Copy(IContent content, int parentId, bool relateToOriginal, bool recursive, int userId = Cms.Core.Constants.Security.SuperUserId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
var copy = content.DeepCloneWithResetIdentities();
|
||||
IContent copy = content.DeepCloneWithResetIdentities();
|
||||
copy.ParentId = parentId;
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
if (scope.Notifications.PublishCancelable(new ContentCopyingNotification(content, copy, parentId, evtMsgs)))
|
||||
if (scope.Notifications.PublishCancelable(new ContentCopyingNotification(content, copy, parentId, eventMessages)))
|
||||
{
|
||||
scope.Complete();
|
||||
return null;
|
||||
@@ -2155,12 +2209,15 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// a copy is not published (but not really unpublishing either)
|
||||
// update the create author and last edit author
|
||||
if (copy.Published)
|
||||
{
|
||||
copy.Published = false;
|
||||
}
|
||||
|
||||
copy.CreatorId = userId;
|
||||
copy.WriterId = userId;
|
||||
|
||||
//get the current permissions, if there are any explicit ones they need to be copied
|
||||
var currentPermissions = GetPermissions(content);
|
||||
EntityPermissionCollection currentPermissions = GetPermissions(content);
|
||||
currentPermissions.RemoveWhere(p => p.IsDefaultPermissions);
|
||||
|
||||
// save and flush because we need the ID for the recursive Copying events
|
||||
@@ -2184,16 +2241,19 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
var total = long.MaxValue;
|
||||
while (page * pageSize < total)
|
||||
{
|
||||
var descendants = GetPagedDescendants(content.Id, page++, pageSize, out total);
|
||||
foreach (var descendant in descendants)
|
||||
IEnumerable<IContent> descendants = GetPagedDescendants(content.Id, page++, pageSize, out total);
|
||||
foreach (IContent descendant in descendants)
|
||||
{
|
||||
// if parent has not been copied, skip, else gets its copy id
|
||||
if (idmap.TryGetValue(descendant.ParentId, out parentId) == false) continue;
|
||||
if (idmap.TryGetValue(descendant.ParentId, out parentId) == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var descendantCopy = descendant.DeepCloneWithResetIdentities();
|
||||
IContent descendantCopy = descendant.DeepCloneWithResetIdentities();
|
||||
descendantCopy.ParentId = parentId;
|
||||
|
||||
if (scope.Notifications.PublishCancelable(new ContentCopyingNotification(descendant, descendantCopy, parentId, evtMsgs)))
|
||||
if (scope.Notifications.PublishCancelable(new ContentCopyingNotification(descendant, descendantCopy, parentId, eventMessages)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -2201,7 +2261,10 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// a copy is not published (but not really unpublishing either)
|
||||
// update the create author and last edit author
|
||||
if (descendantCopy.Published)
|
||||
{
|
||||
descendantCopy.Published = false;
|
||||
}
|
||||
|
||||
descendantCopy.CreatorId = userId;
|
||||
descendantCopy.WriterId = userId;
|
||||
|
||||
@@ -2218,10 +2281,10 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// - tags should be handled by the content repository
|
||||
// - a copy is unpublished and therefore has no impact on tags in DB
|
||||
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>(copy, TreeChangeTypes.RefreshBranch).ToEventArgs());
|
||||
foreach (var x in copies)
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(copy, TreeChangeTypes.RefreshBranch, eventMessages));
|
||||
foreach (Tuple<IContent, IContent> x in copies)
|
||||
{
|
||||
scope.Notifications.Publish(new ContentCopiedNotification(x.Item1, x.Item2, parentId, relateToOriginal, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentCopiedNotification(x.Item1, x.Item2, parentId, relateToOriginal, eventMessages));
|
||||
}
|
||||
Audit(AuditType.Copy, userId, content.Id);
|
||||
|
||||
@@ -2339,22 +2402,22 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
}
|
||||
}
|
||||
|
||||
private OperationResult Sort(IScope scope, IContent[] itemsA, int userId, EventMessages evtMsgs, bool raiseEvents)
|
||||
private OperationResult Sort(IScope scope, IContent[] itemsA, int userId, EventMessages eventMessages, bool raiseEvents)
|
||||
{
|
||||
var sortingNotification = new ContentSortingNotification(itemsA, evtMsgs);
|
||||
var savingNotification = new ContentSavingNotification(itemsA, evtMsgs);
|
||||
var sortingNotification = new ContentSortingNotification(itemsA, eventMessages);
|
||||
var savingNotification = new ContentSavingNotification(itemsA, eventMessages);
|
||||
if (raiseEvents)
|
||||
{
|
||||
// raise cancelable sorting event
|
||||
if (scope.Notifications.PublishCancelable(sortingNotification))
|
||||
{
|
||||
return OperationResult.Cancel(evtMsgs);
|
||||
return OperationResult.Cancel(eventMessages);
|
||||
}
|
||||
|
||||
// raise cancelable saving event
|
||||
if (scope.Notifications.PublishCancelable(savingNotification))
|
||||
{
|
||||
return OperationResult.Cancel(evtMsgs);
|
||||
return OperationResult.Cancel(eventMessages);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2362,7 +2425,7 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
var saved = new List<IContent>();
|
||||
var sortOrder = 0;
|
||||
|
||||
foreach (var content in itemsA)
|
||||
foreach (IContent content in itemsA)
|
||||
{
|
||||
// if the current sort order equals that of the content we don't
|
||||
// need to update it, so just increment the sort order and continue.
|
||||
@@ -2379,7 +2442,9 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
// if it's published, register it, no point running StrategyPublish
|
||||
// since we're not really publishing it and it cannot be cancelled etc
|
||||
if (content.Published)
|
||||
{
|
||||
published.Add(content);
|
||||
}
|
||||
|
||||
// save
|
||||
saved.Add(content);
|
||||
@@ -2389,34 +2454,34 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
if (raiseEvents)
|
||||
{
|
||||
//first saved, then sorted
|
||||
scope.Notifications.Publish(new ContentSavedNotification(itemsA, evtMsgs).WithStateFrom(savingNotification));
|
||||
scope.Notifications.Publish(new ContentSortedNotification(itemsA, evtMsgs).WithStateFrom(sortingNotification));
|
||||
scope.Notifications.Publish(new ContentSavedNotification(itemsA, eventMessages).WithStateFrom(savingNotification));
|
||||
scope.Notifications.Publish(new ContentSortedNotification(itemsA, eventMessages).WithStateFrom(sortingNotification));
|
||||
}
|
||||
|
||||
scope.Events.Dispatch(TreeChanged, this, saved.Select(x => new TreeChange<IContent>(x, TreeChangeTypes.RefreshNode)).ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(saved, TreeChangeTypes.RefreshNode, eventMessages));
|
||||
|
||||
if (raiseEvents && published.Any())
|
||||
{
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(published, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentPublishedNotification(published, eventMessages));
|
||||
}
|
||||
|
||||
Audit(AuditType.Sort, userId, 0, "Sorting content performed by user");
|
||||
return OperationResult.Succeed(evtMsgs);
|
||||
return OperationResult.Succeed(eventMessages);
|
||||
}
|
||||
|
||||
public ContentDataIntegrityReport CheckDataIntegrity(ContentDataIntegrityReportOptions options)
|
||||
{
|
||||
using (var scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
using (IScope scope = ScopeProvider.CreateScope(autoComplete: true))
|
||||
{
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
|
||||
var report = _documentRepository.CheckDataIntegrity(options);
|
||||
ContentDataIntegrityReport report = _documentRepository.CheckDataIntegrity(options);
|
||||
|
||||
if (report.FixedIssues.Count > 0)
|
||||
{
|
||||
//The event args needs a content item so we'll make a fake one with enough properties to not cause a null ref
|
||||
var root = new Content("root", -1, new ContentType(_shortStringHelper, -1)) {Id = -1, Key = Guid.Empty};
|
||||
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IContent>.EventArgs(new TreeChange<IContent>(root, TreeChangeTypes.RefreshAll)));
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(root, TreeChangeTypes.RefreshAll, EventMessagesFactory.Get()));
|
||||
}
|
||||
|
||||
return report;
|
||||
@@ -2476,18 +2541,6 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after change.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event needs to be rewritten using notifications instead
|
||||
/// </remarks>
|
||||
internal static event TypedEventHandler<IContentService, TreeChange<IContent>.EventArgs> TreeChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Publishing Strategies
|
||||
|
||||
/// <summary>
|
||||
@@ -2735,20 +2788,20 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
var changes = new List<TreeChange<IContent>>();
|
||||
var moves = new List<(IContent, string)>();
|
||||
var contentTypeIdsA = contentTypeIds.ToArray();
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
EventMessages eventMessages = EventMessagesFactory.Get();
|
||||
|
||||
// using an immediate uow here because we keep making changes with
|
||||
// PerformMoveLocked and DeleteLocked that must be applied immediately,
|
||||
// no point queuing operations
|
||||
//
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
using (IScope scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
scope.WriteLock(Cms.Core.Constants.Locks.ContentTree);
|
||||
|
||||
var query = Query<IContent>().WhereIn(x => x.ContentTypeId, contentTypeIdsA);
|
||||
var contents = _documentRepository.Get(query).ToArray();
|
||||
IQuery<IContent> query = Query<IContent>().WhereIn(x => x.ContentTypeId, contentTypeIdsA);
|
||||
IContent[] contents = _documentRepository.Get(query).ToArray();
|
||||
|
||||
if (scope.Notifications.PublishCancelable(new ContentDeletingNotification(contents, evtMsgs)))
|
||||
if (scope.Notifications.PublishCancelable(new ContentDeletingNotification(contents, eventMessages)))
|
||||
{
|
||||
scope.Complete();
|
||||
return;
|
||||
@@ -2756,21 +2809,21 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
// order by level, descending, so deepest first - that way, we cannot move
|
||||
// a content of the deleted type, to the recycle bin (and then delete it...)
|
||||
foreach (var content in contents.OrderByDescending(x => x.ParentId))
|
||||
foreach (IContent content in contents.OrderByDescending(x => x.ParentId))
|
||||
{
|
||||
// if it's not trashed yet, and published, we should unpublish
|
||||
// but... Unpublishing event makes no sense (not going to cancel?) and no need to save
|
||||
// just raise the event
|
||||
if (content.Trashed == false && content.Published)
|
||||
{
|
||||
scope.Notifications.Publish(new ContentUnpublishedNotification(content, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentUnpublishedNotification(content, eventMessages));
|
||||
}
|
||||
|
||||
// if current content has children, move them to trash
|
||||
var c = content;
|
||||
var childQuery = Query<IContent>().Where(x => x.ParentId == c.Id);
|
||||
var children = _documentRepository.Get(childQuery);
|
||||
foreach (var child in children)
|
||||
IContent c = content;
|
||||
IQuery<IContent> childQuery = Query<IContent>().Where(x => x.ParentId == c.Id);
|
||||
IEnumerable<IContent> children = _documentRepository.Get(childQuery);
|
||||
foreach (IContent child in children)
|
||||
{
|
||||
// see MoveToRecycleBin
|
||||
PerformMoveLocked(child, Cms.Core.Constants.System.RecycleBinContent, null, userId, moves, true);
|
||||
@@ -2779,18 +2832,18 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
|
||||
// delete content
|
||||
// triggers the deleted event (and handles the files)
|
||||
DeleteLocked(scope, content, evtMsgs);
|
||||
DeleteLocked(scope, content, eventMessages);
|
||||
changes.Add(new TreeChange<IContent>(content, TreeChangeTypes.Remove));
|
||||
}
|
||||
|
||||
var moveInfos = moves
|
||||
MoveEventInfo<IContent>[] moveInfos = moves
|
||||
.Select(x => new MoveEventInfo<IContent>(x.Item1, x.Item2, x.Item1.ParentId))
|
||||
.ToArray();
|
||||
if (moveInfos.Length > 0)
|
||||
{
|
||||
scope.Notifications.Publish(new ContentMovedToRecycleBinNotification(moveInfos, evtMsgs));
|
||||
scope.Notifications.Publish(new ContentMovedToRecycleBinNotification(moveInfos, eventMessages));
|
||||
}
|
||||
scope.Events.Dispatch(TreeChanged, this, changes.ToEventArgs());
|
||||
scope.Notifications.Publish(new ContentTreeChangeNotification(changes, eventMessages));
|
||||
|
||||
Audit(AuditType.Delete, userId, Cms.Core.Constants.System.Root, $"Delete content of type {string.Join(",", contentTypeIdsA)}");
|
||||
|
||||
@@ -3064,8 +3117,5 @@ namespace Umbraco.Cms.Core.Services.Implement
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user