Event Notification Handler


Ticket:56


Believe it or not, I wrote this code before I found out about PageWatches but I think my approach is a little different.

Basically, I wanted something that would email people in my office whenever somebody posted a comment on a page of interest. I thought I would make it a little more robust however. This should be a framework that will allow wikka to automatically react to a variety of page events (i.e. commenting a page, editing a page etc) and trigger some response (i.e. emailing a user, sending an http request to a server etc.)

This isn't finished, yet it is currently running in my office, so I know it works.

Steps:
  1. Create new event watching table.
  1. Create a handler to register an event for a page to watch.
  1. Create a response function (i.e. email notification).
  1. Add code to look for and process a page event. Then call a response function.
  1. Make handler easily accessible for users.

1.) Create Table


CREATE TABLE `wikka_watches` (
  `page_tag` VARCHAR(75) NOT NULL,
  `watcher` VARCHAR(75) NOT NULL,
  `comment` ENUM('Y','N') DEFAULT 'N' NOT NULL,
  `edit` ENUM('Y','N') DEFAULT 'N' NOT NULL
)
TYPE = myisam;

ALTER TABLE `wikka_watches` ADD UNIQUE  (`page_tag`,`watcher`)

ALTER TABLE `wikka_watches` ADD INDEX  (`page_tag`)

ALTER TABLE `wikka_watches` ADD INDEX  (`watcher`)


This will create a table that will store a page_tag and watcher pair. The watcher isn't restricted to being a username. It could be the name of a wikipingserver or something like that. Each column after that corresponds to a particular page event with a simple indication of whether or not that event is being watched for.

2.) Create 'addwatch' handler


Create a file called addwatch.php in your handlers directory. Add this code:

<?php

/**
* Creates a watch on this page for a watcher.
*
* Usage: append /addwatch to the URL of the page
*
* This handler registers a watch in the database on this page
* for a watcher.  Watches can be used to generate events when
* certain things are done to a page. (i.e. email a user when a page
* is commented on.)
*
* @package Handlers
* @subpackage
* @name addwatch
*
* @author {@link http://wikka.jsnx.com/RyeBread RyeBread} - original idea and code - Dec.06.2005
* @copyright    Copyright © 2005, Ryan Jarvis
* @license      http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @version 0.1
* @since Wikka 1.1.6.X
*
* @todo
* 1. Allow handler to take in params specifying what kind of watch should be made
* 2. Enable setting of watcher that isn't a user (i.e. a wikiping server).
*/


do {
   
    if (!$this->page) {
        $this->SetRedirectMessage("Found no page for this handler.");
        break;
    }
   
    if (!$this->GetUser()) {
        $this->SetRedirectMessage("You must be registered to add a watch.");
        break;
    }
   
    //TODO: get type of watch from a param
    //passed into the handler.
    //
    //get type of watch
    $type = "comment";
   
    //check if watch type is valid
    $validity = $this->Query("SHOW COLUMNS FROM " . $this->config["table_prefix"] . "watches LIKE '" . $type . "'");
    if (mysql_num_rows($validity) == 0) {
        $this->SetRedirectMessage("Watch type is invalid.");
        break;
    }
   
    //get page name
    $tag = $this->GetPageTag();
   
    //TODO: optionally specify the id of the
    //watcher instead of assuming user name.
    //
    //get watcher
    $watcher = $this->GetUserName();
   
    //register watch in database
    $existing = $this->Query(
        "SELECT * FROM " . $this->config["table_prefix"] . "watches " .
        "WHERE page_tag = '" . mysql_real_escape_string($tag) . "'" .
        "AND watcher = '" . mysql_real_escape_string($watcher) . "'");
   
    if (mysql_num_rows($existing) == 0 ) {
        $this->Query(
            "INSERT INTO " . $this->config["table_prefix"] . "watches SET ".
            "page_tag = '" . mysql_real_escape_string($tag) . "', " .
            "watcher = '" . mysql_real_escape_string($watcher) . "', " .
            $type . " = 'Y'");
       
        $this->SetRedirectMessage("You are now watching this page for " . $type . "s.");
        break; 
    }
   
    if (mysql_result($existing, 0, $type) == 'Y') {
        $this->SetRedirectMessage("You are already watching this page for " . $type . "s.");
    } else {
        $this->Query(
            "UPDATE " . $this->config["table_prefix"] . "watches SET ".
            "page_tag = '" . mysql_real_escape_string($tag) . "', " .
            "watcher = '" . mysql_real_escape_string($watcher) . "', " .
            $type . " = 'Y'");
        $this->SetRedirectMessage("You are now watching this page for " . $type . "s.");
    }
   
    mysql_free_result($existing);
   
} while (0);

$this->Redirect($this->Href());

?>


As it stands right now, when a registered user invokes this handler on a page, the wikka_watches table will be updated to indicate that this user wants to be notified whenever this page is commented on.

3.) Create 'notify' base function


In wikka.php, I added this function at line 972 before MAINTENANCE

    //COMMUNICATION
    function Notify($to = "", $subject = "", $body = "", $altbody = "")
    {
    <insert your specific mailing code here>
    }


Obviously, how you send mail is dependent on your server setup. I don't use the default mail() function. Instead, I have phpmailer setup, and I use it on an SMTP configuration. If somebody wants to see what I wrote for this function that uses phpmailer, let me know.

Also, it should probably be called 'NotifyOnEmail' as there might be additional notify functions created that belong to this family.

4.) Invoke Event Processing somewhere


Keeping in mind that I want people to be notified of comments made on pages, I decided to invoke the event processing in the 'addcomment.php' action.

Firstly, I have no idea if this is the best place for it to go (as opposed to being added directly in the SaveComment() function). Secondly, there needs to be a generic event-processing-wrapper of some kind that takes a callback function (such as notify) as a parameter. I'm working on that.

Add the following to 'addcomment.php', line 18, right after STORE NEW COMMENT

        //trigger watches
        $watches_table = $this->config["table_prefix"] . "watches";
        $users_table = $this->config["table_prefix"] . "users";
        $watch_query = "SELECT " . $users_table . ".email " .
            "FROM " . $watches_table . "," . $users_table . " " .
            "WHERE " . $watches_table . ".page_tag = '" . $this->tag . "' " .
            "AND " . $watches_table . ".watcher = " . $users_table . ".name";
        $watches = $this->LoadAll($watch_query);
        foreach ($watches as $email) {
            if ($email["email"] == '') {
                continue;  
            }
       
            $this->Notify($email["email"], $this->tag . " commented by " . $this->GetUserName(), $body);
       
        }


5.) Make handler visible


Obviously, I want to make it easy for my users to add watches, so I just hacked the following. It adds a link to the footer.

Add the following to footer.php, line 5 after the 'Edit Page'

echo $this->GetUser() ? "<a href=\"".$this->href("addwatch")."\" title=\"Click to watch this page\">Watch page</a> ::\n" : "";


Now I don't really want to hack footer directly, plus, I want to be able to support adding watches of different types, so I need to eventually construct a separate menu altogether.


Conclusion


Whenever a user in my wiki comes across a particular page of interest, he or she can click on the "Watch page" link at the bottom, and it will record the request to be notified. Thereafter, whenever somebody leaves a comment on that page, the user will receive an email containing the comment in the body of the message.

TODO:



Comments/feedback highly desired. Thank you.
:)


CategoryUserContributions
There are no comments on this page.
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki