Umbraco - when editor create content send email notification to admin - email

Is it possible?
I am an admin. I want to be notified by email when editor (or writer or whom ever with the access) creates some content (e.g. enters some News in News document type).
And how?
I use Umbraco 7.5

You need to code into Umbraco ContentService events.
The following should get you started. It will be triggered whenever an item is published.
Be careful what you wish for though. You may get a barrage of useless emails if somebody publishes a parent node along with all of its child nodes.
There are other events that you can hook into so please refer to documentation at https://our.umbraco.com/Documentation/Reference/Events/ContentService-Events-v7.
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Publishing;
using Umbraco.Core.Services;
namespace My.Namespace
{
public class MyEventHandler : ApplicationEventHandler
{
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ContentService.Published += ContentServicePublished;
}
private void ContentServicePublished(IPublishingStrategy sender, PublishEventArgs<IContent> args)
{
foreach (var node in args.PublishedEntities)
{
// Your code to send email here
}
}
}
}

You can either write your own custom code by creating some event handlers, which is what #wingyip has recommended, or you can use built-in Umbraco notification functionality.
For the second built-in option, please see all the steps here on this post.

Related

How can I change the name of the node AEM creates when a component is first dropped on the page?

I’m trying to figure out if it’s possible to customize the name of the node AEM creates when I first drop a component on the page.
The cq:Component node where my component is defined is named “knowledge-center-question” and when I drop it, AEM creates a node named “knowledge_center_que” in the page’s node tree using its default naming logic. I would prefer for the node name to be “question” when it is dropped (but I’d rather not rename the component itself).
It seems like this kind of thing must be possible given how customizable everything is in AEM, but I’m struggling to find an answer.
Take a look at :nameHints, which can be send as POST arguments to the SlingPostServlet: https://sling.apache.org/documentation/bundles/manipulating-content-the-slingpostservlet-servlets-post.html#algorithm-for-node-name-creation
You need to write a custom Sling post processor. Sling post processor is called after a component dropped in the page. Example code :
#Component(service = SlingPostProcessor.class, immediate = true, name = "com.aem.CustomPostProcessor")
public class CustomPostProcessor implements SlingPostProcessor {
#Override
public void process(SlingHttpServletRequest request, List<Modification> modifications) throws Exception {
if (accepts(request)) {
final Resource resource = request.getResourceResolver().getResource(request.getResource().getPath());
// Your logic
modifications.add(Modification.onCreated(resource.getPath()));
}
}
protected boolean accepts(SlingHttpServletRequest request) {
return "/my/resource/type".equals(request.getResource().getResourceType());
}
}

MVC CORE 2.0.0 run c# code on every page

I need to run some c# code each time any page based on _layout.cshtml is viewed. I don't want to put something in every controller.cs file, just something central like you used to have in ASP.NET's MasterPage.cs
Can't get this
Run a method in each request in MVC, C#?
or this
#Html.Action in Asp.Net Core
to run, not sure if it's because they're not CORE 2.0.0, I just get a lot of compilation errors. All I want to do is be able to run some code like this
public class myClass {
public static bool returnTrue() {
return true;
}
}
every time each page is loaded.
You can accomplish this with an action filter
public class GlobalFilter : IActionFilter{
public void OnActionExecuting(ActionExecutingContext context) {
//code here runs before the action method executes
}
public void OnActionExecuted(ActionExecutedContext context) {
//code here runs after the action method executes
}
}
Then in the Startup.cs file in the ConfigureServices method you wire up the ActionFilter like so:
services.AddScoped<GlobalFilter>(); //add it to IoC container.
services.AddMvc().AddMvcOptions(options => {
options.Filters.AddService(typeof(GlobalFilter)); //Tell MVC about it
});
Then you can place code in this ActionFilter which can run before every action method and you can place code in it to run after every action method. See code comments.
Through the context parameter you have access to the Controller, Controller Name, Action Descriptor, Action Name, Request object (Including the path) and so on, so there is lots of info available for you to determine which page you want to execute the code for. I'm not aware of a specific property that will tell you if the page is using _layout.cshtml but you could probably deduce that based on the other properties I mentioned.
Enjoy.
Filter would also work, but the correct way to go in .Net Core is Middleware. You can read more about it here.
If it's something simple as your example, you can go with the first examples on the link like:
app.Use(async (context, next) =>
{
returnTrue();
await next.Invoke();
});
Let me know if it helped!

How to create a kentico form that does not store the response

Is there any way in Kentico to have a user submit a form and then email the response but not actually save the answer to the related table?
As mentioned the emails from Kentico rely on the record being written to the DB before they trigger. Furthermore (unless I'm just unlucky) the only values you have access to are those stored in the table. I had thought that maybe you could mark the offending fields as Field without database representation, but sadly, the fields you may want will all be null - so best not to go down that route.
I took a slightly different approach to #trevor-j-fayas in that I used the BizFormItemEvents.Insert.Before event so that there is no trace of any log. It's a short hop from there to make use of an email template to make things look good. So my code looked as follows:
using CMS;
using CMS.DataEngine;
using CMS.EmailEngine;
using System;
[assembly: RegisterModule(typeof(FormGlobalEvents))]
public class FormGlobalEvents : Module
{
public FormGlobalEvents() : base("FormGlobalEvents")
{
}
protected override void OnInit()
{
CMS.OnlineForms.BizFormItemEvents.Insert.Before += Insert_Before;
}
private void Insert_Before(object sender, CMS.OnlineForms.BizFormItemEventArgs e)
{
var email = new EmailMessage();
email.From = e.Item.GetStringValue("ContactEmail", "null#foo.com");
email.Recipients = "no-reply#foo.com";
email.Subject = "Test from event handler (before save)";
email.PlainTextBody = "test" + DateTime.Now.ToLongTimeString();
EmailSender.SendEmail(email);
e.Cancel();
}
}
To me, it seems cleaner to not insert the record in the first place than delete it, but obviously that autoresponder etc. will only kick in automatically if you do save the record, so the choice is yours and ultimately depends on your preference.
Well, there's a couple different options, but the easiest is to simply delete the record after it's inserted. Use the Global Event Hooks to capture the BizFormItemEvent insert after, if it's your form, then delete it. Below is for Kentico 10:
using CMS;
using CMS.DataEngine;
using CMS.Forums;
using CMS.Helpers;
using CMS.IO;
using System.Net;
using System.Web;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomLoaderModule))]
public class CustomLoaderModule : Module
{
// Module class constructor, the system registers the module under the name "CustomForums"
public CustomLoaderModule()
: base("CustomLoaderModule")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
CMS.OnlineForms.BizFormItemEvents.Insert.After += BizFormItem_Insert_After;
}
private void BizFormItem_Insert_After(object sender, CMS.OnlineForms.BizFormItemEventArgs e)
{
switch(e.Item.BizFormInfo.FormName)
{
case "YourFormNameHere":
e.Item.Delete();
break;
}
}
}
The other option would be to clone and modify the Online Form Web part to take the information, manually call the email and cancel the insert, but that's a lot of work when this is quicker.
Yes and no. The record is stored before the email notifications and autoresponders are sent out. Your best bet for this is to create a custom global event handler for the form submission(s) using the BizFormItemEvents.Insert.Before. This will call the event before the actual record is stored in the database. You can then cancel out of the event (which will not store the record) and send your email manually.
Handling global events
BizFormItemEvents Events

I want a custom attribute to be fired automatically without writing that on the web api method

I want a custom attribute to be fired automatically without writing that on the web api method.
What is the way I can achieve that?
Let us say for example you have an action filter attribute
public class MyApiActionFilterAttribute : FilterAttribute {
//...
}
With that you can assign it to the class or action depending on how you want it to be used
public class MyApiController : ApiController {
[MyApiActionFilter]
public IHttpActionResult MyAction() {
return Ok();
}
}
This applies to this action only.
But, if you wanted it to be applied on all actions (globally) within the web API, you would need to add it to the configuration.
GlobalConfiguration.Configuration.Filters.Add(new MyApiActionFilterAttribute ());
This is normally done at startup web configuring the web API.
Note that in doing the above, the filter will be applied to all requests.

GWT detect browser refresh in CloseHandler

I have a GWT application and I want to run some code when the user leaves the application to force a logout and remove any data etc.
To do this I am using a CloseHandler and registering it using Window.addCloseHandler.
I have noticed that when the refresh button is clicked the onClose method is run but I have been unable to differentiate this event from a close where the user has closed the browser. If it is a refresh I do not want to do the logout etc, I only want to do this when the user closes the browser/tab or navigates away from the site.
Does anybody know how I can do this?
There is no way to differentiate the 'close' from 'refresh'. But, you can set a cookie that holds the last CloseHandler call time and check, when loading the module, if this time is old enough to clean the information before showing the page.
You can do that with the folowing utility class (BrowserCloseDetector). Here is an example using it on the onModuleLoad.
The test lines:
#Override
public void onModuleLoad() {
if (BrowserCloseDetector.get().wasClosed()) {
GWT.log("Browser was closed.");
}
else {
GWT.log("Refreshing or returning from another page.");
}
}
The utility class:
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
public class BrowserCloseDetector {
private static final String COOKIE = "detector";
private static BrowserCloseDetector instance;
private BrowserCloseDetector() {
Window.addWindowClosingHandler(new Window.ClosingHandler() {
public void onWindowClosing(Window.ClosingEvent closingEvent) {
Cookies.setCookie(COOKIE, "");
}
});
}
public static BrowserCloseDetector get() {
return (instance == null) ? instance = new BrowserCloseDetector() : instance;
}
public boolean wasClosed() {
return Cookies.getCookie(COOKIE) == null;
}
}
Have you tried
<BODY onUnload = "scriptname">
in your gwt hosting/launching html file?
I am thinking that if you defined a map "hash" (i.e. a javascript pseudo hash) in the hosting file and then accessed the "hash" in GWT through Dictionary class, you could update values in that hash as the user progresses through the gwt app. Which means, your programming style would require you to log milestones on the user's progress onto this map.
When the user closes the browser page, the onunload script of the launching html page would be triggered. That script would access the map to figure out what needs to be updated to the server, or what other url to launch.
I am intereted too if someone got a solution (GWT/java side only).
Maybe we can do it with HistoryListerner ?
1-set a flag for your current viewing page.
2-when ClosingHandler event, launch a "timeout" on server-side (for example 10s)
3-if during this time your got a massage from HistoryListerner with the same last flag so it was just a refresh.
of disconnect if timer is over...
Is not a good solution but I think it is easy to do... If someone have a better one...