diff --git a/src/Umbraco.Core/Models/ContentBase.cs b/src/Umbraco.Core/Models/ContentBase.cs index 4c00831cae..6414ea2116 100644 --- a/src/Umbraco.Core/Models/ContentBase.cs +++ b/src/Umbraco.Core/Models/ContentBase.cs @@ -27,6 +27,7 @@ namespace Umbraco.Core.Models private bool _trashed; private int _contentTypeId; private PropertyCollection _properties; + private readonly List _lastInvalidProperties = new List(); /// /// Protected constructor for ContentBase (Base for Content and Media) @@ -421,7 +422,17 @@ namespace Umbraco.Core.Models /// True if content is valid otherwise false public virtual bool IsValid() { - return Properties.Any(property => !property.IsValid()) == false; + _lastInvalidProperties.Clear(); + _lastInvalidProperties.AddRange(Properties.Where(property => property.IsValid() == false)); + return _lastInvalidProperties.Any() == false; + } + + /// + /// Returns a collection of the result of the last validation process, this collection contains all invalid properties. + /// + internal IEnumerable LastInvalidProperties + { + get { return _lastInvalidProperties; } } public abstract void ChangeTrashedState(bool isTrashed, int parentId = -20); diff --git a/src/Umbraco.Core/Publishing/PublishStatus.cs b/src/Umbraco.Core/Publishing/PublishStatus.cs index 6bbaa59783..415b758965 100644 --- a/src/Umbraco.Core/Publishing/PublishStatus.cs +++ b/src/Umbraco.Core/Publishing/PublishStatus.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Umbraco.Core.Models; namespace Umbraco.Core.Publishing @@ -10,6 +11,11 @@ namespace Umbraco.Core.Publishing public IContent ContentItem { get; private set; } public PublishStatusType StatusType { get; internal set; } + /// + /// Gets sets the invalid properties if the status failed due to validation. + /// + public IEnumerable InvalidProperties { get; set; } + public PublishStatus(IContent content, PublishStatusType statusType) { ContentItem = content; @@ -24,6 +30,5 @@ namespace Umbraco.Core.Publishing { } - } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index ed47bc76d6..94aa0f9140 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -1552,6 +1552,8 @@ namespace Umbraco.Core.Services publishStatus.StatusType = CheckAndLogIsPublishable(content); //Content contains invalid property values and can therefore not be published - fire event? publishStatus.StatusType = CheckAndLogIsValid(content); + //set the invalid properties (if there are any) + publishStatus.InvalidProperties = ((ContentBase) content).LastInvalidProperties; //if we're still successful, then publish using the strategy if (publishStatus.StatusType == PublishStatusType.Success) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 8923314534..b1eb029426 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -670,7 +670,7 @@ To manage your website, simply open the umbraco back office and start adding con diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index e56017416b..af7156b776 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -656,7 +656,7 @@ To manage your website, simply open the umbraco back office and start adding con diff --git a/src/Umbraco.Web/WebServices/BulkPublishController.cs b/src/Umbraco.Web/WebServices/BulkPublishController.cs index 74fdf75919..2c18a6df2c 100644 --- a/src/Umbraco.Web/WebServices/BulkPublishController.cs +++ b/src/Umbraco.Web/WebServices/BulkPublishController.cs @@ -93,7 +93,11 @@ namespace Umbraco.Web.WebServices string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), UmbracoUser); case PublishStatusType.FailedContentInvalid: return ui.Text("publish", "contentPublishedFailedInvalid", - string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), UmbracoUser); + new []{ + string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), + string.Join(",", status.InvalidProperties.Select(x => x.Alias)) + }, + UmbracoUser); default: return status.StatusType.ToString(); } diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/publish.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/publish.aspx.cs index dfb7507073..255c61cbe8 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/publish.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/publish.aspx.cs @@ -14,6 +14,7 @@ namespace umbraco.dialogs /// /// Summary description for publish. /// + [Obsolete("This is no longer used whatsoever and will be removed from the codebase")] public partial class publish : UmbracoEnsuredPage { protected Literal total; diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs index 5cbd2b87ef..ab8579db27 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/editContent.aspx.cs @@ -4,6 +4,7 @@ using System.Web.UI.WebControls; using Umbraco.Core.Models; using Umbraco.Core.Persistence.Caching; using Umbraco.Core.IO; +using Umbraco.Core.Publishing; using Umbraco.Core.Services; using umbraco.BusinessLogic.Actions; using umbraco.uicontrols.DatePicker; @@ -290,65 +291,73 @@ namespace umbraco.cms.presentation { //update UI and set document properties PerformSaveLogic(); + + //the business logic here will check to see if the doc can actually be published and will return the + // appropriate result so we can display the correct error messages (or success). + var savePublishResult = _document.SaveAndPublishWithResult(UmbracoUser); - //the page is not valid, we'll still need to save the document and persist it - if (!Page.IsValid) - { - ClientTools.ShowSpeechBubble( - speechBubbleIcon.save, ui.Text("speechBubbles", "editContentSavedHeader", null), - ui.Text("speechBubbles", "editContentSavedText", null)); - _document.Save(); - return; - } + ShowMessageForStatus(savePublishResult.Result); - //If the document is at a level deeper than the root but it's ancestor's path is not published, - //it means that we cannot actually publish this document because one of it's parent's is not published. - //So, we still need to save the document but we'll show a different notification. - if (_document.Level > 1 && !Services.ContentService.IsPublishable(_document.Content)) + if (savePublishResult.Success) { - ClientTools.ShowSpeechBubble( - speechBubbleIcon.warning, ui.Text("publish"), - ui.Text("speechBubbles", "editContentPublishedFailedByParent")); - _document.Save(); - return; - } - - if (_document.SaveAndPublish(UmbracoUser)) - { - //library.UpdateDocumentCache(_document.Id); - - ClientTools.ShowSpeechBubble(speechBubbleIcon.save, ui.Text("speechBubbles", "editContentPublishedHeader", null), ui.Text("speechBubbles", "editContentPublishedText", null)); - _littPublishStatus.Text = string.Format("{0}: {1}
", ui.Text("content", "lastPublished", UmbracoUser), _document.VersionDate.ToString()); if (UmbracoUser.GetPermissions(_document.Path).IndexOf("U") > -1) + { _unPublish.Visible = true; + } _documentHasPublishedVersion = _document.Content.HasPublishedVersion(); - - //if (previouslyPublished == false) - //{ - // var descendants = ((ContentService)ApplicationContext.Current.Services.ContentService) - // .GetPublishedDescendants(_document.Content).ToList(); - - // if (descendants.Any()) - // { - // foreach (var descendant in descendants) - // { - // library.UpdateDocumentCache(descendant.Id); - // } - // library.RefreshContent(); - // } - //} } - else - { - ClientTools.ShowSpeechBubble(speechBubbleIcon.warning, ui.Text("publish"), ui.Text("speechBubbles", "contentPublishedFailedByEvent")); - } - + ClientTools.SyncTree(_document.Path, true); } + private void ShowMessageForStatus(PublishStatus status) + { + switch (status.StatusType) + { + case PublishStatusType.Success: + case PublishStatusType.SuccessAlreadyPublished: + ClientTools.ShowSpeechBubble( + speechBubbleIcon.save, + ui.Text("speechBubbles", "editContentPublishedHeader", UmbracoUser), + ui.Text("speechBubbles", "editContentPublishedText", UmbracoUser)); + break; + case PublishStatusType.FailedPathNotPublished: + ClientTools.ShowSpeechBubble( + speechBubbleIcon.warning, + ui.Text("publish"), + ui.Text("publish", "contentPublishedFailedByParent", + string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), + UmbracoUser).Trim()); + break; + case PublishStatusType.FailedCancelledByEvent: + ClientTools.ShowSpeechBubble( + speechBubbleIcon.warning, + ui.Text("publish"), + ui.Text("speechBubbles", "contentPublishedFailedByEvent")); + break; + case PublishStatusType.FailedHasExpired: + case PublishStatusType.FailedAwaitingRelease: + case PublishStatusType.FailedIsTrashed: + case PublishStatusType.FailedContentInvalid: + ClientTools.ShowSpeechBubble( + speechBubbleIcon.warning, + ui.Text("publish"), + ui.Text("publish", "contentPublishedFailedInvalid", + new[] + { + string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), + string.Join(",", status.InvalidProperties.Select(x => x.Alias)) + }, + UmbracoUser).Trim()); + break; + default: + throw new IndexOutOfRangeException(); + } + } + protected void UnPublishDo(object sender, EventArgs e) { _document.UnPublish(); diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 2df9e19f37..724ca09b34 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -1027,11 +1027,12 @@ namespace umbraco.cms.businesslogic.web } /// - /// Saves and publishes a document + /// Do not use! only used internally in order to get the published status until we upgrade everything to use the new API /// - /// The usercontext under which the action are performed + /// /// - public bool SaveAndPublish(User u) + [Obsolete("Do not use! only used internally in order to get the published status until we upgrade everything to use the new API")] + internal Attempt SaveAndPublishWithResult(User u) { foreach (var property in GenericProperties) { @@ -1065,13 +1066,24 @@ namespace umbraco.cms.businesslogic.web //Now we need to fire the After publish event FireAfterPublish(publishArgs); - return result.Success; + return result; } - - return false; + + return Attempt.False; } - return false; + return Attempt.False; + } + + /// + /// Saves and publishes a document + /// + /// The usercontext under which the action are performed + /// + public bool SaveAndPublish(User u) + { + var result = SaveAndPublishWithResult(u); + return result.Success; } [Obsolete("Obsolete, Use Umbraco.Core.Services.ContentService.HasPublishedVersion()", false)]