/// <summary>
        /// Saves and Publishes a single <see cref="IContent"/> object
        /// </summary>
        /// <param name="content">The <see cref="IContent"/> to save and publish</param>
        /// <param name="userId">Optional Id of the User issueing the publishing</param>
        /// <param name="raiseEvents">Optional boolean indicating whether or not to raise save events.</param>
        /// <returns>True if publishing succeeded, otherwise False</returns>
	    private Attempt<PublishStatus> SaveAndPublishDo(IContent content, int userId = 0, bool raiseEvents = true)
        {
            if (raiseEvents)
            {
                if (Saving.IsRaisedEventCancelled(new SaveEventArgs<IContent>(content), this))
                {
                    return new Attempt<PublishStatus>(false, new PublishStatus(content, PublishStatusType.FailedCancelledByEvent));
                }
            }

            using (new WriteLock(Locker))
            {
                //Has this content item previously been published? If so, we don't need to refresh the children
                var previouslyPublished = content.HasIdentity && HasPublishedVersion(content.Id); //content might not have an id
                var publishStatus = new PublishStatus(content, PublishStatusType.Success); //initially set to success

                //Check if parent is published (although not if its a root node) - if parent isn't published this Content cannot be published
                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)
                {
                    var internalStrategy = (PublishingStrategy)_publishingStrategy;
                    //Publish and then update the database with new status
                    var publishResult = internalStrategy.PublishInternal(content, userId);
                    //set the status type to the publish result
                    publishStatus.StatusType = publishResult.Result.StatusType;
                }

                //we are successfully published if our publishStatus is still Successful
                bool published = publishStatus.StatusType == PublishStatusType.Success;

                var uow = _uowProvider.GetUnitOfWork();
                using (var repository = _repositoryFactory.CreateContentRepository(uow))
                {
                    //Since this is the Save and Publish method, the content should be saved even though the publish fails or isn't allowed
                    content.WriterId = userId;

                    repository.AddOrUpdate(content);

                    uow.Commit();

                    var xml = content.ToXml();
                    //Preview Xml
                    CreateAndSavePreviewXml(xml, content.Id, content.Version, uow.Database);

                    if (published)
                    {
                        //Content Xml
                        CreateAndSaveContentXml(xml, content.Id, uow.Database);
                    }
                }

                if (raiseEvents)
                    Saved.RaiseEvent(new SaveEventArgs<IContent>(content, false), this);

                //Save xml to db and call following method to fire event through PublishingStrategy to update cache
                if (published)
                {
                    _publishingStrategy.PublishingFinalized(content);
                }

                //We need to check if children and their publish state to ensure that we 'republish' content that was previously published
                if (published && previouslyPublished == false && HasChildren(content.Id))
                {
                    var descendants = GetPublishedDescendants(content);

                    _publishingStrategy.PublishingFinalized(descendants, false);
                }

                Audit.Add(AuditTypes.Publish, "Save and Publish performed by user", userId, content.Id);

                return new Attempt<PublishStatus>(publishStatus.StatusType == PublishStatusType.Success, publishStatus);
	        }	        	        
        }
 private string GetMessageForStatus(PublishStatus status)
 {
     switch (status.StatusType)
     {
         case PublishStatusType.Success:
         case PublishStatusType.SuccessAlreadyPublished:
             return ui.Text("publish", "nodePublish", status.ContentItem.Name, UmbracoUser);
         case PublishStatusType.FailedPathNotPublished:
             return ui.Text("publish", "contentPublishedFailedByParent", 
                            string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), UmbracoUser);
         case PublishStatusType.FailedHasExpired:                    
         case PublishStatusType.FailedAwaitingRelease:
         case PublishStatusType.FailedIsTrashed:
             return ""; //we will not notify about this type of failure... or should we ?                
         case PublishStatusType.FailedCancelledByEvent:
             return ui.Text("publish", "contentPublishedFailedByEvent",
                            string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id), UmbracoUser);
         case PublishStatusType.FailedContentInvalid:
             return ui.Text("publish", "contentPublishedFailedInvalid",
                            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();
     }
 }
 private string GetMessageForStatus(PublishStatus status)
 {
     switch (status.StatusType)
     {
         case PublishStatusType.Success:
         case PublishStatusType.SuccessAlreadyPublished:
             return ui.Text("speechBubbles", "editContentPublishedText", UmbracoUser);
         case PublishStatusType.FailedPathNotPublished:
             return ui.Text("publish", "contentPublishedFailedByParent",
                            string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id),
                            UmbracoUser).Trim();
         case PublishStatusType.FailedCancelledByEvent:
             return ui.Text("speechBubbles", "contentPublishedFailedByEvent");
         case PublishStatusType.FailedHasExpired:
         case PublishStatusType.FailedAwaitingRelease:
         case PublishStatusType.FailedIsTrashed:
         case PublishStatusType.FailedContentInvalid:
             return ui.Text("publish", "contentPublishedFailedInvalid",
                            new[]
                                {
                                    string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id),
                                    string.Join(",", status.InvalidProperties.Select(x => x.Alias))
                                }, UmbracoUser);
         default:
             throw new IndexOutOfRangeException();
     }
 }
 private void ShowMessageForPublishStatus(PublishStatus status, ContentItemDisplay display)
 {
     switch (status.StatusType)
     {
         case PublishStatusType.Success:
         case PublishStatusType.SuccessAlreadyPublished:
             display.AddSuccessNotification(
                 ui.Text("speechBubbles", "editContentPublishedHeader", UmbracoUser),
                 ui.Text("speechBubbles", "editContentPublishedText", UmbracoUser));
             break;
         case PublishStatusType.FailedPathNotPublished:
             display.AddWarningNotification(
                 ui.Text("publish"),
                 ui.Text("publish", "contentPublishedFailedByParent",
                         string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id),
                         UmbracoUser).Trim());
             break;
         case PublishStatusType.FailedCancelledByEvent:
             display.AddWarningNotification(
                 ui.Text("publish"),
                 ui.Text("speechBubbles", "contentPublishedFailedByEvent"));
             break;                
         case PublishStatusType.FailedAwaitingRelease:
             display.AddWarningNotification(
                 ui.Text("publish"),
                 ui.Text("publish", "contentPublishedFailedAwaitingRelease",
                         new[]
                             {
                                 string.Format("{0} ({1})", status.ContentItem.Name, status.ContentItem.Id)
                             },
                         UmbracoUser).Trim());
             break;
         case PublishStatusType.FailedHasExpired:
             //TODO: We should add proper error messaging for this!
         case PublishStatusType.FailedIsTrashed:
             //TODO: We should add proper error messaging for this!
         case PublishStatusType.FailedContentInvalid:
             display.AddWarningNotification(
                 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();
     }
 }