r27032 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r27031‎ | r27032 | r27033 >
Date:00:55, 30 October 2007
Author:gri6507
Status:old
Tags:
Comment:
v0.8.1 - initial publication in SVN
Modified paths:
  • /trunk/extensions/TodoTasks/SpecialTaskList.php (added) (history)

Diff [purge]

Index: trunk/extensions/TodoTasks/SpecialTaskList.php
@@ -0,0 +1,430 @@
 2+<?php
 3+
 4+/*
 5+This program is free software; you can redistribute it and/or
 6+modify it under the terms of the GNU General Public License
 7+as published by the Free Software Foundation, version 2
 8+of the License.
 9+
 10+This program is distributed in the hope that it will be useful,
 11+but WITHOUT ANY WARRANTY; without even the implied warranty of
 12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 13+GNU General Public License for more details.
 14+
 15+You should have received a copy of the GNU General Public License
 16+along with this program; if not, write to the Free Software
 17+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 18+*/
 19+
 20+$wgUseProjects = true;
 21+
 22+global $wgHooks;
 23+global $wgSpecialPages;
 24+
 25+$wgSpecialPages['TaskList'] = 'TaskList';
 26+if ($wgUseProjects)
 27+ $wgSpecialPages['TaskListByProject'] = 'TaskListByProject';
 28+$wgHooks['PersonalUrls'][] = 'addPersonalUrl';
 29+$wgHooks['AlternateEdit'][] = 'todoPreviewAction';
 30+$wgHooks['EditPage::attemptSave'][] = 'todoSavePreparser';
 31+$wgExtensionFunctions[] = 'wfTodoParserFunction_Setup';
 32+$wgHooks['LanguageGetMagic'][] = 'wfTodoParserFunction_Magic';
 33+$wgTodoTasksExtensionVersion = '0.8.1';
 34+$wgExtensionCredits['parserhook'][] = array(
 35+ 'version' => $wgTodoTasksExtensionVersion,
 36+ 'name' => 'Todo Tasks',
 37+ 'author' => 'Paul Grinberg',
 38+ 'email' => 'gri6507 at yahoo dot com',
 39+ 'url' => 'http://www.mediawiki.org/wiki/Extension:Todo_Tasks',
 40+ 'description' => 'adds <nowiki>{{#todo:}}</nowiki> parser function for assigning tasks');
 41+$wgExtensionCredits['specialpage'][] = array(
 42+ 'name' => 'Todo Tasks',
 43+ 'version' => $wgTodoTasksExtensionVersion,
 44+ 'author' => 'Paul Grinberg',
 45+ 'email' => 'gri6507 at yahoo dot com',
 46+ 'url' => 'http://www.mediawiki.org/wiki/Extension:Todo_Tasks',
 47+ 'description' => 'Adds a special page for reviewing tasks assignments'
 48+);
 49+
 50+
 51+function wfTodoParserFunction_Setup() {
 52+ global $wgParser;
 53+ # Set a function hook associating the "example" magic word with our function
 54+ $wgParser->setFunctionHook( 'todo', 'wfTodoParserFunction_Render' );
 55+}
 56+
 57+function wfTodoParserFunction_Magic( &$magicWords, $langCode ) {
 58+ # Add the magic word
 59+ # The first array element is case sensitive, in this case it is not case sensitive
 60+ # All remaining elements are synonyms for our parser function
 61+ $magicWords['todo'] = array( 0, 'todo' );
 62+ # unless we return true, other parser functions extensions won't get loaded.
 63+ return true;
 64+}
 65+
 66+function getUserIDFromUserText($user) {
 67+ $dbr = wfGetDB( DB_SLAVE );
 68+ $userid = 0;
 69+
 70+ if (preg_match('/^\s*(.*?)\s*$/', $user, $matches))
 71+ $user = $matches[1];
 72+
 73+ $u = User::newFromName($user);
 74+ if ($u) {
 75+ $userid = $u->idForName(); // valid userName
 76+ }
 77+ if (!$userid) { // if not a valid userName, try as a userRealName
 78+ $userid = $dbr->selectField( 'user', 'user_id', array( 'user_real_name' => $user ), 'renderTodo' );
 79+ if (!$userid) { // if not valid userRealName, try case insensitive userRealName
 80+ $sql = "SELECT user_id FROM ". $dbr->tableName('user') ." WHERE UPPER(user_real_name) LIKE '%" . strtoupper($user)
 81+. "%'";
 82+ $res = $dbr->query( $sql, __METHOD__ );
 83+ if ($dbr->numRows($res)) {
 84+ $row = $dbr->fetchRow($res);
 85+ $userid = $row[0];
 86+ }
 87+ $dbr->freeResult($res);
 88+ if (!$userid) { // if not case insensitive userRealName, try case insensitive lastname
 89+ list ($first, $last) = preg_split('/\s+/', $user);
 90+ if ($last != '') {
 91+ $sql = "SELECT user_id FROM ". $dbr->tableName('user') ." WHERE UPPER(user_real_name) LIKE '%" .
 92+strtoupper($last) . "%'";
 93+ $res = $dbr->query( $sql, __METHOD__ );
 94+ if ($dbr->numRows($res)) {
 95+ $row = $dbr->fetchRow($res);
 96+ $userid = $row[0];
 97+ }
 98+ $dbr->freeResult($res);
 99+ }
 100+ }
 101+ }
 102+ }
 103+ return $userid;
 104+}
 105+
 106+function getValidProjects() {
 107+ $ProjPageTitle = Title::newFromText ('TodoTasksValidProjects', NS_MEDIAWIKI) ;
 108+ return Revision::newFromTitle($ProjPageTitle)->getText();
 109+}
 110+
 111+function validateProject($projlist, $proj) {
 112+ $validprojects = preg_split('/\s*\*\s*/', $projlist, -1, PREG_SPLIT_NO_EMPTY);
 113+ foreach ($validprojects as $vp) {
 114+ if (preg_match("/^$proj$/i", $vp))
 115+ return $vp;
 116+ }
 117+
 118+ return 'Unknown Project';
 119+}
 120+
 121+$todoPreview;
 122+function wfTodoParserFunction_Render( &$parser, $input, $users, $project='') {
 123+ global $wgOut, $wgSitename, $wgEmergencyContact, $todoPreview;
 124+ global $wgUseProjects;
 125+
 126+ $username = '';
 127+ $fullname = '';
 128+ $u = 0;
 129+ $userIdList = array();
 130+ $userIdList2 = array();
 131+ $dbr = wfGetDB( DB_SLAVE );
 132+
 133+ $task_text = '';
 134+ $task_project = '';
 135+
 136+ if ($wgUseProjects) {
 137+ if (isset($project) && ($project != '')) {
 138+ $task_project .= "''";
 139+ $first = true;
 140+ $validProjects = getValidProjects();
 141+ $projlist = preg_split('/\s*,\s*/', $project, -1, PREG_SPLIT_NO_EMPTY);
 142+ foreach ( $projlist as $proj ) {
 143+ if (!$first) {
 144+ $task_project .= ', ';
 145+ } else {
 146+ $first = false;
 147+ }
 148+ $task_project .= validateProject($validProjects, $proj);
 149+ }
 150+ $task_project .= "'' - ";
 151+ }
 152+ }
 153+
 154+ $task_text .= "$input (''' ";
 155+
 156+ if ($users == '') { // if no user specified
 157+ $task_text .= "unspecified user";
 158+ } else {
 159+ $first = true;
 160+ $userlist = preg_split('/\s*,\s*/', $users, -1, PREG_SPLIT_NO_EMPTY);
 161+ foreach ( $userlist as $user ) {
 162+ if (!$first) {
 163+ $task_text .= ', ';
 164+ } else {
 165+ $first = false;
 166+ }
 167+ $userid = getUserIDFromUserText($user);
 168+ if ($userid != 0) { // successfully found the user
 169+ $u = User::newFromId($userid);
 170+ $username = $u->getName();
 171+ $fullname = $u->getRealName();
 172+ $task_text .= "${fullname}";
 173+ array_push($userIdList, $userid);
 174+ array_push($userIdList2, $userid);
 175+ } else { // fall through to worst case scenario
 176+ $task_text .= "incorrect username";
 177+ }
 178+ }
 179+ }
 180+ $task_text .= "''' )";
 181+ $text = $task_project . $task_text;
 182+
 183+ /* The following assumes the existance of an extra wiki table called $prefix_todo.
 184+ To create this table issue
 185+ CREATE TABLE wiki_todo (
 186+ id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
 187+ hash TINYBLOB
 188+ );
 189+ */
 190+
 191+ $hash = md5($task_text);
 192+ if (is_object($todoPreview) && !$todoPreview->preview) {
 193+ /* Only when the action is a Submit instead of a Preview, send out an email
 194+ reminder and store in database (if needed).
 195+ */
 196+ $adminAddress = new MailAddress( $wgEmergencyContact, 'WikiAdmin' );
 197+ $tasklist = Title::newFromText("Special:TaskList");
 198+ $body = ",\n\nSomeone has assigned a new Task for you on " . $parser->getTitle()->getFullURL() .
 199+ ".\n\nTo see your complete Task List go to " . $tasklist->getFullURL() .
 200+ ".\n\n\tYour friendly ${wgSitename} notification system\n";
 201+ $row = $dbr->selectRow( 'todo', 'id', array( 'hash' => $hash ), __METHOD__ );
 202+ if (!$row) { // this is a new todo item
 203+ while ($userid = array_pop($userIdList)) {
 204+ $u = User::newFromId($userid);
 205+ $fullname = $u->getRealName();
 206+ $email = "Dear ${fullname}$body";
 207+ $u->sendMail("[${wgSitename}] Task List Change", $email, $adminAddress->toString());
 208+ $dbr->insert('todo', array( 'hash' => $hash ), __METHOD__ );
 209+ }
 210+ }
 211+ }
 212+
 213+
 214+ return $text;
 215+}
 216+
 217+function addPersonalUrl(&$personal_urls, $wgTitle)
 218+{
 219+ global $wgOut;
 220+
 221+ $personal_urls['mytasks'] = array(
 222+ 'text' => "My tasks",
 223+ 'href' => Skin::makeSpecialUrl( 'TaskList')
 224+ );
 225+ return true;
 226+}
 227+
 228+function todoPreviewAction(&$q) {
 229+ global $todoPreview;
 230+
 231+ $todoPreview = $q;
 232+ return true;
 233+}
 234+
 235+function todoSavePreparser(&$q) {
 236+ // update the text of the todo so that it has a propper full name in it.
 237+ // this way, the <dpl> search will work better
 238+ $newpagetext = '';
 239+ $sections = preg_split('/({{.*?}})/', $q->textbox1, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
 240+ foreach($sections as $section) {
 241+ if (preg_match("/
 242+ ^{{ # we found a template
 243+ \s* # that may begin with spaces
 244+ ( # capture the template name in $1
 245+ (todo) # template may be a TODO
 246+ | # or
 247+ (action item) # template may be an ACTION ITEM
 248+ )
 249+ \s* # the template name may have trailing spaces
 250+ \| # the pipe to indicate template parameter #1 (task description)
 251+ ( # capture the template parameter in $4; this string is comprized of
 252+ [^|]*? # a possible sequence of non pipe characters
 253+ (\[\[.*\|?.*\]\])? # a possible wiki syntax link
 254+ [^|]* # a possible sequence on non pipe characters
 255+ )
 256+ \| # the pipe for the template parameter #3 (task assignees)
 257+ ([,.\s\w\d]*) # any combination of 'chars' repeated any number of times, captured in $6
 258+ ( # following by an optional grouping captured in $7
 259+ \| # which is the template parameter #4 (project associated with task)
 260+ \s*project\s*=\s* # which begins with project= (with possible spaces)
 261+ [,.\s\w\d]*? # any combination of 'chars' repeated any number of times
 262+ )?
 263+ }}$ # which ends the template
 264+ /ix", $section, $matches)) {
 265+ $newpagetext .= '{{' . "$matches[1]|$matches[4]|";
 266+ $first = true;
 267+ $userlist = preg_split('/\s*,\s*/', $matches[6], -1, PREG_SPLIT_NO_EMPTY);
 268+ foreach ( $userlist as $user ) {
 269+ if (!$first) {
 270+ $newpagetext .= ', ';
 271+ } else {
 272+ $first = false;
 273+ }
 274+ $userid = getUserIDFromUserText($user);
 275+ if ($userid != 0) { // successfully found the user
 276+ $u = User::newFromId($userid);
 277+ $username = $u->getName();
 278+ $fullname = $u->getRealName();
 279+ $newpagetext .= "${fullname}";
 280+ } else { // fall through to worst case scenario
 281+ $newpagetext .= $user;
 282+ }
 283+ }
 284+ if (isset($matches[7]))
 285+ $newpagetext .= "$matches[7]";
 286+ $newpagetext .= '}}';
 287+ } else {
 288+ $newpagetext .= $section;
 289+ }
 290+ }
 291+ $q->textbox1 = $newpagetext;
 292+ return true;
 293+}
 294+
 295+
 296+require ( dirname( __FILE__ ) . "/../includes/SpecialPage.php" );
 297+
 298+class TaskList extends SpecialPage
 299+{
 300+ function TaskList() {
 301+ SpecialPage::SpecialPage("TaskList");
 302+ self::loadMessages();
 303+ return true;
 304+ }
 305+
 306+ function loadMessages() {
 307+ static $messagesLoaded = false;
 308+ global $wgMessageCache;
 309+ if ($messagesLoaded) return;
 310+ $messagesLoaded = true;
 311+
 312+ $allMessages = array(
 313+ 'en' => array(
 314+ 'tasklist' => 'Task List',
 315+ )
 316+ );
 317+
 318+ foreach ( $allMessages as $lang => $langMessages ) {
 319+ $wgMessageCache->addMessages( $langMessages, $lang );
 320+ }
 321+ return true;
 322+ }
 323+
 324+ function execute($user) {
 325+ global $wgRequest, $wgOut, $wgUser;
 326+
 327+ $this->setHeaders();
 328+ $wgOut->setPagetitle(wfMsg('tasklist'));
 329+
 330+ $u = array();
 331+ if (is_null($user)) {
 332+ $u[] = $wgUser;
 333+ } else {
 334+ foreach (explode(',', $user) as $usr) {
 335+ $u[] = User::newFromName($usr);
 336+ }
 337+ }
 338+
 339+ foreach ($u as $user) {
 340+ if (!$user) {
 341+ $user = $wgUser;
 342+ }
 343+ $username = $user->getName();
 344+ $fullname = $user->getRealName();
 345+ list ($firstname, $lastname) = preg_split('/ /', $fullname);
 346+
 347+ $wgOut->addWikiText("== Todo List for $fullname ==");
 348+ $wgOut->addWikiText("<dpl> uses=Template:Todo\n notuses=Template:Status Legend\n include={Todo}.dpl\n
 349+includematch=/${fullname}/i\n </dpl>");
 350+ }
 351+ }
 352+}
 353+
 354+class TaskListByProject extends SpecialPage
 355+{
 356+ function TaskListByProject() {
 357+ SpecialPage::SpecialPage("TaskListByProject");
 358+ self::loadMessages();
 359+ return true;
 360+ }
 361+
 362+ function loadMessages() {
 363+ static $messagesLoaded = false;
 364+ global $wgMessageCache;
 365+ if ($messagesLoaded) return;
 366+ $messagesLoaded = true;
 367+
 368+ $allMessages = array(
 369+ 'en' => array(
 370+ 'tasklistbyproject' => 'Task List By Project',
 371+ )
 372+ );
 373+
 374+ foreach ( $allMessages as $lang => $langMessages ) {
 375+ $wgMessageCache->addMessages( $langMessages, $lang );
 376+ }
 377+ return true;
 378+ }
 379+
 380+ function execute($proj) {
 381+ global $wgRequest, $wgOut;
 382+
 383+ $this->setHeaders();
 384+ $wgOut->setPagetitle(wfMsg('tasklistbyproject'));
 385+
 386+ $project = '';
 387+
 388+ if (isset($proj)) {
 389+ $proj = str_replace('+', ' ', $proj);
 390+ $validProjects = getValidProjects();
 391+ $project = validateProject($validProjects, $proj);
 392+ if ($project == 'Unknown Project') {
 393+ $wgOut->addWikiText("Project '''$proj''' is not a valid project. For a list of valid projects, see
 394+[[MediaWiki:TodoTasksValidProjects]].");
 395+ self::ValidProjectsForm();
 396+ return;
 397+ }
 398+ }
 399+
 400+ self::ValidProjectsForm();
 401+
 402+ if ($project == '')
 403+ $project = $wgRequest->getVal('project');
 404+ if ($project) {
 405+ $wgOut->addWikiText("----");
 406+ $wgOut->addWikiText("Assigned Tasks for '''$project'''");
 407+ $dpl = "<dpl>\n uses=Template:Todo \n notuses=Template:Status Legend \n include={Todo}.dpl \n";
 408+ $dpl .= 'includematch=/project\s*=\s*([^\x2c]*\x2c)*\s*' . $project . '\s*(\x2c[^\x2c]*\s*)*$/i';
 409+ $dpl .= "\n </dpl>";
 410+ $wgOut->addWikiText($dpl);
 411+ }
 412+ }
 413+
 414+ function ValidProjectsForm() {
 415+ global $wgOut;
 416+
 417+ $titleObj = SpecialPage::getTitleFor( "TaskListByProject" );
 418+ $kiaction = $titleObj->getLocalUrl();
 419+ $wgOut->addHtml("<FORM ACTION=\"{$kiaction}\" METHOD=GET><LABEL FOR=project>Select Project: </LABEL>");
 420+ $wgOut->addHtml("<select name=project>");
 421+
 422+ $validprojects = preg_split('/\s*\*\s*/', getValidProjects(), -1, PREG_SPLIT_NO_EMPTY);
 423+ foreach ($validprojects as $vp)
 424+ $wgOut->addHtml("<option value=\"$vp\">$vp</option>");
 425+
 426+ $wgOut->addHtml("</select><INPUT TYPE=submit VALUE='Display'>");
 427+ }
 428+}
 429+
 430+
 431+?>

Status & tagging log