Index: trunk/extensions/CategoryWatch/CategoryWatch.php |
— | — | @@ -0,0 +1,162 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * CategoryWatch extension |
| 5 | + * - Extends watchlist functionality to include notification about membership changes of watched categories |
| 6 | + * |
| 7 | + * See http://www.mediawiki.org/Extension:CategoryWatch for installation and usage details |
| 8 | + * See http://www.organicdesign.co.nz/Extension_talk:CategoryWatch for development notes and disucssion |
| 9 | + * {{Category:Extensions|CategoryWatch}}{{php}} |
| 10 | + * @package MediaWiki |
| 11 | + * @subpackage Extensions |
| 12 | + * @author Aran Dunkley [http://www.organicdesign.co.nz/nad User:Nad] |
| 13 | + * @copyright © 2007 Aran Dunkley |
| 14 | + * @licence GNU General Public Licence 2.0 or later |
| 15 | + */ |
| 16 | + |
| 17 | +if (!defined('MEDIAWIKI')) die('Not an entry point.'); |
| 18 | + |
| 19 | +define('CATEGORYWATCH_VERSION', '0.1.0, 2008-09-03'); |
| 20 | + |
| 21 | +$wgCategoryWatchNotifyEditor = false; |
| 22 | + |
| 23 | +$wgExtensionFunctions[] = 'wfSetupCategoryWatch'; |
| 24 | +$wgExtensionCredits['other'][] = array( |
| 25 | + 'name' => 'CategoryWatch', |
| 26 | + 'author' => '[http://www.organicdesign.co.nz/User:Nad User:Nad]', |
| 27 | + 'description' => 'Extends watchlist functionality to include notification about membership changes of watched categories', |
| 28 | + 'url' => 'http://www.mediawiki.org/wiki/Extension:CategoryWatch', |
| 29 | + 'version' => CATEGORYWATCH_VERSION |
| 30 | + ); |
| 31 | + |
| 32 | +class CategoryWatch { |
| 33 | + |
| 34 | + function __construct() { |
| 35 | + global $wgHooks; |
| 36 | + $wgHooks['ArticleSave'][] = $this; |
| 37 | + $wgHooks['ArticleSaveComplete'][] = $this; |
| 38 | + } |
| 39 | + |
| 40 | + /** |
| 41 | + * Get a list of categories before article updated |
| 42 | + */ |
| 43 | + function onArticleSave(&$article, &$user, &$text) { |
| 44 | + $this->before = array(); |
| 45 | + $dbr = &wfGetDB(DB_SLAVE); |
| 46 | + $cl = $dbr->tableName('categorylinks'); |
| 47 | + $id = $article->getID(); |
| 48 | + $res = $dbr->select($cl, 'cl_to', "cl_from = $id", __METHOD__, array('ORDER BY' => 'cl_sortkey')); |
| 49 | + while ($row = $dbr->fetchRow($res)) $this->before[] = $row[0]; |
| 50 | + $dbr->freeResult($res); |
| 51 | + return true; |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * Find changes in categorisation and send messages to watching users |
| 56 | + */ |
| 57 | + function onArticleSaveComplete(&$article, &$user, &$text) { |
| 58 | + |
| 59 | + # Get cats after update |
| 60 | + $this->after = array(); |
| 61 | + $dbr = &wfGetDB(DB_SLAVE); |
| 62 | + $cl = $dbr->tableName('categorylinks'); |
| 63 | + $id = $article->getID(); |
| 64 | + $res = $dbr->select($cl, 'cl_to', "cl_from = $id", __METHOD__, array('ORDER BY' => 'cl_sortkey')); |
| 65 | + while ($row = $dbr->fetchRow($res)) $this->after[] = $row[0]; |
| 66 | + $dbr->freeResult($res); |
| 67 | + |
| 68 | + # Get list of added and removed cats |
| 69 | + $add = array_diff($this->after, $this->before); |
| 70 | + $sub = array_diff($this->before, $this->after); |
| 71 | + |
| 72 | + # Notify watchers of each cat about the addition or removal of this article |
| 73 | + $page = $article->getTitle()->getText(); |
| 74 | + if (count($add) == 1 && count($sub) == 1) { |
| 75 | + $add = array_shift($add); |
| 76 | + $sub = array_shift($sub); |
| 77 | + |
| 78 | + $title = Title::newFromText($add, NS_CATEGORY); |
| 79 | + $message = wfMsg('categorywatch-catmovein', $page, $add, $sub); |
| 80 | + $this->notifyWatchers($title, $user, $message); |
| 81 | + |
| 82 | + $title = Title::newFromText($sub, NS_CATEGORY); |
| 83 | + $message = wfMsg('categorywatch-catmoveout', $page, $sub, $add); |
| 84 | + $this->notifyWatchers($title, $user, $message); |
| 85 | + } |
| 86 | + else { |
| 87 | + |
| 88 | + foreach ($add as $cat) { |
| 89 | + $title = Title::newFromText($cat, NS_CATEGORY); |
| 90 | + $message = wfMsg('categorywatch-catadd', $page, $cat); |
| 91 | + $this->notifyWatchers($title, $user, $message); |
| 92 | + } |
| 93 | + |
| 94 | + foreach ($sub as $cat) { |
| 95 | + $title = Title::newFromText($cat, NS_CATEGORY); |
| 96 | + $message = wfMsg('categorywatch-catsub', $page, $cat); |
| 97 | + $this->notifyWatchers($title, $user, $message); |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + return true; |
| 102 | + } |
| 103 | + |
| 104 | + function notifyWatchers(&$title, &$editor, &$message) { |
| 105 | + global $wgLang, $wgEmergencyContact, $wgNoReplyAddress, $wgCategoryWatchNotifyEditor; |
| 106 | + |
| 107 | + # Get list of users watching this category |
| 108 | + $dbr = wfGetDB(DB_SLAVE); |
| 109 | + $conds = array('wl_title' => $title->getDBkey(), 'wl_namespace' => $title->getNamespace()); |
| 110 | + if (!$wgCategoryWatchNotifyEditor) $conds[] = 'wl_user <> '.intval($editor->getId()); |
| 111 | + $res = $dbr->select('watchlist', array('wl_user'), $conds, __METHOD__); |
| 112 | + |
| 113 | + # Wrap message with common body and send to each watcher |
| 114 | + $page = $title->getText(); |
| 115 | + $from = new MailAddress($wgEmergencyContact, 'WikiAdmin'); |
| 116 | + $replyto = new MailAddress($wgNoReplyAddress); |
| 117 | + foreach ($res as $row) { |
| 118 | + $watchingUser = User::newFromId($row->wl_user); |
| 119 | + if ($watchingUser->getOption('enotifwatchlistpages') && $watchingUser->isEmailConfirmed()) { |
| 120 | + $to = new MailAddress($watchingUser); |
| 121 | + $timecorrection = $watchingUser->getOption('timecorrection'); |
| 122 | + $editdate = $wgLang->timeanddate(wfTimestampNow(), true, false, $timecorrection); |
| 123 | + $body = wfMsg( |
| 124 | + 'categorywatch-emailbody', |
| 125 | + $watchingUser->getName(), |
| 126 | + $page, |
| 127 | + $editdate, |
| 128 | + $editor->getName(), |
| 129 | + $message |
| 130 | + ); |
| 131 | + UserMailer::send( |
| 132 | + $to, |
| 133 | + $from, |
| 134 | + wfMsg('categorywatch-emailsubject', $page), |
| 135 | + $body, |
| 136 | + $replyto |
| 137 | + ); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + $dbr->freeResult($res); |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +function wfSetupCategoryWatch() { |
| 146 | + global $wgCategoryWatch, $wgLanguageCode, $wgMessageCache; |
| 147 | + |
| 148 | + # Instantiate the CategoryWatch singleton now that the environment is prepared |
| 149 | + $wgCategoryWatch = new CategoryWatch(); |
| 150 | + |
| 151 | + # Add messages |
| 152 | + if ($wgLanguageCode == 'en') { |
| 153 | + $wgMessageCache->addMessages(array( |
| 154 | + 'categorywatch-emailbody' => "Hi $1, you have received this message because you are watching the \"$2\" category. This message is to notify you that at $3 user $4 $5.", |
| 155 | + 'categorywatch-emailsubject' => "Activity involving watched category \"$1\"", |
| 156 | + 'categorywatch-catmovein' => "moved $1 into category $2 from $3", |
| 157 | + 'categorywatch-catmoveout' => "moved $1 out of category $2 into $3", |
| 158 | + 'categorywatch-catadd' => "added $1 to category $2", |
| 159 | + 'categorywatch-catsub' => "removed $1 from category $2" |
| 160 | + )); |
| 161 | + } |
| 162 | +} |
| 163 | + |