Index: trunk/extensions/FlaggedRevs/FlaggedRevs.php |
— | — | @@ -66,6 +66,7 @@ |
67 | 67 | # Can users make comments that will show up below flagged revisions? |
68 | 68 | # NOTE: this is NOT the same as the simple log comment |
69 | 69 | $wgFlaggedRevsComments = false; // @TODO: remove when ready? |
| 70 | + |
70 | 71 | # Auto-review settings for edits/new pages: |
71 | 72 | # FR_AUTOREVIEW_NONE |
72 | 73 | # Don't auto-review any edits or new pages |
— | — | @@ -242,6 +243,7 @@ |
243 | 244 | $wgAutoloadClasses['FlaggedRevs'] = $dir . 'FlaggedRevs.class.php'; |
244 | 245 | $wgAutoloadClasses['FRUserCounters'] = $dir . 'FRUserCounters.php'; |
245 | 246 | $wgAutoloadClasses['FRInclusionManager'] = $dir . 'FRInclusionManager.php'; |
| 247 | +$wgAutoloadClasses['FRUserActivity'] = $dir . 'FRUserActivity.php'; |
246 | 248 | $wgAutoloadClasses['FlaggedRevsHooks'] = $dir . 'FlaggedRevs.hooks.php'; |
247 | 249 | $wgAutoloadClasses['FlaggedRevsLogs'] = $dir . 'FlaggedRevsLogs.php'; |
248 | 250 | $wgAutoloadClasses['FRExtraCacheUpdate'] = $dir . 'FRExtraCacheUpdate.php'; |
Index: trunk/extensions/FlaggedRevs/language/FlaggedRevs.i18n.php |
— | — | @@ -192,7 +192,8 @@ |
193 | 193 | 'revreview-submit-unreviewed' => 'Done. Unaccepted!', |
194 | 194 | 'revreview-successful' => '\'\'\'Revision of [[:$1|$1]] successfully flagged. ([{{fullurl:{{#Special:ReviewedVersions}}|page=$2}} view reviewed versions])\'\'\'', |
195 | 195 | 'revreview-successful2' => '\'\'\'Revision of [[:$1|$1]] successfully unflagged.\'\'\'', |
196 | | - 'revreview-text' => '\'\'[[{{MediaWiki:Validationpage}}|Reviewed versions]] are checked versions of pages used to determine the stable version.\'\'', |
| 196 | + 'revreview-poss-conflict-p' => '\'\'\'WARNING: Another user, [[User:$1|$1]], just started reviewing this page at $2.\'\'\'', |
| 197 | + 'revreview-poss-conflict-c' => '\'\'\'WARNING: Another user, [[User:$1|$1]], just started reviewing these changes at $2.\'\'\'', |
197 | 198 | 'revreview-toggle-show' => '(+)', |
198 | 199 | 'revreview-toggle-hide' => '(-)', |
199 | 200 | 'revreview-toggle-title' => 'show/hide details', |
Index: trunk/extensions/FlaggedRevs/forms/RevisionReviewForm.php |
— | — | @@ -644,7 +644,7 @@ |
645 | 645 | User $user, FlaggedArticle $article, Revision $rev, |
646 | 646 | $refId = 0, $topNotice = '', $templateIDs, $imageSHA1Keys |
647 | 647 | ) { |
648 | | - global $wgOut, $wgParser, $wgEnableParserCache; |
| 648 | + global $wgOut, $wgLang, $wgParser, $wgEnableParserCache; |
649 | 649 | $id = $rev->getId(); |
650 | 650 | if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { |
651 | 651 | return false; # The revision must be valid and public |
— | — | @@ -705,9 +705,18 @@ |
706 | 706 | $form .= Xml::closeElement( 'legend' ) . "\n"; |
707 | 707 | # Show explanatory text |
708 | 708 | $form .= $topNotice; |
709 | | - if ( !FlaggedRevs::lowProfileUI() ) { |
710 | | - $form .= wfMsgExt( 'revreview-text', array( 'parse' ) ); |
| 709 | + # Show possible conflict warning msg |
| 710 | + if ( $refId ) { |
| 711 | + list( $u, $ts ) = FRUserActivity::getUserReviewingDiff( $refId, $rev->getId() ); |
| 712 | + } else { |
| 713 | + list( $u, $ts ) = FRUserActivity::getUserReviewingPage( $rev->getPage() ); |
711 | 714 | } |
| 715 | + if ( $u !== null && $u != $user->getName() ) { |
| 716 | + $msg = $refId ? 'revreview-poss-conflict-c' : 'revreview-poss-conflict-p'; |
| 717 | + $form .= '<p><span class="fr-under-review">' . |
| 718 | + wfMsgExt( $msg, 'parseinline', $u, $wgLang->timeanddate( $ts, true ) ) . |
| 719 | + '</span></p>'; |
| 720 | + } |
712 | 721 | |
713 | 722 | if ( $disabled ) { |
714 | 723 | $form .= Xml::openElement( 'div', array( 'class' => 'fr-rating-controls-disabled', |
Index: trunk/extensions/FlaggedRevs/specialpages/PendingChanges_body.php |
— | — | @@ -209,7 +209,7 @@ |
210 | 210 | } |
211 | 211 | |
212 | 212 | public function formatRow( $row ) { |
213 | | - global $wgLang, $wgUser, $wgMemc; |
| 213 | + global $wgLang, $wgUser; |
214 | 214 | $css = $quality = $underReview = ''; |
215 | 215 | |
216 | 216 | $title = Title::newFromRow( $row ); |
— | — | @@ -229,7 +229,7 @@ |
230 | 230 | } |
231 | 231 | # Is anybody watching? |
232 | 232 | if ( !$this->including() && $wgUser->isAllowed( 'unreviewedpages' ) ) { |
233 | | - $uw = UnreviewedPages::usersWatching( $title ); |
| 233 | + $uw = FRUserActivity::numUsersWatchingPage( $title ); |
234 | 234 | $watching = $uw |
235 | 235 | ? wfMsgExt( 'pendingchanges-watched', 'parsemag', $wgLang->formatNum( $uw ) ) |
236 | 236 | : wfMsgHtml( 'pendingchanges-unwatched' ); |
— | — | @@ -259,9 +259,9 @@ |
260 | 260 | } else { |
261 | 261 | $age = ""; // wtf? |
262 | 262 | } |
263 | | - $key = wfMemcKey( 'stableDiffs', 'underReview', $row->stable, $row->page_latest ); |
264 | 263 | # Show if a user is looking at this page |
265 | | - if ( $wgMemc->get( $key ) ) { |
| 264 | + list( $u, $ts ) = FRUserActivity::getUserReviewingDiff( $row->stable, $row->page_latest ); |
| 265 | + if ( $u !== null ) { |
266 | 266 | $underReview = ' <span class="fr-under-review">' . |
267 | 267 | wfMsgHtml( 'pendingchanges-viewing' ) . '</span>'; |
268 | 268 | } |
Index: trunk/extensions/FlaggedRevs/specialpages/UnreviewedPages_body.php |
— | — | @@ -92,7 +92,7 @@ |
93 | 93 | } |
94 | 94 | |
95 | 95 | public function formatRow( $row ) { |
96 | | - global $wgLang, $wgUser, $wgMemc; |
| 96 | + global $wgLang, $wgUser; |
97 | 97 | |
98 | 98 | $stxt = $underReview = $watching = ''; |
99 | 99 | $title = Title::newFromRow( $row ); |
— | — | @@ -122,7 +122,7 @@ |
123 | 123 | $age = ' ' . wfMsg( 'unreviewedpages-recent' ); // hot off the press :) |
124 | 124 | } |
125 | 125 | if ( $wgUser->isAllowed( 'unwatchedpages' ) ) { |
126 | | - $uw = self::usersWatching( $title ); |
| 126 | + $uw = FRUserActivity::numUsersWatchingPage( $title ); |
127 | 127 | $watching = $uw |
128 | 128 | ? wfMsgExt( 'unreviewedpages-watched', 'parsemag', $wgLang->formatNum( $uw ) ) |
129 | 129 | : wfMsgHtml( 'unreviewedpages-unwatched' ); |
— | — | @@ -132,53 +132,18 @@ |
133 | 133 | } |
134 | 134 | $css = self::getLineClass( $hours, $uw ); |
135 | 135 | $css = $css ? " class='$css'" : ""; |
136 | | - $pageId = isset( $row->page_id ) ? $row->page_id : $row->qc_value; |
137 | | - $key = wfMemcKey( 'unreviewedPages', 'underReview', $pageId ); |
138 | | - $val = $wgMemc->get( $key ); |
| 136 | + |
139 | 137 | # Show if a user is looking at this page |
140 | | - if ( $val ) { |
141 | | - $underReview = " <b class='fr-under-review'>" . |
142 | | - wfMsgHtml( 'unreviewedpages-viewing' ) . '</b>'; |
| 138 | + list( $u, $ts ) = FRUserActivity::getUserReviewingPage( $row->page_id ); |
| 139 | + if ( $u !== null ) { |
| 140 | + $underReview = " <span class='fr-under-review'>" . |
| 141 | + wfMsgHtml( 'unreviewedpages-viewing' ) . '</span>'; |
143 | 142 | } |
144 | 143 | |
145 | 144 | return( "<li{$css}>{$link} {$stxt} ({$hist})" . |
146 | 145 | "{$age}{$watching}{$underReview}</li>" ); |
147 | 146 | } |
148 | | - |
149 | | - /** |
150 | | - * Get number of users watching a page. |
151 | | - * @param Title $title |
152 | | - * @return int |
153 | | - */ |
154 | | - public static function usersWatching( Title $title ) { |
155 | | - global $wgMiserMode, $wgCookieExpiration; |
156 | | - $dbr = wfGetDB( DB_SLAVE ); |
157 | | - $count = - 1; |
158 | | - if ( $wgMiserMode ) { |
159 | | - # Get a rough idea of size |
160 | | - $count = $dbr->estimateRowCount( 'watchlist', '*', |
161 | | - array( 'wl_namespace' => $title->getNamespace(), |
162 | | - 'wl_title' => $title->getDBkey() ), |
163 | | - __METHOD__ ); |
164 | | - } |
165 | | - # If it is small, just COUNT() it, otherwise, stick with estimate... |
166 | | - if ( $count == - 1 || $count <= 100 ) { |
167 | | - # Get number of active editors watchling this |
168 | | - $cutoff = $dbr->timestamp( wfTimestamp( TS_UNIX ) - 2 * $wgCookieExpiration ); |
169 | | - $res = $dbr->select( array( 'watchlist', 'user' ), '1', |
170 | | - array( 'wl_namespace' => $title->getNamespace(), |
171 | | - 'wl_title' => $title->getDBkey(), |
172 | | - 'wl_user = user_id', |
173 | | - // logged in or out |
174 | | - 'user_touched > ' . $dbr->addQuotes( $cutoff ) ), |
175 | | - __METHOD__, |
176 | | - array( 'USE INDEX' => array( 'watchlist' => 'namespace_title' ) ) |
177 | | - ); |
178 | | - $count = $dbr->numRows( $res ); |
179 | | - } |
180 | | - return (int)$count; |
181 | | - } |
182 | | - |
| 147 | + |
183 | 148 | protected static function getLineClass( $hours, $uw ) { |
184 | 149 | if ( $uw == 0 ) |
185 | 150 | return 'fr-unreviewed-unwatched'; |
— | — | @@ -189,7 +154,7 @@ |
190 | 155 | else |
191 | 156 | return ""; |
192 | 157 | } |
193 | | - |
| 158 | + |
194 | 159 | /** |
195 | 160 | * There may be many pages, most of which are reviewed |
196 | 161 | */ |
— | — | @@ -303,8 +268,8 @@ |
304 | 269 | |
305 | 270 | function getQueryCacheInfo() { |
306 | 271 | $conds = $this->mConds; |
307 | | - $fields = array( 'page_namespace', 'page_title', 'page_len', 'qc_value', |
308 | | - 'MIN(rev_timestamp) AS creation' ); |
| 272 | + $fields = array( 'page_namespace', 'page_title', 'page_len', 'page_id', |
| 273 | + 'qc_value', 'MIN(rev_timestamp) AS creation' ); |
309 | 274 | # Re-join on flaggedpages to double-check since things |
310 | 275 | # could have changed since the cache date. Also, use |
311 | 276 | # the proper cache for this level. |
Index: trunk/extensions/FlaggedRevs/specialpages/ProblemChanges_body.php |
— | — | @@ -173,7 +173,7 @@ |
174 | 174 | } |
175 | 175 | |
176 | 176 | public function formatRow( $row ) { |
177 | | - global $wgLang, $wgUser, $wgMemc; |
| 177 | + global $wgLang, $wgUser; |
178 | 178 | $css = $quality = $tags = $underReview = ''; |
179 | 179 | |
180 | 180 | $title = Title::newFromRow( $row ); |
— | — | @@ -196,7 +196,7 @@ |
197 | 197 | } |
198 | 198 | # Is anybody watching? |
199 | 199 | if ( !$this->including() && $wgUser->isAllowed( 'unreviewedpages' ) ) { |
200 | | - $uw = UnreviewedPages::usersWatching( $title ); |
| 200 | + $uw = FRUserActivity::numUsersWatchingPage( $title ); |
201 | 201 | $watching = $uw |
202 | 202 | ? wfMsgExt( 'pendingchanges-watched', 'parsemag', $wgLang->formatNum( $uw ) ) |
203 | 203 | : wfMsgHtml( 'pendingchanges-unwatched' ); |
— | — | @@ -228,9 +228,9 @@ |
229 | 229 | } else { |
230 | 230 | $age = ""; // wtf? |
231 | 231 | } |
232 | | - $key = wfMemcKey( 'stableDiffs', 'underReview', $row->stable, $row->page_latest ); |
233 | 232 | # Show if a user is looking at this page |
234 | | - if ( $wgMemc->get( $key ) ) { |
| 233 | + list( $u, $ts ) = FRUserActivity::getUserReviewingDiff( $row->stable, $row->page_latest ); |
| 234 | + if ( $u !== null ) { |
235 | 235 | $underReview = ' <span class="fr-under-review">' . |
236 | 236 | wfMsgHtml( 'pendingchanges-viewing' ) . '</span>'; |
237 | 237 | } |
Index: trunk/extensions/FlaggedRevs/FlaggedRevs.hooks.php |
— | — | @@ -133,14 +133,16 @@ |
134 | 134 | |
135 | 135 | // Mark when an unreviewed page is being reviewed |
136 | 136 | protected static function maybeMarkUnderReview( FlaggedArticle $fa, WebRequest $request ) { |
137 | | - global $wgMemc; |
| 137 | + global $wgUser; |
| 138 | + if ( !$request->getInt( 'reviewing' ) && !$request->getInt( 'rcid' ) ) { |
| 139 | + return true; // not implied by URL |
| 140 | + } |
138 | 141 | # Set a key to note when someone is reviewing this. |
139 | 142 | # NOTE: diff-to-stable views already handled elsewhere. |
140 | | - if ( $request->getInt( 'reviewing' ) || $request->getInt( 'rcid' ) ) { |
141 | | - if ( $fa->isReviewable() && $fa->getTitle()->userCan( 'review' ) ) { |
142 | | - $key = wfMemcKey( 'unreviewedPages', 'underReview', $fa->getId() ); |
143 | | - $wgMemc->set( $key, '1', 20 * 60 ); |
144 | | - } |
| 143 | + if ( $fa->isReviewable() && !$fa->getStable() // not reviewed yet |
| 144 | + && $fa->getTitle()->userCan( 'review' ) ) |
| 145 | + { |
| 146 | + FRUserActivity::setUserReviewingPage( $wgUser, $fa->getID() ); |
145 | 147 | } |
146 | 148 | return true; |
147 | 149 | } |
— | — | @@ -2027,4 +2029,4 @@ |
2028 | 2030 | } |
2029 | 2031 | return true; |
2030 | 2032 | } |
2031 | | -} |
| 2033 | +} |
\ No newline at end of file |
Index: trunk/extensions/FlaggedRevs/FRUserActivity.php |
— | — | @@ -0,0 +1,132 @@ |
| 2 | +<?php |
| 3 | +/* |
| 4 | +* Class of utility functions for getting/tracking user activity |
| 5 | +*/ |
| 6 | +class FRUserActivity { |
| 7 | + /** |
| 8 | + * Get number of active users watching a page |
| 9 | + * @param Title $title |
| 10 | + * @return int |
| 11 | + */ |
| 12 | + public static function numUsersWatchingPage( Title $title ) { |
| 13 | + global $wgMemc, $wgCookieExpiration; |
| 14 | + # Check the cache... |
| 15 | + $key = wfMemcKey( 'flaggedrevs', 'usersWatching', $title->getArticleID() ); |
| 16 | + $val = $wgMemc->get( $key ); |
| 17 | + if ( is_int( $val ) ) { |
| 18 | + return $val; // cache hit |
| 19 | + } |
| 20 | + # Get number of active editors watching this page... |
| 21 | + $dbr = wfGetDB( DB_SLAVE ); |
| 22 | + $cutoff = $dbr->timestamp( wfTimestamp( TS_UNIX ) - 2 * $wgCookieExpiration ); |
| 23 | + $count = (int)$dbr->selectField( |
| 24 | + array( 'watchlist', 'user' ), |
| 25 | + 'COUNT(*)', |
| 26 | + array( |
| 27 | + 'wl_namespace' => $title->getNamespace(), |
| 28 | + 'wl_title' => $title->getDBkey(), |
| 29 | + 'wl_user = user_id', |
| 30 | + 'user_touched > ' . $dbr->addQuotes( $cutoff ) // logged in or out |
| 31 | + ), |
| 32 | + __METHOD__, |
| 33 | + array( 'USE INDEX' => array( 'watchlist' => 'namespace_title' ) ) |
| 34 | + ); |
| 35 | + if ( $count > 10 ) { |
| 36 | + # Save new value to cache (more aggresive for larger counts) |
| 37 | + $wgMemc->set( $key, $count, ( $count > 200 ) ? 30*60 : 5*60 ); |
| 38 | + } |
| 39 | + |
| 40 | + return $count; |
| 41 | + } |
| 42 | + |
| 43 | + /* |
| 44 | + * Get who is currently reviewing a page |
| 45 | + * @param int $pageId |
| 46 | + * @return array (username or null, MW timestamp or null) |
| 47 | + */ |
| 48 | + public static function getUserReviewingPage( $pageId ) { |
| 49 | + global $wgMemc; |
| 50 | + $key = wfMemcKey( 'flaggedrevs', 'userReviewingPage', $pageId ); |
| 51 | + $val = $wgMemc->get( $key ); |
| 52 | + if ( is_array( $val ) && count( $val ) == 2 ) { |
| 53 | + return $val; |
| 54 | + } |
| 55 | + return array( null, null ); |
| 56 | + } |
| 57 | + |
| 58 | + /* |
| 59 | + * Set the flag for who is reviewing a page if not already set by someone |
| 60 | + * @param User $user |
| 61 | + * @param int $pageId |
| 62 | + * @return bool flag set |
| 63 | + */ |
| 64 | + public static function setUserReviewingPage( $user, $pageId ) { |
| 65 | + global $wgMemc; |
| 66 | + $key = wfMemcKey( 'flaggedrevs', 'userReviewingPage', $pageId ); |
| 67 | + $val = array( $user->getName(), wfTimestampNow() ); |
| 68 | + if ( !$wgMemc->get( $key ) ) { // no flag set |
| 69 | + # Set the flag (use locks if available) |
| 70 | + $wgMemc->lock( $key, 4000 ); // 4 sec timeout |
| 71 | + $wgMemc->set( $key, $val, 20*60 ); // 20 min |
| 72 | + $wgMemc->unlock( $key ); |
| 73 | + return true; |
| 74 | + } |
| 75 | + return false; |
| 76 | + } |
| 77 | + |
| 78 | + /* |
| 79 | + * Clear the flag for who is reviewing a page |
| 80 | + * @param int $pageId |
| 81 | + */ |
| 82 | + public static function clearUserReviewingPage( $pageId ) { |
| 83 | + global $wgMemc; |
| 84 | + $key = wfMemcKey( 'flaggedrevs', 'userReviewingPage', $pageId ); |
| 85 | + $wgMemc->delete( $key ); |
| 86 | + } |
| 87 | + |
| 88 | + /* |
| 89 | + * Get who is currently reviewing a diff |
| 90 | + * @param int $oldId |
| 91 | + * @param int $newId |
| 92 | + * @return array (username or null, MW timestamp or null) |
| 93 | + */ |
| 94 | + public static function getUserReviewingDiff( $oldId, $newId ) { |
| 95 | + global $wgMemc; |
| 96 | + $key = wfMemcKey( 'flaggedrevs', 'userReviewingDiff', $oldId, $newId ); |
| 97 | + $val = $wgMemc->get( $key ); |
| 98 | + if ( is_array( $val ) && count( $val ) == 2 ) { |
| 99 | + return $val; |
| 100 | + } |
| 101 | + return array( null, null ); |
| 102 | + } |
| 103 | + |
| 104 | + /* |
| 105 | + * Set the flag for who is reviewing a diff if not already set by someone |
| 106 | + * @param User $user |
| 107 | + * @param int $pageId |
| 108 | + * @return bool flag set |
| 109 | + */ |
| 110 | + public static function setUserReviewingDiff( $user, $oldId, $newId ) { |
| 111 | + global $wgMemc; |
| 112 | + $key = wfMemcKey( 'flaggedrevs', 'userReviewingDiff', $oldId, $newId ); |
| 113 | + $val = array( $user->getName(), wfTimestampNow() ); |
| 114 | + if ( !$wgMemc->get( $key ) ) { // no flag set |
| 115 | + # Set the flag (use locks if available) |
| 116 | + $wgMemc->lock( $key, 4000 ); // 4 sec timeout |
| 117 | + $wgMemc->set( $key, $val, 6*20 ); // 6 min |
| 118 | + $wgMemc->unlock( $key ); |
| 119 | + return true; |
| 120 | + } |
| 121 | + return false; |
| 122 | + } |
| 123 | + |
| 124 | + /* |
| 125 | + * Clear the flag for who is reviewing a diff |
| 126 | + * @param int $pageId |
| 127 | + */ |
| 128 | + public static function clearUserReviewingDiff( $oldId, $newId ) { |
| 129 | + global $wgMemc; |
| 130 | + $key = wfMemcKey( 'flaggedrevs', 'userReviewingDiff', $oldId, $newId ); |
| 131 | + $wgMemc->delete( $key ); |
| 132 | + } |
| 133 | +} |
Property changes on: trunk/extensions/FlaggedRevs/FRUserActivity.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 134 | + native |
Index: trunk/extensions/FlaggedRevs/FlaggedArticleView.php |
— | — | @@ -1387,7 +1387,8 @@ |
1388 | 1388 | # If the user can review then prompt them to review them... |
1389 | 1389 | if ( $wgUser->isAllowed( 'review' ) ) { |
1390 | 1390 | # Set a key to note that someone is viewing this |
1391 | | - $this->markDiffUnderReview( $oldRev, $newRev ); |
| 1391 | + FRUserActivity::setUserReviewingDiff( |
| 1392 | + $wgUser, $oldRev->getId(), $newRev->getId() ); |
1392 | 1393 | // Reviewer just edited... |
1393 | 1394 | if ( $wgRequest->getInt( 'shownotice' ) |
1394 | 1395 | && $newRev->isCurrent() |
— | — | @@ -1580,13 +1581,6 @@ |
1581 | 1582 | return $diffLinks; |
1582 | 1583 | } |
1583 | 1584 | |
1584 | | - // Mark that someone is viewing a portion or all of the diff-to-stable |
1585 | | - protected function markDiffUnderReview( Revision $oldRev, Revision $newRev ) { |
1586 | | - global $wgMemc; |
1587 | | - $key = wfMemcKey( 'stableDiffs', 'underReview', $oldRev->getID(), $newRev->getID() ); |
1588 | | - $wgMemc->set( $key, '1', 6 * 60 ); |
1589 | | - } |
1590 | | - |
1591 | 1585 | /** |
1592 | 1586 | * Set $this->isDiffFromStable and $this->isMultiPageDiff fields |
1593 | 1587 | * Note: $oldRev could be false |