r111085 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r111084‎ | r111085 | r111086 >
Date:20:39, 9 February 2012
Author:maxsem
Status:ok (Comments)
Tags:needs-php-test, todo 
Comment:
(bug 28936, bug 5280) Broken or invalid titles can't be removed from watchlist. Now titles are fixed or deleted, if unfixable, upon loading Special:EditWatchlist.
Modified paths:
  • /trunk/phase3/RELEASE-NOTES-1.19 (modified) (history)
  • /trunk/phase3/includes/User.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialEditWatchlist.php (modified) (history)

Diff [purge]

Index: trunk/phase3/RELEASE-NOTES-1.19
@@ -246,6 +246,7 @@
247247 getText() on a non-object
248248 * (bug 31676) Group dynamically inserted CSS into a single <style> tag, to work
249249 around a bug where not all styles were applied in Internet Explorer
 250+* (bug 28936, bug 5280) Broken or invalid titles can't be removed from watchlist.
250251
251252 === API changes in 1.19 ===
252253 * Made action=edit less likely to return "unknownerror", by returning the actual error
Index: trunk/phase3/includes/User.php
@@ -2602,14 +2602,6 @@
26032603 }
26042604
26052605 /**
2606 - * Cleans up watchlist by removing invalid entries from it
2607 - */
2608 - public function cleanupWatchlist() {
2609 - $dbw = wfGetDB( DB_MASTER );
2610 - $dbw->delete( 'watchlist', array( 'wl_namespace < 0', 'wl_user' => $this->getId() ), __METHOD__ );
2611 - }
2612 -
2613 - /**
26142606 * Clear the user's notification timestamp for the given title.
26152607 * If e-notif e-mails are on, they will receive notification mails on
26162608 * the next change of the page if it's watched etc.
Index: trunk/phase3/includes/specials/SpecialEditWatchlist.php
@@ -23,6 +23,8 @@
2424
2525 protected $toc;
2626
 27+ private $badItems = array();
 28+
2729 public function __construct(){
2830 parent::__construct( 'EditWatchlist' );
2931 }
@@ -224,11 +226,15 @@
225227 if( $res->numRows() > 0 ) {
226228 foreach ( $res as $row ) {
227229 $title = Title::makeTitleSafe( $row->wl_namespace, $row->wl_title );
228 - if( $title instanceof Title && !$title->isTalkPage() )
 230+ if ( $this->checkTitle( $title, $row->wl_namespace, $row->wl_title )
 231+ && !$title->isTalkPage()
 232+ ) {
229233 $list[] = $title->getPrefixedText();
 234+ }
230235 }
231236 $res->free();
232237 }
 238+ $this->cleanupWatchlist();
233239 return $list;
234240 }
235241
@@ -263,6 +269,60 @@
264270 }
265271
266272 /**
 273+ * Validates watchlist entry
 274+ *
 275+ * @param Title $title
 276+ * @param int $namespace
 277+ * @param String $dbKey
 278+ * @return bool: Whether this item is valid
 279+ */
 280+ private function checkTitle( $title, $namespace, $dbKey ) {
 281+ if ( $title
 282+ && ( $title->isExternal()
 283+ || $title->getNamespace() < 0
 284+ )
 285+ ) {
 286+ $title = false; // unrecoverable
 287+ }
 288+ if ( !$title
 289+ || $title->getNamespace() != $namespace
 290+ || $title->getDBkey() != $dbKey
 291+ ) {
 292+ $this->badItems[] = array( $title, $namespace, $dbKey );
 293+ }
 294+ return (bool)$title;
 295+ }
 296+
 297+ /**
 298+ * Attempts to clean up broken items
 299+ */
 300+ private function cleanupWatchlist() {
 301+ if ( count( $this->badItems ) ) {
 302+ $dbw = wfGetDB( DB_MASTER );
 303+ }
 304+ foreach ( $this->badItems as $row ) {
 305+ list( $title, $namespace, $dbKey ) = $row;
 306+ wfDebug( "User {$this->getUser()} has broken watchlist item ns($namespace):$dbKey, "
 307+ . ( $title ? 'cleaning up' : 'deleting' ) . ".\n"
 308+ );
 309+
 310+ $dbw->delete( 'watchlist',
 311+ array(
 312+ 'wl_user' => $this->getUser()->getId(),
 313+ 'wl_namespace' => $namespace,
 314+ 'wl_title' => $dbKey,
 315+ ),
 316+ __METHOD__
 317+ );
 318+
 319+ // Can't just do an UPDATE instead of DELETE/INSERT due to unique index
 320+ if ( $title ) {
 321+ $this->getUser()->addWatch( $title );
 322+ }
 323+ }
 324+ }
 325+
 326+ /**
267327 * Remove all titles from a user's watchlist
268328 */
269329 private function clearWatchlist() {
@@ -375,30 +435,25 @@
376436 $fields = array();
377437 $count = 0;
378438
379 - $haveInvalidNamespaces = false;
380439 foreach( $this->getWatchlistInfo() as $namespace => $pages ){
381 - if ( $namespace < 0 ) {
382 - $haveInvalidNamespaces = true;
383 - continue;
 440+ if ( $namespace >= 0 ) {
 441+ $fields['TitlesNs'.$namespace] = array(
 442+ 'class' => 'EditWatchlistCheckboxSeriesField',
 443+ 'options' => array(),
 444+ 'section' => "ns$namespace",
 445+ );
384446 }
385447
386 - $fields['TitlesNs'.$namespace] = array(
387 - 'class' => 'EditWatchlistCheckboxSeriesField',
388 - 'options' => array(),
389 - 'section' => "ns$namespace",
390 - );
391 -
392448 foreach( array_keys( $pages ) as $dbkey ){
393449 $title = Title::makeTitleSafe( $namespace, $dbkey );
394 - $text = $this->buildRemoveLine( $title );
395 - $fields['TitlesNs'.$namespace]['options'][$text] = $title->getEscapedText();
396 - $count++;
 450+ if ( $this->checkTitle( $title, $namespace, $dbkey ) ) {
 451+ $text = $this->buildRemoveLine( $title );
 452+ $fields['TitlesNs'.$namespace]['options'][$text] = $title->getEscapedText();
 453+ $count++;
 454+ }
397455 }
398456 }
399 - if ( $haveInvalidNamespaces ) {
400 - wfDebug( "User {$this->getContext()->getUser()->getId()} has invalid watchlist entries, cleaning up...\n" );
401 - $this->getContext()->getUser()->cleanupWatchlist();
402 - }
 457+ $this->cleanupWatchlist();
403458
404459 if ( count( $fields ) > 1 && $count > 30 ) {
405460 $this->toc = Linker::tocIndent();

Follow-up revisions

RevisionCommit summaryAuthorDate
r111175REL1_19: MFT r111029, r111034, r111067, r111076, r111085, r111128, r111144reedy18:37, 10 February 2012

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r45389Disallow broken Talk:File:x type titles (bug 5280)aaron09:39, 4 January 2009
r45479Revert r45389 "Disallow broken Talk:File:x type titles (bug 5280)"...brion02:55, 7 January 2009
r45780Redid r45389 "Disallow broken Talk:File:x type titles (bug 5280)"aaron18:36, 15 January 2009

Comments

#Comment by Nikerabbit (talk | contribs)   08:52, 10 February 2012
+	 * @param Title $title

Should be in order @param $title Title. Also it is misleading since the function also expects null/false.

#Comment by MaxSem (talk | contribs)   11:34, 10 February 2012

Doxygen understands both - unlike NetBeans which I use.

#Comment by Nikerabbit (talk | contribs)   11:58, 10 February 2012

It's inconsistent. Although I kind of like that syntax more than the unreadable @param $title title title of the page.

#Comment by Bawolff (talk | contribs)   13:20, 10 February 2012

In my testing, when it cleans up watchlist page entries, for a normal (non-raw) edit, it doesn't properly delete the bad entries for the corresponding talk page.

For example, I added some invalid stuff to my watchlist:

mysql> select wl_namespace, concat( "[", wl_title, "]" ) from watchlist;
+--------------+------------------------------+
| wl_namespace | concat( "[", wl_title, "]" ) |
+--------------+------------------------------+
|            0 | [spacing cha R2]           | 
|            0 | [spacing cha r]            | 
|            1 | [spacing cha r]            | 
|           82 | [ns 82]                      | 
|           83 | [ns 82]                      | 
+--------------+------------------------------+

After doing an edit to it, the entries looked like:

mysql> select wl_namespace, concat( "[", wl_title, "]" ) from watchlist;
+--------------+------------------------------+
| wl_namespace | concat( "[", wl_title, "]" ) |
+--------------+------------------------------+
|            0 | [ns_82]                      | 
|            0 | [spacing_cha_R2]             | 
|            0 | [spacing_cha_r]              | 
|            1 | [ns_82]                      | 
|            1 | [spacing cha r]            | 
|            1 | [spacing_cha_R2]             | 
|            1 | [spacing_cha_r]              | 
|           83 | [ns 82]                      | 
+--------------+------------------------------+

Where they should have looked like:

mysql> select wl_namespace, concat( "[", wl_title, "]" ) from watchlist;
+--------------+------------------------------+
| wl_namespace | concat( "[", wl_title, "]" ) |
+--------------+------------------------------+
|            0 | [ns_82]                      | 
|            0 | [spacing_cha_R2]             | 
|            0 | [spacing_cha_r]              | 
|            1 | [ns_82]                      | 
|            1 | [spacing_cha_R2]             | 
|            1 | [spacing_cha_r]              | 
+--------------+------------------------------+

This issue does not seem to occour when doing raw edits. (And its really not a major issue, db looks wrong, but they're not displayed to user, so should be ok).

Additionally, it seems like the entries that are removed from watchlist as invalid sometimes still end up on the edit page (but won't if you reload the page). This seems to be true for the raw view for all types of entries, and for the normal edit mode, this is true only for my article in namespace 82.

(For reference, I should say i have no namespace 82 defined)

These are rather minor issues though, and certainly much better than the old behaviour.

#Comment by Hashar (talk | contribs)   19:57, 14 February 2012
if ( $this->checkTitle( $title, $row->wl_namespace, $row->wl_title )
+					&& !$title->isTalkPage()
+				) {

That isTalkPage should probably be part of the checkTitle() method.


User->cleanupWatchlist() should be properly deprecated for back compatibility (it is a public function).


A new class property probably deserve a new comment :-)

+	private $badItems = array();


In cleanupWatchlist() the foreach on badTitle seems to be inserting those bad titles back in the DB:

if ( $title ) {
+				$this->getUser()->addWatch( $title );
+			}
#Comment by MaxSem (talk | contribs)   21:05, 14 February 2012

> User->cleanupWatchlist() should be properly deprecated for back compatibility (it is a public function).

But it had no callers whatsoever save this code that was there just for one version.

> In cleanupWatchlist() the foreach on badTitle seems to be inserting those bad titles back in the DB

This code path is for updating of titles normalised by Title::secureAndSplit(), what's your definition of 'bad'?

#Comment by Hashar (talk | contribs)   21:25, 14 February 2012

> > User->cleanupWatchlist() should be properly deprecated for back compatibility (it is a public function). > But it had no callers whatsoever save this code that was there just for one version.

It still deserves a proper deprecation in my opinion. Just in case someone decided to use it with 1.18 :-( But maybe I am just too paranoid.

#Comment by Hashar (talk | contribs)   21:27, 14 February 2012

> This code path is for updating of titles normalised by Title::secureAndSplit(), what's your definition of 'bad'?

Oh the bad title array contains a safe title. Guess that is just misleading variable names. Maybe renames $title to $safeTitle.

#Comment by Aaron Schulz (talk | contribs)   00:47, 23 February 2012
- if ( $namespace < 0 ) {
- $haveInvalidNamespaces = true;
- continue;

You replaced this with an "if", but it no longer breaks out before the inner loop on $pages.

#Comment by Aaron Schulz (talk | contribs)   20:51, 1 March 2012

This is OK with the checkTitle() below.

#Comment by Aaron Schulz (talk | contribs)   20:53, 1 March 2012

Overall, this is OK. I don't like the object state changes in checkTitle(), it should take an argument by reference that builds the list rather than mutating some weird member variable.

From bawolf's comments, this still needs some work to finish the job, but the commit is a working improvement.

Status & tagging log