r49583 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r49582‎ | r49583 | r49584 >
Date:23:05, 16 April 2009
Author:tparscal
Status:deferred (Comments)
Tags:
Comment:
Added more robust documentation. Made drafts follow pages when moved. Fixed empty list bug when loading a draft of a deleted article.
Modified paths:
  • /trunk/extensions/Drafts/Drafts.classes.php (modified) (history)
  • /trunk/extensions/Drafts/Drafts.hooks.php (modified) (history)
  • /trunk/extensions/Drafts/Drafts.js (modified) (history)
  • /trunk/extensions/Drafts/Drafts.pages.php (modified) (history)
  • /trunk/extensions/Drafts/Drafts.php (modified) (history)

Diff [purge]

Index: trunk/extensions/Drafts/Drafts.classes.php
@@ -10,6 +10,12 @@
1111
1212 /* Static Functions */
1313
 14+ /**
 15+ * Counts the number of existing drafts for a specific user
 16+ * @return Number of drafts which match condition parameters
 17+ * @param object $title[optional] Title of article, defaults to all articles
 18+ * @param integer $userID[optional] ID of user, defaults to current user
 19+ */
1420 public static function num(
1521 &$title = null,
1622 $userID = null
@@ -39,6 +45,10 @@
4046 return $dbr->selectField( 'drafts', 'count(*)', $where, __METHOD__ );
4147 }
4248
 49+ /**
 50+ * Removes drafts which have not been modified for a period of time defined
 51+ * by $wgDraftsLifeSpan
 52+ */
4353 public static function clean() {
4454 global $egDraftsLifeSpan;
4555 // Get database connection
@@ -48,12 +58,42 @@
4959 // Removes expired drafts from database
5060 $dbw->delete( 'drafts',
5161 array(
52 - 'draft_savetime < ' . $dbw->addQuotes( $dbw->timestamp( $cutoff ) )
 62+ 'draft_savetime < ' .
 63+ $dbw->addQuotes( $dbw->timestamp( $cutoff ) )
5364 ),
5465 __METHOD__
5566 );
5667 }
5768
 69+ /**
 70+ * Re-titles drafts which point to a particlar article, as a response to the
 71+ * article being moved.
 72+ */
 73+ public static function move(
 74+ $oldTitle,
 75+ $newTitle
 76+ ) {
 77+ // Get database connection
 78+ $dbw = wfGetDB( DB_MASTER );
 79+ // Updates title and namespace of drafts upon moving
 80+ $dbw->update( 'drafts',
 81+ array(
 82+ 'draft_namespace' => $newTitle->getNamespace(),
 83+ 'draft_title' => $newTitle->getDBKey()
 84+ ),
 85+ array(
 86+ 'draft_page' => $newTitle->getArticleId()
 87+ ),
 88+ __METHOD__
 89+ );
 90+ }
 91+
 92+ /**
 93+ * Gets a list of existing drafts for a specific user
 94+ * @return
 95+ * @param object $title[optional] Title of article, defaults to all articles
 96+ * @param integer $userID[optional] ID of user, defaults to current user
 97+ */
5898 public static function get(
5999 $title = null,
60100 $userID = null
@@ -75,7 +115,6 @@
76116 $where['draft_page'] = $pageId;
77117 } else {
78118 // Adds new page information to conditions
79 - $where['draft_page'] = 0; // page not created yet
80119 $where['draft_namespace'] = $title->getNamespace();
81120 $where['draft_title'] = $title->getDBKey();
82121 }
@@ -98,19 +137,25 @@
99138 $drafts[] = Draft::newFromRow( $row );
100139 }
101140 }
102 - // Returns array of matching drafts or null id there were none
 141+ // Returns array of matching drafts or null if there were none
103142 return count( $drafts ) ? $drafts : null;
104143 }
105144
 145+ /**
 146+ * Outputs a table of existing drafts
 147+ * @return Number of drafts in the table
 148+ * @param object $title[optional] Title of article, defaults to all articles
 149+ * @param integer $userID[optional] ID of user, defaults to current user
 150+ */
106151 public static function display(
107152 &$title = null,
108 - $user = null
 153+ $userID = null
109154 ) {
110155 global $wgOut, $wgRequest, $wgUser, $wgLang;
111156 // Gets draftID
112157 $currentDraft = Draft::newFromID( $wgRequest->getIntOrNull( 'draft' ) );
113158 // Output HTML for list of drafts
114 - $drafts = Drafts::get( $title, $user );
 159+ $drafts = Drafts::get( $title, $userID );
115160 if ( count( $drafts ) > 0 ) {
116161 global $egDraftsLifeSpan;
117162 // Internationalization
@@ -164,8 +209,8 @@
165210 // Get article title text
166211 $htmlTitle = $draft->getTitle()->getEscapedText();
167212 // Build Article Load link
168 - $urlLoad = $draft->getTitle()->getFullUrl( 'action=edit&draft=' .
169 - urlencode( $draft->getID() )
 213+ $urlLoad = $draft->getTitle()->getFullUrl(
 214+ 'action=edit&draft=' . urlencode( $draft->getID() )
170215 );
171216 // Build discard link
172217 $urlDiscard = SpecialPage::getTitleFor( 'Drafts' )->getFullUrl(
@@ -282,6 +327,12 @@
283328
284329 /* Static Functions */
285330
 331+ /**
 332+ * Creates a new Draft object from a draft ID
 333+ * @return New Draft object
 334+ * @param integer $id ID of draft
 335+ * @param boolean $autoload[optional] Whether to load draft information
 336+ */
286337 public static function newFromID(
287338 $id,
288339 $autoload = true
@@ -289,12 +340,19 @@
290341 return new Draft( $id, $autoload );
291342 }
292343
 344+ /**
 345+ * Creates a new Draft object from a database row
 346+ * @return New Draft object
 347+ * @param array $row Database row to create Draft object with
 348+ */
293349 public static function newFromRow(
294350 $row
295351 ) {
296352 $draft = new Draft( $row['draft_id'], false );
297353 $draft->setToken( $row['draft_token'] );
298 - $draft->setTitle( Title::makeTitle( $row['draft_namespace'], $row['draft_title'] ) );
 354+ $draft->setTitle(
 355+ Title::makeTitle( $row['draft_namespace'], $row['draft_title'] )
 356+ );
299357 $draft->setSection( $row['draft_section'] );
300358 $draft->setStartTime( $row['draft_starttime'] );
301359 $draft->setEditTime( $row['draft_edittime'] );
@@ -306,113 +364,203 @@
307365 return $draft;
308366 }
309367
310 - public static function newToken() {
311 - return wfGenerateToken();
312 - }
313 -
314368 /* Properties */
315369
 370+ /**
 371+ * @return Whether draft exists in database
 372+ */
316373 public function exists() {
317374 return $this->exists;
318375 }
319376
 377+ /**
 378+ * @return Draft ID
 379+ */
320380 public function getID() {
321381 return $this->id;
322382 }
323383
 384+ /**
 385+ * @return Edit token
 386+ */
 387+ public function getToken() {
 388+ return $this->token;
 389+ }
 390+
 391+ /**
 392+ * Sets the edit token, like one generated by wfGenerateToken()
 393+ * @param string $token
 394+ */
324395 public function setToken(
325396 $token
326397 ) {
327398 $this->token = $token;
328399 }
329 - public function getToken() {
330 - return $this->token;
 400+
 401+ /**
 402+ * @return User ID of draft creator
 403+ */
 404+ public function getUserID() {
 405+ return $this->userID;
331406 }
332 -
333 - public function getUserID(
 407+
 408+ /**
 409+ * Sets user ID of draft creator
 410+ * @param integer $userID
 411+ */
 412+ public function setUserID(
334413 $userID
335414 ) {
336415 $this->userID = $userID;
337416 }
338 - public function setUserID() {
339 - return $this->userID;
340 - }
341417
 418+ /**
 419+ * @return Title of article of draft
 420+ */
342421 public function getTitle() {
343422 return $this->title;
344423 }
 424+
 425+ /**
 426+ * Sets title of article of draft
 427+ * @param object $title
 428+ */
345429 public function setTitle(
346430 $title
347431 ) {
348432 $this->title = $title;
349433 }
350434
 435+ /**
 436+ * @return Section of the article of draft
 437+ */
351438 public function getSection() {
352439 return $this->section;
353440 }
 441+
 442+ /**
 443+ * Sets section of the article of draft
 444+ * @param integer $section
 445+ */
354446 public function setSection(
355447 $section
356448 ) {
357449 $this->section = $section;
358450 }
359451
 452+ /**
 453+ * @return Time when draft of the article started
 454+ */
360455 public function getStartTime() {
361456 return $this->starttime;
362457 }
 458+
 459+ /**
 460+ * Sets time when draft of the article started
 461+ * @param string $starttime
 462+ */
363463 public function setStartTime(
364464 $starttime
365465 ) {
366466 $this->starttime = $starttime;
367467 }
368468
 469+ /**
 470+ * @return Time of most recent revision of article when this draft started
 471+ */
369472 public function getEditTime() {
370473 return $this->edittime;
371474 }
 475+
 476+ /**
 477+ * Sets time of most recent revision of article when this draft started
 478+ * @param string $edittime
 479+ */
372480 public function setEditTime(
373481 $edittime
374482 ) {
375483 $this->edittime = $edittime;
376484 }
377485
 486+ /**
 487+ * @return Time when draft was last modified
 488+ */
378489 public function getSaveTime() {
379490 return $this->savetime;
380491 }
 492+
 493+ /**
 494+ * Sets time when draft was last modified
 495+ * @param string $savetime
 496+ */
381497 public function setSaveTime(
382498 $savetime
383499 ) {
384500 $this->savetime = $savetime;
385501 }
386502
 503+ /**
 504+ * @return Scroll position of editor when draft was last modified
 505+ */
387506 public function getScrollTop() {
388507 return $this->scrolltop;
389508 }
 509+
 510+ /**
 511+ * Sets scroll position of editor when draft was last modified
 512+ * @param integer $scrolltop
 513+ */
390514 public function setScrollTop(
391515 $scrolltop
392516 ) {
393517 $this->scrolltop = $scrolltop;
394518 }
395519
 520+ /**
 521+ * @return Text of draft version of article
 522+ */
396523 public function getText() {
397524 return $this->text;
398525 }
 526+
 527+ /**
 528+ * Sets text of draft version of article
 529+ * @param string $text
 530+ */
399531 public function setText(
400532 $text
401533 ) {
402534 $this->text = $text;
403535 }
404536
 537+ /**
 538+ * @return Summary of changes
 539+ */
405540 public function getSummary() {
406541 return $this->summary;
407542 }
 543+
 544+ /**
 545+ * Sets summary of changes
 546+ * @param string $summary
 547+ */
408548 public function setSummary(
409549 $summary
410550 ) {
411551 $this->summary = $summary;
412552 }
413553
 554+ /**
 555+ * @return Whether edit is considdered to be a minor change
 556+ */
414557 public function getMinorEdit() {
415558 return $this->minoredit;
416559 }
 560+
 561+ /**
 562+ * Sets whether edit is considdered to be a minor change
 563+ * @param boolean $minoredit
 564+ */
417565 public function setMinorEdit(
418566 $minoredit
419567 ) {
@@ -421,6 +569,11 @@
422570
423571 /* Functions */
424572
 573+ /**
 574+ * Generic constructor
 575+ * @param integer $id[optional] ID to use
 576+ * @param boolean $autoload[optional] Whether to load from database
 577+ */
425578 public function __construct(
426579 $id = null,
427580 $autoload = true
@@ -433,7 +586,10 @@
434587 $this->load();
435588 }
436589 }
437 -
 590+
 591+ /**
 592+ * Selects draft row from database and populates object properties
 593+ */
438594 private function load() {
439595 global $wgUser;
440596 // Checks if the ID of the draft was set
@@ -480,7 +636,10 @@
481637 // Updates state
482638 $this->exists = true;
483639 }
484 -
 640+
 641+ /**
 642+ * Inserts or updates draft row in database
 643+ */
485644 public function save() {
486645 global $wgUser, $wgRequest;
487646 // Gets database connection
@@ -541,7 +700,11 @@
542701 // Returns success
543702 return true;
544703 }
545 -
 704+
 705+ /**
 706+ * Deletes draft row from database
 707+ * @param integer $user[optional] User ID, defaults to current user ID
 708+ */
546709 public function discard(
547710 $user = null
548711 ) {
@@ -550,7 +713,7 @@
551714 $user = $user === null ? $wgUser : $user;
552715 // Gets database connection
553716 $dbw = wfGetDB( DB_MASTER );
554 - // Deletes draft from database (verifying propper user to avoid hacking!)
 717+ // Deletes draft from database verifying propper user to avoid hacking!
555718 $dbw->delete( 'drafts',
556719 array(
557720 'draft_id' => $this->id,
Index: trunk/extensions/Drafts/Drafts.pages.php
@@ -6,11 +6,13 @@
77 * @ingroup Extensions
88 */
99
10 -// Drafts Special Page
1110 class DraftsPage extends SpecialPage {
1211
1312 /* Functions */
1413
 14+ /**
 15+ * Generic constructor
 16+ */
1517 public function __construct() {
1618 // Initialize special page
1719 SpecialPage::SpecialPage( 'Drafts' );
@@ -18,7 +20,11 @@
1921 wfLoadExtensionMessages( 'Drafts' );
2022 }
2123
22 - public function execute( $par ) {
 24+ /**
 25+ * Executes special page rendering and data processing
 26+ * @param string $sub MediaWiki supplied sub-page path
 27+ */
 28+ public function execute( $sub ) {
2329 global $wgRequest, $wgOut, $wgUser;
2430 // Begin output
2531 $this->setHeaders();
Index: trunk/extensions/Drafts/Drafts.php
@@ -18,7 +18,7 @@
1919
2020 // Check environment
2121 if ( !defined( 'MEDIAWIKI' ) ) {
22 - echo( "This is an extension to the MediaWiki package and cannot be run standalone.\n" );
 22+ echo( "This is an extension to MediaWiki and cannot be run standalone.\n" );
2323 die( - 1 );
2424 }
2525
@@ -70,6 +70,9 @@
7171 // Register article save hook
7272 $wgHooks['ArticleSaveComplete'][] = 'DraftHooks::discard';
7373
 74+// Updates namespaces and titles of drafts to new locations after moves
 75+$wgHooks['SpecialMovepageAfterMove'][] = 'DraftHooks::move';
 76+
7477 // Register controls hook
7578 $wgHooks['EditPageBeforeEditButtons'][] = 'DraftHooks::controls';
7679
Index: trunk/extensions/Drafts/Drafts.hooks.php
@@ -6,20 +6,36 @@
77 * @ingroup Extensions
88 */
99
10 -// Drafts hooks
1110 class DraftHooks {
 11+
 12+ /* Static Functions */
 13+
1214 /**
 15+ * SpecialMovepageAfterMove hook
 16+ */
 17+ public static function move(
 18+ $this,
 19+ $ot,
 20+ $nt
 21+ ) {
 22+ // Update all drafts of old article to new article for all users
 23+ Drafts::move( $ot, $nt );
 24+ // Continue
 25+ return true;
 26+ }
 27+
 28+ /**
1329 * ArticleSaveComplete hook
1430 */
1531 public static function discard(
16 - &$article,
17 - &$user,
18 - &$text,
19 - &$summary,
20 - &$m,
21 - &$watchthis,
22 - &$section,
23 - &$flags,
 32+ $article,
 33+ $user,
 34+ $text,
 35+ $summary,
 36+ $m,
 37+ $watchthis,
 38+ $section,
 39+ $flags,
2440 $rev
2541 ) {
2642 global $wgRequest;
@@ -38,7 +54,7 @@
3955 * Load draft...
4056 */
4157 public static function loadForm(
42 - &$editpage
 58+ $editpage
4359 ) {
4460 global $wgUser, $wgRequest, $wgOut, $wgTitle, $wgLang;
4561 // Check permissions
@@ -58,7 +74,8 @@
5975 if ( $wgRequest->getVal( 'action' ) == 'submit' &&
6076 $wgUser->editToken() == $wgRequest->getText( 'wpEditToken' ) )
6177 {
62 - // If the draft wasn't specified in the url, try using a form-submitted one
 78+ // If the draft wasn't specified in the url, try using a
 79+ // form-submitted one
6380 if ( !$draft->exists() ) {
6481 $draft = Draft::newFromID(
6582 $wgRequest->getIntOrNull( 'wpDraftID' )
@@ -120,14 +137,14 @@
121138
122139 /**
123140 * EditFilter hook
124 - * Intercept the saving of an article to detect if the submission was from the non-javascript
125 - * save draft button
 141+ * Intercept the saving of an article to detect if the submission was from
 142+ * the non-javascript save draft button
126143 */
127144 public static function interceptSave(
128145 $editor,
129146 $text,
130147 $section,
131 - &$error
 148+ $error
132149 ) {
133150 global $wgRequest;
134151 // Don't save if the save draft button caused the submit
@@ -144,8 +161,8 @@
145162 * Add draft saving controls
146163 */
147164 public static function controls(
148 - &$editpage,
149 - &$buttons
 165+ $editpage,
 166+ $buttons
150167 ) {
151168 global $wgUser, $wgTitle, $wgRequest;
152169 global $egDraftsAutoSaveWait, $egDraftsAutoSaveTimeout;
@@ -210,7 +227,7 @@
211228 array(
212229 'type' => 'hidden',
213230 'name' => 'wpDraftToken',
214 - 'value' => Draft::newToken()
 231+ 'value' => wfGenerateToken()
215232 )
216233 );
217234 $buttons['savedraft'] .= Xml::element( 'input',
Index: trunk/extensions/Drafts/Drafts.js
@@ -19,6 +19,10 @@
2020
2121 /* Functions */
2222
 23+ /**
 24+ * Sets the state of the draft
 25+ * @param {String} newState
 26+ */
2327 this.setState = function(
2428 newState
2529 ) {
@@ -50,10 +54,16 @@
5155 }
5256 }
5357
 58+ /**
 59+ * Gets the state of the draft
 60+ */
5461 this.getState = function() {
5562 return state;
5663 }
5764
 65+ /**
 66+ * Sends draft data to server to be saved
 67+ */
5868 this.save = function() {
5969 // Checks if a save is already taking place
6070 if ( state == 'saving' ) {
@@ -94,6 +104,9 @@
95105 clearTimeout( timer );
96106 }
97107
 108+ /**
 109+ * Updates the user interface to represent being out of sync with the server
 110+ */
98111 this.change = function() {
99112 // Sets state to changed
100113 self.setState( 'changed' );
@@ -111,6 +124,9 @@
112125 }
113126 }
114127
 128+ /**
 129+ * Initializes the user interface
 130+ */
115131 this.initialize = function() {
116132 // Cache edit form reference
117133 form = document.editform;
@@ -145,6 +161,10 @@
146162 }
147163 }
148164
 165+ /**
 166+ * Responds to the server after a save request has been handled
 167+ * @param {Object} request
 168+ */
149169 this.respond = function(
150170 request
151171 ) {

Comments

#Comment by Aaron Schulz (talk | contribs)   23:25, 16 April 2009

This adds serious overhead since the move query is not indexed.

One option is due add a page_id index. Another option is to use the current title rather than the draft_title field on save.

#Comment by Werdna (talk | contribs)   07:42, 23 April 2009

There's now an index on that field; however, Drafts::move() is still a bit bizarre. It doesn't seem to use its first parameter.

#Comment by Brion VIBBER (talk | contribs)   00:00, 29 April 2009

I believe it's a hook parameter, providing the move-page-form object. If it's not needed here it makes sense not to use it. :)

#Comment by Werdna (talk | contribs)   00:16, 29 April 2009

Move query is definitely indexed, and seems to work

Query was:
UPDATE /* Drafts::move Andrew */  `drafts` SET draft_namespace = '0',draft_title = 'Mian_Page' WHERE draft_page = '1'

mysql> explain select * from drafts WHERE draft_page = '1';
+----+-------------+--------+------+---------------+------------+---------+-------+------+-------+
| id | select_type | table  | type | possible_keys | key        | key_len | ref   | rows | Extra |
+----+-------------+--------+------+---------------+------------+---------+-------+------+-------+
|  1 | SIMPLE      | drafts | ref  | draft_page    | draft_page | 4       | const |    1 |       | 
+----+-------------+--------+------+---------------+------------+---------+-------+------+-------+
1 row in set (0.00 sec)

Status & tagging log