User Message (former Speech bubble) in custom event
Hi,
I wrote a custom publish event. When the event has been canceled cause some conditions do not fit, the user gets the message "Publishing was cancelled by a 3rd party plugin". Is there any way to customize and change this feedback, so that you can tell the user more exactly what went wrong?
Our solution involves adding a custom message handler which intercepts requests to the api. In this instance we are intercepting the requests to the PostSave event and adding a continuation which executes when the response is received. Here we can check for the "Publishing was cancelled" warning notification and change it to our custom message.
using Umbraco.Core;
public class CustomNotificationsRegistration : IApplicationEventHandler
{
public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication,
ApplicationContext applicationContext)
{ }
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication,
ApplicationContext applicationContext)
{
System.Web.Http.GlobalConfiguration.Configuration.MessageHandlers.Add(new WebApiHandler());
}
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication,
ApplicationContext applicationContext)
{
}
}
using System;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core.Logging;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.UI;
public class WebApiHandler : System.Net.Http.DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.RequestUri.AbsolutePath.ToLower() == "/umbraco/backoffice/umbracoapi/content/postsave")
{
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
var response = task.Result;
try
{
var data = response.Content;
var content = ((ObjectContent)(data)).Value as ContentItemDisplay;
//perform any checking (if needed) to ensure you have the right request
//for us the cancellation of publish was only on one content type so we could narrow that down here
if (content.ContentTypeAlias.Equals("[My content type alias]"))
{
if (content.Notifications.Count > 0)
{
foreach (var notification in content.Notifications)
{
if (notification.Header.Equals("Publish") && notification.Message.ToLower().Contains("publishing was cancelled"))
{
//change the default notification to our custom message
notification.Header = "[Custom Header Message]";
notification.Message = "[Custom Message]";
notification.NotificationType = SpeechBubbleIcon.Warning;
}
}
}
}
}
catch (Exception ex)
{
LogHelper.Error<WebApiHandler>("Error changing custom publishing cancelled message.", ex);
}
return response;
});
}
return base.SendAsync(request, cancellationToken);
}
}
I guess this could also be used in v7 to send extra notification? Basically after save event i am creating a media folder and i want to inform user this has been succesful.
Hi all,
I was trying to approach this in a different way and had a look at the source code for Umbraco.
For the update checker that displays the blue notification info bar if you are the admin user of Umbraco and that there is a newer version of Umbraco available to install.
Rather than push the notification from a C# event directly they do a WebAPI call the first time the backoffice is installed, depending on the response they push a notification using the AngularJS notificationService add() function.
//Get the same base module that Umbraco uses
var app = angular.module("umbraco");
//When the module runs/excutes...
app.run(["$rootScope", "notificationsService", "eventsService", function ($rootScope, notificationsService, eventsService) {
//Let's listen for any time formSubmitting
eventsService.on("formSubmitting", function (e, args) {
console.log("e", e);
console.log("args", args);
//Sad panda :(
//This event 'formSubmitting' from formHelper.service.js only fires on the relative scope
//And not the rootScope so have no easy way to listen in for this
//Need another smart way?!
//Psudeo code
//Check for the type of docType that is being saved
//If type == "magic"
//Then do $http post or own service/resource with promise
//Do some funky event stuff - create an auto media folder
//If success promise
//Show notification with notificationService.add() using JSON response from API $http
});
//Let's listen for any time formSubmitted
eventsService.on("formSubmitted", function (e, args) {
console.log("e", e);
console.log("args", args);
});
//Let's listen for any time app.ready this is an event on the rootScope that is emitted
//So this works just lovely
eventsService.on("app.ready", function (e, args) {
console.log("e", e);
console.log("args", args);
notificationsService.success("Warren", "says hello");
});
}]);
However Shannon replied to me on the gist with a comment and suggested it was not a good idea with reasons, I recommend you read it to understand why this is not a good approach as a fix for now.
But he did mention that he was not aware of any issue on the issue tracker regarding this problems of not being able to send notifications from C# events.
So I am off to create one now and will post back here shortly with the issue tracker link and would recommend that we vote this up, so it can get some attention and thought from the Core team.
Yes, you can use this to send an extra notification. I amended my example to add a new notification rather than edit an existing one and it worked, giving both the Content Published message and the custom message I added. Again you would want to check you had the correct response (e.g. by checking the content type) so the message does not appear for every page you save. Also you would presumably want to check that the message from Umbraco is actually a success message and not a failure. I have not included that check in the sample below.
var data = response.Content;
var content = ((ObjectContent)(data)).Value as ContentItemDisplay;
if (content.ContentTypeAlias.Equals("[My content type alias]"))
{
content.Notifications.Add(new Umbraco.Web.Models.ContentEditing.Notification()
{
Header = "Media Folder",
Message = "The media folder was created sucessfully",
NotificationType = SpeechBubbleIcon.Success
});
}
Here is my flow, I create a new item of type Talent, I have event for ContentService_Saved and only for talent items i create a media folder. I can use your example and in the delegating handler check if current type is Talent and it's a save, however this always fire for talent save i only need it to fire once as the folder is only created once any ideas?
I have had a look into it and there is an AdditionalData dictionary on the IContent/ContentItemDisplay object which you can use to set a flag if you have created a new media folder. I have tried it and it works on my machine :)
In the save event handler:
if("[you have created a new Media folder]")
{
content.AdditionalData.Add("NewMediaFolderCreated", System.DateTime.Now);
}
In the DelegatingHandler:
bool hasNewMediaFolder = content.AdditionalData.ContainsKey("NewMediaFolderCreated");
if (hasNewMediaFolder)
{
//add the additional message to the response
}
As far as I can see in this instance the AdditionalData does not persist after the request so you don't need to check for its existence in the save event handler or delete it in the DelegatingHandler afterwards.
I know its an old post, with a already acceptet answer. But i hope you still follow this.
I wanna know how you can get content in a event handler?
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
MediaService.Saved += MediaService_Saved;
}
private static void MediaService_Saved(IMediaService sender, SaveEventArgs<IMedia> e)
{
// How do i get the content as an MediaItemDisplay or ContentItemDisplay?
content.AdditionalData.Add("NewMediaFolderCreated", System.DateTime.Now);
// I can do this. But that gives a message that stops the process..
e.Messages.Add(new EventMessage("Saved", "MediaService_Saved", EventMessageType.Success));
}
A bit of a long shot now but...did you ever find out why that stops the process and more importantly how to work around it? I'm trying to do something similar in a v7 site.
You can alternatively use this class to easily create the notification if it helps like the above WebAPI that the Content section of the Angular'fied Umbraco backoffice uses to push a notification down the response in the JSON.
Ace to know that this can be done & that some great community teamwork in action here. Now we could do with spending a little bit of time documenting this for others to discover easier. With the Markdown docs over on the Umbraco GitHub repositories, so it eventually gets pushed over to the docs on our.umbraco.org :)
I needed the same functionality but after members were created.
I'm still in the process of coding it.
Stumbled into some problems with @Andrew's answer because the Value field didn't contain the IMember and instead contained a MemberDisplay, so I couldn't find an elegant way to send additional information from my OnMemberCreated handler to the SendAsync method.
I was looking to trying to do this in the ApplicationEventHandler on a content service saving event.
As on a document type in the back office editor i have some custom rules for i need to apply and the only place i can think of doing this would be on the on saving event and if the validation fails i can cancel the saving.
The document has two fields version number (text) and a media uploader, and i need to ensure that if version number has been updated the uploaded media has also changed.
I have the logic in place to cancel the saving but cant find a way to show that the save has been cancelled to the user.
I think there is no possibility to do this with the original 7.2.8 version. You must wait for 7.3.0 in the next few weeks or you can try to do this:
Download the source code of 7.2.8, change the 5 files like in this revision (https://github.com/Umbraco/Umbraco-CMS/commit/926ea54c393dc80d1531224a5d0b1ac4c76e3c5c) build the solution and copy/overwrite the dll's in the bin-folder of your original 7.2.8 instance. I don't know if this works, but in theory it should work.
User Message (former Speech bubble) in custom event
Hi,
I wrote a custom publish event. When the event has been canceled cause some conditions do not fit, the user gets the message "Publishing was cancelled by a 3rd party plugin". Is there any way to customize and change this feedback, so that you can tell the user more exactly what went wrong?
Best regards -
Tom
Hi Tom,
I have the same problem. I would solve this with ClientTools:
But it seems like this would not work in eventhanlder. Has anyone an idea to solve this?
Best regards
Sören
Hi I've come across the same issue. Any updates on this?
Much Appreciated
Lakshan
Hi,
We had exactly this same problem where we were cancelling publishing for some items but were unable to tell the editor why. I eventually solved it by adapting some code I found in the Hybrid Framework for Umbraco v7 Best Practises here: https://github.com/jbreuer/Hybrid-Framework-for-Umbraco-v7-Best-Practises/blob/master/Umbraco.Extensions/Utilities/WebApiHandler.cs
Our solution involves adding a custom message handler which intercepts requests to the api. In this instance we are intercepting the requests to the PostSave event and adding a continuation which executes when the response is received. Here we can check for the "Publishing was cancelled" warning notification and change it to our custom message.
Hope this helps.
Andrew
Andrew,
I guess this could also be used in v7 to send extra notification? Basically after save event i am creating a media folder and i want to inform user this has been succesful.
Regards
Ismail
Hi all,
I was trying to approach this in a different way and had a look at the source code for Umbraco.
For the update checker that displays the blue notification info bar if you are the admin user of Umbraco and that there is a newer version of Umbraco available to install. Rather than push the notification from a C# event directly they do a WebAPI call the first time the backoffice is installed, depending on the response they push a notification using the AngularJS notificationService add() function.
So I tried last night to do a POC to try in the similar way to do the same thing:
https://gist.github.com/warrenbuckley/07d21b682c8e076cb5e2
However Shannon replied to me on the gist with a comment and suggested it was not a good idea with reasons, I recommend you read it to understand why this is not a good approach as a fix for now.
But he did mention that he was not aware of any issue on the issue tracker regarding this problems of not being able to send notifications from C# events.
So I am off to create one now and will post back here shortly with the issue tracker link and would recommend that we vote this up, so it can get some attention and thought from the Core team.
Cheers,
Warren
The issue to follow this up with the Core team and vote up is here:
http://issues.umbraco.org/issue/U4-5927
Hi Ismail,
Yes, you can use this to send an extra notification. I amended my example to add a new notification rather than edit an existing one and it worked, giving both the Content Published message and the custom message I added. Again you would want to check you had the correct response (e.g. by checking the content type) so the message does not appear for every page you save. Also you would presumably want to check that the message from Umbraco is actually a success message and not a failure. I have not included that check in the sample below.
Regards
Andrew
Andrew,
Here is my flow, I create a new item of type Talent, I have event for ContentService_Saved and only for talent items i create a media folder. I can use your example and in the delegating handler check if current type is Talent and it's a save, however this always fire for talent save i only need it to fire once as the folder is only created once any ideas?
Regards
Ismail
Hi Ismail,
I have had a look into it and there is an AdditionalData dictionary on the IContent/ContentItemDisplay object which you can use to set a flag if you have created a new media folder. I have tried it and it works on my machine :)
In the save event handler:
In the DelegatingHandler:
As far as I can see in this instance the AdditionalData does not persist after the request so you don't need to check for its existence in the save event handler or delete it in the DelegatingHandler afterwards.
Hope this helps.
Andrew
I know its an old post, with a already acceptet answer. But i hope you still follow this.
I wanna know how you can get content in a event handler?
The message i get look like this
A bit of a long shot now but...did you ever find out why that stops the process and more importantly how to work around it? I'm trying to do something similar in a v7 site.
Andrew,
Awesome this works a treat, not sure why i cannot mark it as solution!
Regards
Ismail
@ismail you are not the original poster of this thread hence you can't mark Andrew's response as the solution/answer.
@warren I get an access denied page when trying to go to your issue. (http://issues.umbraco.org/issue/U4-5927)
@Mark yep issue was locked to me & HQ/Core team only. Not sure why asked to be visible to all. Will see what will happen with it.
@Andrew well done for finding the answer to this. Seems like it is possible like you showed Ismail.
I found an example of where it's used in the Umbraco Core to push notifications down the wire.
https://github.com/umbraco/Umbraco-CMS/blob/788a0241d828cecd09f84a2a356b643422c6599c/src/Umbraco.Web/Editors/ContentController.cs#L275
You can alternatively use this class to easily create the notification if it helps like the above WebAPI that the Content section of the Angular'fied Umbraco backoffice uses to push a notification down the response in the JSON.
https://github.com/umbraco/Umbraco-CMS/blob/788a0241d828cecd09f84a2a356b643422c6599c/src/Umbraco.Web/Models/ContentEditing/MessagesExtensions.cs#L17
Ace to know that this can be done & that some great community teamwork in action here. Now we could do with spending a little bit of time documenting this for others to discover easier. With the Markdown docs over on the Umbraco GitHub repositories, so it eventually gets pushed over to the docs on our.umbraco.org :)
Found some more examples of Notifications being used in the backoffice
https://github.com/umbraco/Umbraco-CMS/blob/788a0241d828cecd09f84a2a356b643422c6599c/src/Umbraco.Web/Editors/CurrentUserController.cs#L64
https://github.com/umbraco/Umbraco-CMS/blob/788a0241d828cecd09f84a2a356b643422c6599c/src/Umbraco.Web/Editors/DataTypeController.cs#L162
Thank you @Andrew McFarland for the great solution. Worked for me!
I needed the same functionality but after members were created. I'm still in the process of coding it.
Stumbled into some problems with @Andrew's answer because the Value field didn't contain the IMember and instead contained a MemberDisplay, so I couldn't find an elegant way to send additional information from my OnMemberCreated handler to the SendAsync method.
Thanks to everyone for sharing their discoveries.
I was looking to trying to do this in the ApplicationEventHandler on a content service saving event.
As on a document type in the back office editor i have some custom rules for i need to apply and the only place i can think of doing this would be on the on saving event and if the validation fails i can cancel the saving.
The document has two fields version number (text) and a media uploader, and i need to ensure that if version number has been updated the uploaded media has also changed.
I have the logic in place to cancel the saving but cant find a way to show that the save has been cancelled to the user.
I have seen this link: http://issues.umbraco.org/issue/U4-5927 that i should be able to achieve this with the change that is coming in 7.3.0
Is there anything that i can do on 7.2.8, version of achieve something similar?
Hi Paul,
I think there is no possibility to do this with the original 7.2.8 version. You must wait for 7.3.0 in the next few weeks or you can try to do this: Download the source code of 7.2.8, change the 5 files like in this revision (https://github.com/Umbraco/Umbraco-CMS/commit/926ea54c393dc80d1531224a5d0b1ac4c76e3c5c) build the solution and copy/overwrite the dll's in the bin-folder of your original 7.2.8 instance. I don't know if this works, but in theory it should work.
Best, Sören
is working on a reply...