Index: trunk/extensions/Tasks/Tasks.php |
— | — | @@ -7,22 +7,28 @@ |
8 | 8 | include ( "extensions/Tasks.php" ) ; |
9 | 9 | |
10 | 10 | Also, you need to run the following SQL statement: |
11 | | -CREATE TABLE `tasks` ( |
12 | | - `task_id` int(8) unsigned NOT NULL auto_increment, |
13 | | - `task_page_id` int(8) unsigned NOT NULL default '0', |
14 | | - `task_page_title` varchar(255) NOT NULL default '', |
15 | | - `task_user_id` int(8) unsigned NOT NULL default '0', |
16 | | - `task_user_text` varchar(255) NOT NULL default '', |
17 | | - `task_user_assigned` int(8) unsigned NOT NULL default '0', |
18 | | - `task_status` int(4) unsigned NOT NULL default '0', |
19 | | - `task_comment` mediumtext NOT NULL, |
20 | | - `task_type` int(4) unsigned NOT NULL default '0', |
21 | | - `task_timestamp` varchar(14) binary NOT NULL default '', |
22 | | - `task_user_close` int(8) unsigned NOT NULL default '0', |
23 | | - PRIMARY KEY (`task_id`), |
24 | | - KEY `task_page_id` (`task_page_id`,`task_status`,`task_type`), |
25 | | - KEY `task_page_title` (`task_page_title`) |
26 | | -) TYPE=InnoDB ; |
| 11 | +CREATE TABLE tasks ( |
| 12 | + task_id int(8) unsigned NOT NULL auto_increment, |
| 13 | + task_page_id int(8) unsigned NOT NULL default '0', |
| 14 | + task_page_title varchar(255) NOT NULL default '', |
| 15 | + task_user_id int(8) unsigned NOT NULL default '0', |
| 16 | + task_user_text varchar(255) NOT NULL default '', |
| 17 | + task_user_assigned int(8) unsigned NOT NULL default '0', |
| 18 | + task_status int(4) unsigned NOT NULL default '0', |
| 19 | + task_comment mediumtext NOT NULL, |
| 20 | + task_type int(4) unsigned NOT NULL default '0', |
| 21 | + task_timestamp varchar(14) binary NOT NULL default '', |
| 22 | + task_user_close int(8) unsigned NOT NULL default '0', |
| 23 | + task_timestamp_closed varchar(14) NOT NULL default '', |
| 24 | + PRIMARY KEY (task_id), |
| 25 | + KEY task_page_id (task_page_id,task_status,task_type), |
| 26 | + KEY task_page_title (task_page_title) |
| 27 | +) TYPE=InnoDB; |
| 28 | + |
| 29 | +Known bugs: |
| 30 | +* setPageTitle in page_management doesn't work for some reason |
| 31 | +* Both the "article" and "tasks" tabs are displayed as active when viewing the "tasks" tab |
| 32 | + |
27 | 33 | */ |
28 | 34 | |
29 | 35 | if (!defined('MEDIAWIKI')) die(); |
— | — | @@ -42,6 +48,7 @@ |
43 | 49 | $wgHooks['UnknownAction'][] = 'wfTasksExtensionAction' ; |
44 | 50 | $wgHooks['ArticleSaveComplete'][] = 'wfTasksExtensionArticleSaveComplete' ; |
45 | 51 | $wgHooks['ArticleDeleteComplete'][] = 'wfTasksExtensionArticleDeleteComplete' ; |
| 52 | +$wgHooks['SpecialMovepageAfterMove'][] = 'wfTasksExtensionAfterMove' ; |
46 | 53 | |
47 | 54 | |
48 | 55 | # BEGIN logging functions |
— | — | @@ -76,15 +83,31 @@ |
77 | 84 | |
78 | 85 | |
79 | 86 | |
80 | | -#---------------------------------------------------------------- |
| 87 | +#___________________________________________________________________ |
| 88 | +# Hook functions |
81 | 89 | |
82 | 90 | /** |
| 91 | +* Catch page movement, fix internal task_page_title values |
| 92 | +*/ |
| 93 | +function wfTasksExtensionAfterMove ( &$special_page , &$old_title , &$new_title ) { |
| 94 | + if ( $new_title->isTalkPage() ) return false ; # No tasks for talk pages, no need to bother the database... |
| 95 | + |
| 96 | + wfTasksAddCache() ; |
| 97 | + |
| 98 | + $st = new SpecialTasks ; |
| 99 | + $st->rename_tasks_page ( $old_title , $new_title ) ; |
| 100 | + return false ; |
| 101 | +} |
| 102 | + |
| 103 | + |
| 104 | +/** |
83 | 105 | * Catch article deletion, remove all tasks |
84 | 106 | */ |
85 | 107 | function wfTasksExtensionArticleDeleteComplete ( &$article , &$user , $reason ) { |
86 | 108 | # return false ; # Uncomment this line to prevent deletion of tasks upon deletion of article |
87 | 109 | wfTasksAddCache() ; |
88 | 110 | $t = $article->getTitle() ; |
| 111 | + if ( $t->isTalkPage() ) return false ; # No tasks for talk pages, no need to bother the database... |
89 | 112 | |
90 | 113 | $st = new SpecialTasks ; |
91 | 114 | $st->delete_all_tasks ( $t ) ; |
— | — | @@ -97,15 +120,15 @@ |
98 | 121 | function wfTasksExtensionArticleSaveComplete ( &$article , &$user , $text , $summary, $isminor, $watchthis, $something ) { |
99 | 122 | wfTasksAddCache() ; |
100 | 123 | $t = $article->getTitle() ; |
| 124 | + if ( $t->isTalkPage() ) return false ; # No tasks for talk pages, no need to bother the database... |
101 | 125 | $new_id = $t->mArticleID ; |
102 | 126 | $t->mArticleID = -1 ; # Fake non-existing page |
103 | 127 | |
104 | 128 | $st = new SpecialTasks ; |
105 | 129 | $tasks = $st->get_tasks_for_page ( $t , true ) ; |
106 | 130 | foreach ( $tasks AS $task ) { |
107 | | - if ( $st->task_types[$task->task_type] != 'create' ) continue ; # Not a "create" task |
108 | | - $status = $st->status_types[$task->task_status] ; |
109 | | - if ( $status != 'open' && $status != 'assigned' ) continue ; # Not open |
| 131 | + if ( !$st->is_creation_task ( $task->task_type ) ) continue ; # Not a "create" task |
| 132 | + if ( $sk->is_closed ( $task->task_status ) ) continue ; # Not open |
110 | 133 | $st->change_task_status ( $task->task_id , 3 ) ; # "Closed" |
111 | 134 | $t->mArticleID = $new_id ; |
112 | 135 | $st->set_new_article_id ( $t ) ; |
— | — | @@ -120,6 +143,7 @@ |
121 | 144 | */ |
122 | 145 | function wfTasksExtensionTab ( &$skin , &$content_actions ) { |
123 | 146 | global $wgTitle , $action ; |
| 147 | + if ( $wgTitle->isTalkPage() ) return false ; # No tasks for talk pages, no need to bother the database... |
124 | 148 | wfTasksAddCache() ; |
125 | 149 | $content_actions['tasks'] = array( |
126 | 150 | 'class' => ($action == 'tasks') ? 'selected' : false, |
— | — | @@ -132,7 +156,7 @@ |
133 | 157 | * This is where the action is :-) |
134 | 158 | */ |
135 | 159 | function wfTasksExtensionAction ( $action , $article ) { |
136 | | - if ( $action != 'tasks' ) return true ; |
| 160 | + if ( $action != 'tasks' ) return true ; # Not my kind of action! |
137 | 161 | |
138 | 162 | wfTasksAddCache() ; |
139 | 163 | |
— | — | @@ -142,6 +166,8 @@ |
143 | 167 | return false ; |
144 | 168 | } |
145 | 169 | |
| 170 | +#_____________________________________________________________________________ |
| 171 | + |
146 | 172 | /** |
147 | 173 | * Text adding function |
148 | 174 | */ |
— | — | @@ -152,22 +178,23 @@ |
153 | 179 | $wgMessageCache->addMessages( |
154 | 180 | array( |
155 | 181 | 'tasks_tab' => 'Tasks', |
| 182 | + 'tasks_title' => "Tasks for $1", |
156 | 183 | 'tasks_form_new' => "Create new task", |
157 | 184 | 'tasks_form_comment' => "Comment", |
158 | 185 | 'tasks_error1' => "Task was not created: there is already such a task!<br/>", |
159 | 186 | 'tasks_ok1' => "New task has been created!<br/>", |
160 | 187 | 'tasks_create_header' => "Create a new task", |
161 | 188 | 'tasks_existing_header' => "Existing tasks", |
162 | | - 'tasks_existing_table_header' => "<th>Task</th><th>Created</th><th>Comment</th><th>Assignment/Actions/Page</th>", |
| 189 | + 'tasks_existing_table_header' => "<th>Task</th><th>Dates</th><th>Initial comment</th><th>Assignment/Actions/Page</th>", |
163 | 190 | 'tasks_noone' => "noone", |
164 | 191 | 'tasks_assign_me' => "<a href=\"$1\">Assign myself</a>", |
165 | 192 | 'tasks_close' => "<a href=\"$1\">Close task</a>", |
166 | 193 | 'tasks_wontfix' => "<a href=\"$1\">Won't fix</a>", |
167 | 194 | 'tasks_reopen' => "<a href=\"$1\">Reopen task</a>", |
168 | 195 | 'tasks_assignedto' => "Assigned to $1", |
169 | | - 'tasks_created_by' => "By $1", |
| 196 | + 'tasks_created_by' => "Created by $1", |
170 | 197 | 'tasks_discussion_page_link' => "Task discussion page", |
171 | | - 'tasks_closedby' => "(by $1)", |
| 198 | + 'tasks_closedby' => "Closed by $1", |
172 | 199 | |
173 | 200 | 'tasks_status_open' => "Open" , |
174 | 201 | 'tasks_status_assigned' => "Assigned" , |
— | — | @@ -177,7 +204,8 @@ |
178 | 205 | 'tasks_type_wikify' => "Wikify" , |
179 | 206 | 'tasks_type_rewrite' => "Rewrite" , |
180 | 207 | 'tasks_type_delete' => "Delete" , |
181 | | - 'tasks_type_create' => "Create" , |
| 208 | + 'tasks_type_create' => "Create blank page" , |
| 209 | + 'tasks_type_write' => "Write article" , |
182 | 210 | 'tasks_status_bgcol_open' => "#FF9999" , |
183 | 211 | 'tasks_status_bgcol_assigned' => "#FFF380" , |
184 | 212 | 'tasks_status_bgcol_closed' => "#99FF99" , |
— | — | @@ -227,7 +255,10 @@ |
228 | 256 | 3 => 'rewrite', |
229 | 257 | 4 => 'delete', |
230 | 258 | 5 => 'create', |
| 259 | + 6 => 'write', |
231 | 260 | ) ; |
| 261 | + |
| 262 | + var $creation_tasks = array ( 5 , 6 ) ; |
232 | 263 | |
233 | 264 | /** |
234 | 265 | * Constructor |
— | — | @@ -237,6 +268,20 @@ |
238 | 269 | $this->includable( true ); |
239 | 270 | } |
240 | 271 | |
| 272 | + function is_creation_task ( &$task_type ) { |
| 273 | + return in_array ( $task_type , $this->creation_tasks ) ; |
| 274 | + } |
| 275 | + |
| 276 | + function is_open ( $status ) { |
| 277 | + if ( $status == 1 || $status == 2 ) |
| 278 | + return true ; |
| 279 | + return false ; |
| 280 | + } |
| 281 | + |
| 282 | + function is_closed ( $status ) { |
| 283 | + return !$this->is_open ( $status ) ; |
| 284 | + } |
| 285 | + |
241 | 286 | /** |
242 | 287 | * Takes a title and a list of existing tasks, and decides which new tasks can be created. |
243 | 288 | * There's no point in having a dozen "wikify" tasks for a single article, now is there? :-) |
— | — | @@ -249,7 +294,7 @@ |
250 | 295 | foreach ( $tasks AS $t ) |
251 | 296 | $tg[$t->task_type] = 1 ; |
252 | 297 | for ( $a = min ( array_keys ( $this->task_types ) ) ; $a <= max ( array_keys ( $this->task_types ) ) ; $a++ ) { |
253 | | - if ( !$exists AND $a != 5 ) continue ; # Article does not exits; only valid action: create |
| 298 | + if ( !$exists AND $this->is_creation_task ( $a ) ) continue ; # Article does not exits; only valid action: create |
254 | 299 | if ( isset ( $tg[$a] ) AND ( $tg[$a]->task_status < 3 ) ) continue ; # Task exists and is not closed |
255 | 300 | $tk = $this->task_types[$a] ; |
256 | 301 | if ( $tk == 'create' && $exists ) continue ; # Can't create an existing article... |
— | — | @@ -280,8 +325,8 @@ |
281 | 326 | 'task_page_title' => $title->getPrefixedDBkey() , |
282 | 327 | 'task_user_id' => $wgUser->getID() , |
283 | 328 | 'task_user_text' => $wgUser->getName() , |
284 | | - 'task_user_assigned' => '0' , # default |
285 | | - 'task_status' => '1' , # Hack, should check for the numerical value assigned to 'open' |
| 329 | + 'task_user_assigned' => '0' , # default: No user assigned |
| 330 | + 'task_status' => $this->get_status_number('open') , |
286 | 331 | 'task_comment' => $comment , |
287 | 332 | 'task_type' => $type , |
288 | 333 | 'task_timestamp' => $dbw->timestamp() |
— | — | @@ -308,18 +353,24 @@ |
309 | 354 | |
310 | 355 | $out .= "<tr>" ; |
311 | 356 | $out .= "<td valign='top' align='left' nowrap bgcolor='" . wfMsg('tasks_status_bgcol_'.$this->status_types[$status]) . "'>" ; |
312 | | - $out .= "<b>" . $ttype . "</b><br/>" ; |
| 357 | + $out .= "<b>" . $ttype . "</b><br/><i>" ; |
313 | 358 | $out .= wfMsg ( 'tasks_status_' . $this->status_types[$status] ) ; |
314 | | - if ( $task->task_user_close != 0 && ( $status == 3 || $status == 4 ) ) { |
| 359 | + $out .= "</i></td>" ; |
| 360 | + $out .= "<td align='left' valign='top' nowrap>" ; |
| 361 | + $out .= wfMsg ( 'tasks_created_by' , $sk->makeLink ( $cu->getPrefixedText() , $task->task_user_text ) ) ; |
| 362 | + $out .= "<br/>{$ct}" ; |
| 363 | + |
| 364 | + # Closing information |
| 365 | + if ( $task->task_user_close != 0 && $this->is_closed ( $status ) ) { |
315 | 366 | $user_close = new User ; |
316 | 367 | $user_close->setID ( $task->task_user_close ) ; |
317 | 368 | $uct = Title::makeTitleSafe( NS_USER, $user_close->getName() ) ; # Assigned user title |
318 | 369 | $out .= "<br/>" . wfMsg ( 'tasks_closedby' , $sk->makeLink ( $uct->getPrefixedText() , $user_close->getName() ) ) ; |
| 370 | + if ( $task->task_timestamp_closed != "" ) |
| 371 | + $out .= "<br/>" . $wgContLang->timeanddate ( $task->task_timestamp_closed ) ; |
319 | 372 | } |
320 | 373 | $out .= "</td>" ; |
321 | | - $out .= "<td align='left' valign='top' nowrap>" ; |
322 | | - $out .= wfMsg ( 'tasks_created_by' , $sk->makeLink ( $cu->getPrefixedText() , $task->task_user_text ) ) ; |
323 | | - $out .= "<br/>{$ct}</td>" ; |
| 374 | + |
324 | 375 | $out .= "<td align='left' valign='top'>" . $comment . "</td>" ; |
325 | 376 | $out .= "<td align='left' valign='top'>" ; |
326 | 377 | if ( $task->task_user_assigned == 0 ) { # Noone is assigned this task |
— | — | @@ -336,7 +387,7 @@ |
337 | 388 | $url = $sk->makeUrl ( $title->getPrefixedText() , "action=tasks&mode=assignme&taskid={$tid}" ) ; |
338 | 389 | $txt[] = wfMsg ( 'tasks_assign_me' , $url ) ; |
339 | 390 | } |
340 | | - if ( $status < 3 ) { # Open or assigned |
| 391 | + if ( $this->is_open ( $status ) ) { # Open or assigned |
341 | 392 | $url = $sk->makeUrl ( $title->getPrefixedText() , "action=tasks&mode=close&taskid={$tid}" ) ; |
342 | 393 | $txt[] = wfMsg ( 'tasks_close' , $url ) ; |
343 | 394 | $url = $sk->makeUrl ( $title->getPrefixedText() , "action=tasks&mode=wontfix&taskid={$tid}" ) ; |
— | — | @@ -375,7 +426,7 @@ |
376 | 427 | } |
377 | 428 | |
378 | 429 | /** |
379 | | - * Checks if there's a "mode" set (performs changes on tasks, like assigning or closing them) |
| 430 | + * Checks if there's a "mode" set in the URL of the current page (performs changes on tasks, like assigning or closing them) |
380 | 431 | */ |
381 | 432 | function check_mode ( &$title ) { |
382 | 433 | global $wgUser , $wgRequest ; |
— | — | @@ -392,7 +443,7 @@ |
393 | 444 | $dbw->update( 'tasks', |
394 | 445 | array( # SET |
395 | 446 | 'task_user_assigned' => $wgUser->getID(), |
396 | | - 'task_status' => 2 |
| 447 | + 'task_status' => $this->get_status_number('assigned') |
397 | 448 | ), |
398 | 449 | $conditions, |
399 | 450 | $fname ); |
— | — | @@ -406,30 +457,38 @@ |
407 | 458 | return $out ; |
408 | 459 | } |
409 | 460 | |
410 | | - function get_status_number ( $mode ) { |
| 461 | + /** |
| 462 | + * Returns the number for the status |
| 463 | + */ |
| 464 | + function get_status_number ( $status ) { |
411 | 465 | foreach ( $this->status_types AS $k => $v ) { |
412 | | - if ( $v == $mode ) |
| 466 | + if ( $v == $status ) |
413 | 467 | return $k ; |
414 | 468 | } |
415 | 469 | return 0 ; # Invalid status |
416 | 470 | } |
417 | 471 | |
| 472 | + /** |
| 473 | + * Changes the status of a task, performs some associated cleanup, and logs the action |
| 474 | + */ |
418 | 475 | function change_task_status ( $taskid , $new_status ) { |
419 | 476 | global $wgUser ; |
420 | 477 | $fname = "Tasks:change_task_status" ; |
| 478 | + $dbw =& wfGetDB( DB_MASTER ); |
421 | 479 | |
422 | 480 | $as = array ( 'task_status' => $new_status ) ; # What to chenge |
423 | 481 | $aw = array ( 'task_id' => $taskid ) ; # Where to change it |
424 | 482 | |
425 | | - if ( $new_status == 3 || $new_status == 4 ) { # When closing, set closing user ID, and reset assignment |
| 483 | + if ( $this->is_closed ( $new_status ) ) { # When closing, set closing user ID, and reset assignment |
426 | 484 | $as['task_user_close'] = $wgUser->getID() ; |
427 | 485 | $as['task_user_assigned'] = 0 ; |
428 | | - } else if ( $new_status == 1 ) { # Change to "open", no assigned user or closing user |
| 486 | + $as['task_timestamp_closed'] = $dbw->timestamp() ; |
| 487 | + } else if ( $new_status == $this->get_status_number('open') ) { # Change to "open", no assigned user or closing user |
429 | 488 | $as['task_user_assigned'] = 0 ; |
430 | 489 | $as['task_user_close'] = 0 ; |
| 490 | + $as['task_timestamp_closed'] = "" ; |
431 | 491 | } |
432 | 492 | |
433 | | - $dbw =& wfGetDB( DB_MASTER ); |
434 | 493 | $dbw->update( 'tasks', |
435 | 494 | $as , # SET |
436 | 495 | $aw , # WHERE |
— | — | @@ -479,19 +538,35 @@ |
480 | 539 | */ |
481 | 540 | function delete_all_tasks ( &$title ) { |
482 | 541 | $fname = "Tasks:delete_all_tasks" ; |
| 542 | + if ( $title->getArticleID() == 0 ) |
| 543 | + $conds = array ( 'task_page_title' => $title->getPrefixedDBkey() ) ; |
| 544 | + else |
| 545 | + $conds = array ( 'task_page_id' => $title->getArticleID() ) ; |
483 | 546 | $dbw =& wfGetDB( DB_MASTER ); |
484 | 547 | $dbw->delete ( 'tasks' , |
485 | | - array ( 'task_page_title' => $title->getPrefixedDBkey() ) , |
| 548 | + $conds , |
486 | 549 | $fname ) ; |
487 | 550 | } |
488 | 551 | |
| 552 | + function rename_tasks_page ( $old_title , $new_title ) { |
| 553 | + $fname = "Tasks:rename_tasks_page" ; |
| 554 | + $dbw =& wfGetDB( DB_MASTER ); |
| 555 | + $dbw->update( 'tasks', |
| 556 | + array ( 'task_page_title' => $new_title->getPrefixedDBkey() ) , # SET |
| 557 | + array ( "task_page_title" => $old_title->getPrefixedDBkey() ) , # WHERE |
| 558 | + $fname ); |
| 559 | + } |
| 560 | + |
489 | 561 | /** |
490 | 562 | * THIS IS THE MAIN FUNCTION FOR THE TAB-BASED INTERFACE |
491 | 563 | */ |
492 | 564 | function page_management ( $title ) { |
493 | | - global $wgOut ; |
| 565 | + if ( $title->isTalkPage() ) return ; # No tasks for talk pages, no need to bother the database... |
| 566 | + |
| 567 | + global $wgOut , $action ; |
494 | 568 | $out = "" ; |
495 | 569 | $tasks = array() ; |
| 570 | + $wgOut->setPageTitle ( wfMsg('tasks_title',$title->getPrefixedText()) ) ; # Doesn't work for some reason... |
496 | 571 | |
497 | 572 | # Create from form |
498 | 573 | $out .= $this->create_from_form ( $title ) ; |