After i have installed DekiWiki for our internal purposes on eBesucher, i realized, that it do not support Email-Notification for the Watchlist. It has only the option to get the notifications as RSS-Feed. Well, ok, this might not be the problem. Why not? Thunderbird supports RSS-Feeds, so i set it up to get my Watchlist as RSS. But what i did not know: you have to be logged in, to view the watchlist. This means that only Firefox can read my RSS-Watchlist properly.
After that some using of google, i found an api-Link for the feed, that handles the authentication via standard-HTTPauth. This is something like this: http://yourwiki/@api/deki/site/feed?title=Special:Watchlist
So now i could add the Watchlist in my Thunderbird. But what’s this? The messages seemed broken: they only said that some page has been changed. But without the changes really to be included. At first, i thought, it was a Thunderbird-Problem. But after some testing, I found out, that the feed was only 6kb unstead of 13kb. Why that? I think there is a bug in the DekiWiki-Permissionsmangement, the API-HTTPauth does not give me the full view permissions. It is still necessary to pass the authorisation-cookie (authtoken) to get the full feed.
So to summ up, I can not use any RSS-Feed-Reader other than my browser. Firefox can view the feed properly, but there is no notification feeling. And rss2email doesn’t work with this too.
That’s why i’ve spent about a day on writing a php-script to forward the messages from this tricky feed to email properly. And i would like to share this. So let’s start!
Here is the Part that handles RSS and Email:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 | <?php /** * DekiReader * is a class for getting instant email notifications with DekiWiki, if someone * changes a site in your Watchlist * * This script is free to use for private and commercial purposes * Author: Evgeny Anisiforov * mailtO: jeff at ebesucher point de * * I spend a whole day on writing this, so * Please just leave a comment in my blog, if you use this. ;) */ /** * The most problem about getting notifications is that DekiWiki requires us * to be logged in (with a cookie) to be able to view the full rss feed * of changes (including changed things) * This is a big problem, as the most rss read does not have such function. * This script emulates a login for each user to get the auth cookie * and then sends the contents of the RSS-feed to the specified email-address * It also takes care of marking old messages as read, so your users won't * get notifications more than one time * * The best practice would be to use a cronjob to start DekiReader every X minutes. * like this: * / 10 * * * * cd /www/Cron_Jobs/DekiReader; nice php notifyfromdb.php * notice: this file has only the class definitions, of cource you need a script * to create an object of DekiReader and pass the userdata to it. * */ /* * this script needs the PEAR-packages "http_client" and "http_request" */ require_once "HTTP/Request.php"; require_once "HTTP/Client.php"; define('ERROR_DEKIWIKI_WRONG_CREDENTIALS', 'ERROR_DEKIWIKI_WRONG_CREDENTIALS'); define('ERROR_WEB_SERVICE', 'ERROR_WEB_SERVICE'); /* ------- Cookie's creation for Deki Wiki ------- */ class DekiCookie { public $url = "http://wiki.ebesucher.in"; /** thanks to kurdte from: http://wiki.developer.mindtouch.com/MindTouch_Deki/Specs/Authentication_Providers */ public function getAuthToken($login, $password) { /* Request a value for the user's cookie */ $url = $this->url."/@api/deki/users/authenticate/"; $req =& new HTTP_Request($url); $req->setBasicAuth($login, $password); $response = $req->sendRequest(); if (!PEAR::isError($response)) { $output=$req->getResponseBody(); /* Authentication proccess : if the response contains 401 authentication failed, the user is not registered */ if(strpos($output,"authentication")==0 && strpos($output,"401")==0) { //$cookie_deki=$req->getResponseCookies(); return $output; //setcookie("authtoken",str_replace("\"","",$cookie_deki[0]['value']),time()+3600, '/'); } else { $error = ERROR_DEKIWIKI_WRONG_CREDENTIALS; } } else { $response->getMessage(); $error = ERROR_WEB_SERVICE; } } } class DekiReader { /** array with the date of users to check every item must contain: username, password every item may contain: authtoken */ public $userdata; public $url; public $emaildomain; private $domain; /** Directory to store cache-Data (what feed-messages did we * allready read? */ public $cachedir = "cache/"; /** * creates a DekiReader * $emaildomain = the domain for sender-address * if not given, we'll take the domain */ public function DekiReader($domain, $userdata, $emaildomain = false) { $this->domain = $domain; $this->url = $domain."/index.php?title=Special:Watchlist&feed=rss"; $this->userdata = $userdata; if (!$emaildomain) { //delete http:// or https:// at the beginning $d = eregi_replace('^http://', '', $domain); $d = eregi_replace('^https://', '', $d); $this->emaildomain = $d; } else { $this->emaildomain = $emaildomain; } } /** * Returns the proper RFC 822 formatted date. * @return string */ public function RFCDate($timestamp) { $tz = date("Z", $timestamp); $tzs = ($tz < 0) ? "-" : "+"; $tz = abs($tz); $tz = ($tz/3600)*100 + ($tz%3600)/60; $result = sprintf("%s %s%04d", date("D, j M Y H:i:s", $timestamp), $tzs, $tz); return $result; } /** convert the Dateformat of the Feed to a Timestamp */ public function strangeDate2Timestamp($date) { $regs = array(); preg_match('~((\d+)-(\d+)-(\d+))T((\d+):(\d+):(\d+))Z~is', $date, $regs); //date and time $d = $regs[0]; $t = $regs[1]; return mktime($regs[6], $regs[7], $regs[8], $regs[3], $regs[4], $regs[2]); } /** read the message cache for a user */ public function getCache($username) { //we use username and feed-url to cache read messages $cache = $this->getCacheFilename($username); //read the cache $contents = file_exists($cache) ? file_get_contents($cache) : ''; return $contents; } //get the filename of the message cache for a username public function getCacheFilename($username) { return $this->cachedir.'rss_' . md5($username."@".$this->url) . '.txt'; } //add something to messagecache public function addToCache($username, $url) { $handle = fopen($this->getCacheFilename($username), 'a'); fwrite($handle, $url . "\r\n"); fclose($handle); } public function run() { $deki = new DekiCookie(); header('Content-Type: text/plain'); foreach ($this->userdata as $user) { echo "trying to get ".$this->url." for user ".$user['username']."\n"; $req = new HTTP_Request($this->url); $req->setMethod(HTTP_REQUEST_METHOD_GET); //do we have an authtoken? if (!$user['authtoken']) { $user['authtoken'] = $deki->getAuthToken($user['username'], $user['password']); echo "estimated authtoken for user ".$user['username'].": ".$user['authtoken']."\n"; } $req->addCookie("authtoken", $user['authtoken']); $req->sendRequest(); $rss = $req->getResponseBody(); $xml = new SimpleXMLElement($rss); $cache_contents = $this->getCache($user['username']); //some output echo 'Feed: ' . (string)$xml->link['href'] . "\r\n"; //iterate the items in the feed foreach ($xml->entry as $item) { $url = (string)$item->link['href']; $id = (string)$item->id; //did we allready read this? if (strpos($cache_contents, $id) !== false) { echo " read: $id\r\n"; continue; } else { echo " unread: $id\r\n"; } // The data from the feed $authorname = (string)$item->author->name; //delete scopes for better compartibility $authorname = str_replace("(", "", $authorname); $authorname = str_replace(")", "", $authorname); //here we don't have a read possibility to get the email of //the author, we just simulate it by adding our domain name //to the username (or you could write a function that does that better..) $author = '"'.$authorname.'"'."<".$authorname."@".$this->emaildomain.">"; $title = (string)$item->title; $link = (string)$item->link['href']; $pubDate = (string)$item->published; //convert the date from the feed to a compartible date format //for the emails, so that we can see the correct date of //the posting in our email program $updatedtimestamp = $this->strangeDate2Timestamp((string)$item->updated); $updated = $this->RFCDate($updatedtimestamp); //we want all tags between <summary> and </summary>, so just //iterate through the children $description = ""; foreach ($item->summary->children() as $child) { $description .= $child->asXML(); } $to = $user['email']; $mail = " <html><head></head><body> Page: <a href=\"$url\">$title</a> $description </body></html>"; mail($to, '[Wiki] ' . $title, $mail, "From: $author" ."\nContent-Type: text/html; charset=utf-8" ."\nDate: ".$updated ); // we have send a notification for this item, so send // write this to the cache $this->addToCache($user['username'], $id); } } } } ?> |
So now lets use this! I use remote authentication on my site, so i’ve written a small file to read user data from my auth db.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <?php //include some internal db stuff // .... //then include_once("dekireader.php"); $watch_accounts = array("jeff", "sebastian"); if (count($watch_accounts)<1) die("Please define Accounts to watch!"); $sql = "SELECT Username as username, PW as password, Email as email FROM Admins WHERE Username IN ('".implode("','", $watch_accounts)."')"; $res = mysql_query($sql); echo mysql_error(); $userdata = mysql_get_whole_result($res); $dekireader = new DekiReader('http://mywiki', $userdata, 'myemaildomain.no'); $dekireader->run(); ?> |
But you could also just select all all admins. Or hard-code userdata:
1 2 3 4 5 6 7 8 9 10 11 12 | <?php $userdata = array(array( 'username' => 'jeff', 'password' => 'secret', //'authtoken' => 'something', //you could cache authtokens to make the script faster 'email' => 'bla@bla.bla' )); $dekireader = new DekiReader('http://mywiki', $userdata, 'myemaildomain.no'); $dekireader->run(); ?> |
I did not handle using internal dekiwiki database for authorizing local users. I also did not try this. But this should be no problem after you examine the db structure of dikiwiki. Let me know, if you try this!
So now just set up a cronjob to run this script regulary, and you have a good email notification for your wiki. Like this:
* / 10 * * * * cd /www/Cron_Jobs/DekiReader; nice php notifyfromdb.php
I’m still looking forward and hope that Deki-team will soon implement Deki to support this out-of-the-box.
You can use this script for any purpose, just please leave a comment! My blog is hungry ![]()
Download the main script: dekireader.phps