Notification of Site Changes

Permalink 6 users found helpful
How can we be e-mailed a notification whenever an Administrator makes changes on the website? A client of ours would like a notice sent to them whenever one of their other Administrators have made a change to the site.

jedininja
View Replies: View Best Answer
Mnkras replied on at Permalink Reply
Mnkras
You can use events and hook into the on_page_approve event to send an email.

If you would like I can build it for you for some $.

Mike
jordanlev replied on at Permalink Reply
jordanlev
Sorry Mike, beat you to it (I didn't see your offer before I posted) :P
Mnkras replied on at Permalink Reply
Mnkras
Haha no worries :)
On Jul 19, 2011 1:12 PM, "Concrete5 Community" <[email protected]>
wrote:
jordanlev replied on at Permalink Reply 1 Attachment
jordanlev
There is no built-in functionality to do that but you could code up something using events (http://www.concrete5.org/documentation/developers/system/events... )...

Download the attached file and unzip it, then place it in your site's top-level "libraries" directory (make sure you're just placing the file called "change_notifications.php", not the ZIP file and not an entire folder). You'll also want to edit that file to change the email "To" and "From" addresses (at the top of the attached file).

Then create a new file called "site_events.php" and add it to your top-level "config" directory. In that file, put the following code:
<?php
Events::extend('on_page_add', 'ChangeNotifications', 'on_page_add', 'libraries/change_notifications.php');
Events::extend('on_page_update', 'ChangeNotifications', 'on_page_update', 'libraries/change_notifications.php');
Events::extend('on_page_delete', 'ChangeNotifications', 'on_page_delete', 'libraries/change_notifications.php');
Events::extend('on_page_move', 'ChangeNotifications', 'on_page_move', 'libraries/change_notifications.php');
Events::extend('on_page_duplicate', 'ChangeNotifications', 'on_page_duplicate', 'libraries/change_notifications.php');
Events::extend('on_page_version_approve', 'ChangeNotifications', 'on_page_version_approve', 'libraries/change_notifications.php');


I haven't tested this out so there may be some problems -- let me know if you run into any.

-Jordan

UPDATE: If you're using Concrete5.4.2 or later, scroll further down to see an updated solution that works for all situations.
jordanlev replied on at Permalink Reply
jordanlev
FYI: I just learned that while the technique I used will alert you if/when someone "Publishes" the changes, it won't alert you if they just "Preview" them. This is due to the way the Concrete5 even system is built and to work around it would require some custom coding (and if this is an important feature to you, Mnkras is definitely a Concrete5 expert so I'd talk to him about it for sure).
olliephillips replied on at Permalink Reply
olliephillips
Jordan thanks for this, useful to see. I wondered if you knew if the on_page_version_approve event passes two objects i.e. approved page and previous page. Similar to the how page duplicate event passes two objects.

The docs say "passes an additional page object", but I've never been clear.
Mnkras replied on at Permalink Reply
Mnkras
Here is an example object passed by the on_page_version_approve event, there is only 1 object returned:

Page Object
(
[blocksAliasedFromMasterCollection:protected] => 
[cID] => 136
[attributes:protected] => Array
(
)
[error] => 
[pkgID] => 0
[cPointerID] => 0
[cPointerExternalLink] => 
[cPointerExternalLinkNewWindow] => 0
[cFilename] => 
[cDateAdded] => 2011-07-02 18:25:17
[cDisplayOrder] => 0


Check out my event tester, it logs all items returned by events you specify,https://github.com/Mnkras/Event-Tester/...

Mike
Mnkras replied on at Permalink Reply
Mnkras
I would also check out the
on_page_version_add event, not sure when that was added,
olliephillips replied on at Permalink Reply
olliephillips
Thanks Mike - was just about to ask you how you got at that then I saw your link. I will indeed check that out.
jordanlev replied on at Permalink Reply
jordanlev
I searched 5.4.1.1 for all "on_page_" strings and didn't see this one -- I presume it's for 5.4.2 (which is awesome that it's in there). This has been an enlightening discussion for me!
jedininja replied on at Permalink Reply
jedininja
Wow! Thank you, it worked with a slight amount of tweaking. I was thrilled by the quick response. I was able to get our client appeased in the same day they requested the feature.

Best Wishes,
Deen Foxx
jordanlev replied on at Permalink Reply
jordanlev
You're welcome! If you don't mind, can you share what needed to be tweaked? (So that other people with this issue in the future can see the code that works)
chrismodlao replied on at Permalink Reply
chrismodlao
Nice work.
I wonder if it will be possible that the user (people looking at the website) can be advise if any changes on the pages.

I mean :
- 1: they subscribe entering their email.
- 2: email send dynamically to the USER database
- 3: the define('CHANGE_NOTIFICATION_EMAIL_TO', XXXXX) in change_notifications.php is dynamically filed in

Hope i'm clear.

Thanks in advance

Chris
jordanlev replied on at Permalink Reply 2 Attachments
jordanlev
UPDATE: In the new Concrete5.4.2, there is now an event for when pages are changed but not published, so a complete solution is now possible.

Attached are 2 files. Unzip them, and place the "change_notifications.php" file in your site's top-level "libraries" directory, and place the "site_events.php" file in your site's top-level "config" directory.

Then edit the "change_notifications.php" file and put in the appropriate email address that you want notifications sent to (up at the top of that file).

-Jordan
Mnkras replied on at Permalink Reply
Mnkras
Beware of spam ;)
campbell replied on at Permalink Reply
campbell
Hey, Jordan.

Those files are really helpful, but I do want to ask about the "from" email address.

You've got "define('CHANGE_NOTIFICATION_EMAIL_FROM', '[email protected]');" included in the change_notifications.php file, but I don't understand what address should go in there. If c5 is automatically generating this email, is the "from" necessary?

Maybe I don't understand fully how email in c5 works. If I'm running a test site on localhost, how would I need to set up the site's email ability to test this change notification email functionality?

(Sorry for the newb questions)

John

EDIT: Just to add, I have placed those files in the appropriate folders and made some page changes, but nothing is showing up in the logs. I'll get notification in the logs that c5 attempted to send an email when I send a private message between accounts, but nothing when I make changes to pages. Am I doing something wrong?
jordanlev replied on at Permalink Reply
jordanlev
C5 is generating the email but C5 is just a piece of software and hence doesn't have its own email address. There is actually nothing special about "from" addresses in emails -- they are entirely made-up just like "to" address and the subject. It just so happens that 99.9% of the time your email program uses your own email address as the "from" address so you never pay attention to this. But whenever you have a web application that is sending out emails, it always needs to be told explicitly what the "from" address is.
There are some blocks and other functionality in C5 that don't ask for a "from" address, but it's just using the email address of the admin account in that case.

As for your other question about the emails not being logged -- are you receiving the emails at all? I'm not sure why those wouldn't show up -- I would double-check in your dashboard, I think Sitewide Settings -> Email, make sure it's enabled for the site.

-Jordan
campbell replied on at Permalink Reply
campbell
Ah, thanks for the clarification about the from address. Out of curiosity, is there a way to set the file up to pull the email address for the user that made the changes referenced in the change notification?

For example, say I have a user Bob that is making changes to a few pages. Is it possible to have the emails generated pull Bob's email address from his user information and include it as the "from" in the change notification emails? Likewise, if user Jim comes in and makes other changes, the emails would contain his email as the "from"?

In my Sitewide Settings > Email, I've got Default PHP Mail Function selected, and in the Mail Importers section, the only one I have listed is Private Message (which is enabled). I don't see a way to add another mail importer (if that's what I would need to do). And I don't currently have a mailserver actually set up (I've just created a test site on localhost), so I'm relying on the logs to tell me if the system is trying to send an email or not.
jordanlev replied on at Permalink Reply
jordanlev
The code would have to be modified to make the from address match the author of the change (I think you might be able to pull that info out of the page object that's passed to the event handler in change_notifications.php). Would probably take a bit of time so unfortunately it's not something I am able to do for you right now.

As for the email problems, I'm not really sure about that -- should work just fine as this code is using the built-in C5 emailing functionality. Do other system emails work (like if you ask to reset your password, or if you add a Form block to a page and put in an email address to be notified of submissions and then submit a test form?). I think this is a fairly common issue so I'd search the forums for other threads that might help solve it.
campbell replied on at Permalink Reply
campbell
Thanks for the clarification and for taking the time to help out a newbie, Jordan. I'm not worried about actually modifying the code currently, but more interested in seeing if that functionality would even be possible (I'm still trying to sell my manager on using c5 for our needs and the more I know and more functionality I can assure her of, the better).

Regarding the email issues, I haven't yet tried to take any actions that would generate system emails, so I'll start down that path and see what I can turn up. Thanks again for all the info and direction.
jordanlev replied on at Permalink Reply
jordanlev
UPDATE: Just realized I think there was a bug in my code. I've updated the file -- try re-downloading the attachment from that post up above and seeing if that works any better (you only need to replace the change_notifications.php file, not site_events.php).
campbell replied on at Permalink Reply
campbell
Hi, Jordan.

I checked my system emails (for forgotten passwords, and for forms that notify someone via email of responses) and both of them show in the log (errors, obviously, saying that SMTP authentication is required).

But I'm still not getting anything in the logs when I add or change a page. Just FYI... might be something worth paying attention to.

Thanks again for the info and assistance. I'm going to dive back into the forums and see if I can learn more. :)

UPDATE: This is bizarre. Nothing was showing in the logs when I would add a page, update a page, anything. So I installed mnkras' Event Tester addon to test the events and make sure they were firing. I added and updated a page... nothing. Then in the Event Tester, I added the "on_page_add" event (even though it already exists as a default in c5) and went through the process again. Boom. Suddenly, the logs show email attempts for the add, update, and approve page events, just as defined in your files, Jordan.

I'm not sure what happened, but I'm glad it did. Now to try and set up a mailserver on my localhost (maybe).
jordanlev replied on at Permalink Reply
jordanlev
That is strange. Just to be sure -- did you re-download the change_notifications.php file I posted up above (because I just updated it to fix a bug that prevented it from working)?

Maybe the system had cached the prior version or something and didn't register the change for a bit?

Oh well, glad it's working now. Best of luck with your explorations.

-Jordan
campbell replied on at Permalink Reply
campbell
Yeah, I did grab the new version of the change notifications file. Thanks for the update. :)
jb1 replied on at Permalink Reply
jb1
Hey Jordan, it would be great if you could write this up a quick "how to" (if you haven't already). Its a super useful technique that would benefit lots of folks.
jordanlev replied on at Permalink Best Answer Reply
jordanlev
olliephillips replied on at Permalink Reply
olliephillips
Jordan. This will be very useful to a lot of people - nice how-to! When I posted the question re collection versions being passed above my thinking was that this would be killer code if it sent the output of htmldiff.py in the email's body. Not only would you know who had updated, but what they had done?

Without the new page version object and previous page version object I'm not sure how to accomplish this.

Anyone any thoughts?
jordanlev replied on at Permalink Reply
jordanlev
You should be able to get the previous page object from the current one (which is passed to the event).

Check out the "VersionList" class as the bottom of concrete/models/collection_version.php, for example. Might be other useful functions in concrete/models/collection.php and concrete/models/page.php as well.
olliephillips replied on at Permalink Reply
olliephillips
Thanks for pointing me in right direction Jordan - will check that out.

Sent from my iPhone
campbell replied on at Permalink Reply
campbell
Hey, Jordan.

I finally have this functionality working (though I'm still waiting on my company's IT to help out with the Exchange issues, it works fine via Gmail). I've got a new question, though.

In the files that you provided, you have all change notifications in a single file (and all of the ChangeNotifications class). That's clearly useful if you want to use the same email header and to/from addresses when notification emails are generated. But I'd like to be able to use different email headers for different events.

I assume that I can create individual change notification files for individual events (for example, an add_page_notification.php file and an approved_page_notification.php file). Likewise, I also assume that I would have to edit the site_events.php file to point to those individual files - something like this:

Events::extend('on_page_add', 'ChangeNotifications', 'on_page_add', 'libraries/add_page_notifications.php');


My question is whether I would have to create a new class in each of those individual files, or if I could continue to use the ChangeNotifications class? If I had to create the new class (e.g., "AddPageNotifications"), would that name go in the appropriate event line in the site_events.php file - as in the following?

Events::extend('on_page_add', 'AddPageNotifications', 'on_page_add', 'libraries/add_page_notifications.php');


Sorry if these are beginner-type questions, but the only PHP I know is what I've seen in these forums over the last 2 weeks. :)
jordanlev replied on at Permalink Reply
jordanlev
No need to apologize for asking questions -- that's what the forums are for! (And I applaud you for making an effort).

If you look in the change_notifications.php file, you'll see a bunch of repetitive code that responds to the 6 or 7 different events, and they all call another function down at the bottom of the file called "send". The "send" function gets the message passed to it by each event but always uses the same to, from, and subject.
But we can modify the send function so in addition to getting passed the message, it also gets passed a different to, from, and subject for each call. Then you can manually set those for each different event.

Here's the code (just overwrite the entire contents of the change_notifications.php file with this code):
<?php defined('C5_EXECUTE') or die("Access Denied.");
class ChangeNotifications {
    function on_page_add($page) {
        ChangeNotifications::send($page, 'A new page has been added to your website.', [email protected], [email protected]', [email protected]', 'Website Updated!');
    }
    function on_page_update($page) {
        ChangeNotifications::send($page, 'A page has been updated on your website.', [email protected], [email protected]', [email protected]', 'Website Updated!');
    }
    function on_page_delete($page) {
        ChangeNotifications::send($page, 'A page has been deleted from your website.', [email protected], [email protected]', [email protected]', 'Website Updated!');
    }
    function on_page_move($page, $old_parent_page, $new_parent_page) {
        ChangeNotifications::send($page, 'A page has been moved on your website.', [email protected], [email protected]', [email protected]', 'Website Updated!');
    }
    function on_page_duplicate($new_page, $current_page) {

(note that you'll want to click the little "View entire code block" at the bottom right of that code to see the entire thing)
campbell replied on at Permalink Reply
campbell
Very cool, Jordan. I see the logic now.

As I put this code into place and tested it, I did come across something else I'd like to fix, if possible.

My users won't have permission to approve edits, so they can't publish documents. This impacts the URL that is included in the email message to the supervisors. For an existing document, it's no big deal since the existing document has been published once before and has its URL. But if they are publishing a new document, the only URL included in the body of the message is "http://localhost/concrete/" which does the supervisor no good if he doesn't know what document he needs to review.

Is it possible to instead pull the page name or page alias into the body of the email message? Additionally, is it possible to pull the name of the page owner (in the case of newly added pages) or the last editor of a page (in the case of edits to existing pages) into the email? If at all possible, I'd love to be able to tweak these emails to read something like...

"The (ABC123) document in the company's document library has been updated by (Jimbob) and is awaiting review. Please login to the document library and review the document."

It would be great to keep the URLs in there, but a URL just pointing to the home page of the site doesn't really help as much.
jordanlev replied on at Permalink Reply
jordanlev
Interesting... well you should be able to pull out the info you need from the $page variable in the event handler function and construct your message as needed from that. You'll need to do some experimentation yourself with this though (will be a good learning experience!).

Here's how to get the page name:
$name = $page->getCollectionName();


And here's how to get the username of the page author:
$author = $page->getVersionObject()->getVersionAuthorUserName();

Note that the above code only gets the username of the person who most-recently edited the page, not necessarily the original author of the page. I think that's what you'll want for this situation, but just in case you want to always get the very first original author of a page, you can use this code:
$author = Page::getByID($page->getCollectionID(), 1)->getVersionObject()->getVersionAuthorUserName();


Good luck!

-Jordan
campbell replied on at Permalink Reply
campbell
Where do I declare those variables? Would they be done at the top of the change_notifications.php file, or would I do it within the function itself?

Do I need to include those variables as parameters in the function? I'm reading through some tutorials on php and javascript, but haven't come across similar examples just yet.

I'll keep searching and update if/when I discover something that will work (or at least make sense to me).
jordanlev replied on at Permalink Reply
jordanlev
Within the functions themselves. Note that since this issue only applies to new pages that have yet to be published, you should only need to put these changes into the on_page_version_add function.
campbell replied on at Permalink Reply
campbell
Awesome!

Took me a bit, but I got that working, too!

Thanks again, Jordan. Your help in this has been incredible.
diorist replied on at Permalink Reply
diorist
It /would/ be a good learning experience to figure this yourself. (Kinda wish C5 Forums had a [spoiler] tag.)

To add a page title and the username of the changer to your notifications, you can modify Line 42 of change_notifications.php to:

$msg .= "\n\n" . BASE_URL . View::url($page->getCollectionPath())."\n\n Page: ".$page->getCollectionName()."\n\n Whodunnit: ".$page->getVersionObject()->getVersionAuthorUserName();
campbell replied on at Permalink Reply 1 Attachment
campbell
Hi, Jordan.

I have another question regarding the change notifications, if you have a moment to answer it.

I've discovered that the code you provided that should get the username of the person who most recently edited the page isn't quite working in the way you suggested. It's actually getting the name of the person who performed the next-to-last edits.

Apparently, on_page_version_add has two arguments... Page Object and Collection Version Object. For some reason, that code is getting the username from the Page Object (i.e., the existing author's name) instead of getting it from the Collection Version Object (i.e., the name of the person modifying the page and creating a new version). Is there a way to modify that code to check that the version is most recent before getting the username? Or maybe the code could get the name of the user that checked the collection out?

I've attached the log to hopefully illustrate what I'm talking about.

Thanks,
John
jordanlev replied on at Permalink Reply
jordanlev
Sorry John, I won't be able to put any time into this soon (swamped with client work). Hopefully someone else can help out -- you might want to try re-posting a new thread (I've noticed that in the forums sometimes people respond to brand new unanswered questions more than ones that already have a long history).

If you do get it figured out, please post back to this thread for future reference.

Good luck.

-Jordan

EDIT: For future reference, looks like John finally got this figured out. See here:http://www.concrete5.org/community/forums/chat/auto-notification-em...
Pottman replied on at Permalink Reply
I also found I had to update the site.php file with

define('ENABLE_APPLICATION_EVENTS', true);

before I started receiving email alerts... not sure this is mentioned here or in the how to.
gtrhough replied on at Permalink Reply
gtrhough
Is there a way to restrict notifications to only certain users? Example: if I am on the site doing some work, I don't want to receive a ton of emails telling me what I already know. But, if someone else is on the site doing work, I'd like it to send notifications.

Basically, I want to disable notifications for my user account.
gtrhough replied on at Permalink Reply
gtrhough
Actually just figured it out.

In the change_notifications.php file...

I loaded the 'userinfo' model, verified the 'userID' of the logged in user, wrapped the ChangeNotifications class in an 'if' statement checking that the userID was not equal to my userID. Works perfect.

<?php defined('C5_EXECUTE') or die("Access Denied.");
define('CHANGE_NOTIFICATION_EMAIL_TO', [email protected]');
define('CHANGE_NOTIFICATION_EMAIL_FROM', [email protected]');
define('CHANGE_NOTIFICATION_EMAIL_SUBJECT', 'Website Changes Made!');
   Loader::model('userinfo');  /* Loads the Concrete5 userinfo model */
   $u = new User();   /* Sets the new user to a variable */
   /* This first if statement should wrap everything that a user has to be logged in to do. */
    if ($u->isRegistered()) { 
      $ui = UserInfo::getByID($u->getUserID());   /* Gets the users info based on their userID and sets it to a variable */
      $userID = $u->getUserID();
     }
   if ($userID != 1) {
class ChangeNotifications {
    function on_page_add($page) {
        ChangeNotifications::send($page, 'A new page has been added to your website.');
INTcommunications replied on at Permalink Reply
INTcommunications
tried this and it seemed to work but when I changed a few blocks the blocks produced errors. Couldn't you just wrap the sendmail() and send if it is not the admin?
PatrickHenry replied on at Permalink Reply
PatrickHenry
I tried that and couldn't seem to get it to work. Seems a lot more elegant tho.
leotata replied on at Permalink Reply
I need to provide Admin an option to choose whether or not to send notification to users. This way Admin can notify users, only on selected info/articles and not on all updates.
How can this be achieved.