MediaWiki
REL1_22
|
00001 <?php 00029 class WatchedItem { 00035 const IGNORE_USER_RIGHTS = 0; 00036 00042 const CHECK_USER_RIGHTS = 1; 00043 00044 var $mTitle, $mUser, $mCheckRights; 00045 private $loaded = false, $watched, $timestamp; 00046 00056 public static function fromUserTitle( $user, $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) { 00057 $wl = new WatchedItem; 00058 $wl->mUser = $user; 00059 $wl->mTitle = $title; 00060 $wl->mCheckRights = $checkRights; 00061 00062 return $wl; 00063 } 00064 00069 protected function getTitle() { 00070 return $this->mTitle; 00071 } 00072 00074 protected function getTitleNs() { 00075 return $this->getTitle()->getNamespace(); 00076 } 00077 00079 protected function getTitleDBkey() { 00080 return $this->getTitle()->getDBkey(); 00081 } 00083 protected function getUserId() { 00084 return $this->mUser->getId(); 00085 } 00086 00093 private function dbCond() { 00094 return array( 00095 'wl_user' => $this->getUserId(), 00096 'wl_namespace' => $this->getTitleNs(), 00097 'wl_title' => $this->getTitleDBkey(), 00098 ); 00099 } 00100 00104 private function load() { 00105 if ( $this->loaded ) { 00106 return; 00107 } 00108 $this->loaded = true; 00109 00110 // Only loggedin user can have a watchlist 00111 if ( $this->mUser->isAnon() ) { 00112 $this->watched = false; 00113 return; 00114 } 00115 00116 # Pages and their talk pages are considered equivalent for watching; 00117 # remember that talk namespaces are numbered as page namespace+1. 00118 00119 $dbr = wfGetDB( DB_SLAVE ); 00120 $row = $dbr->selectRow( 'watchlist', 'wl_notificationtimestamp', 00121 $this->dbCond(), __METHOD__ ); 00122 00123 if ( $row === false ) { 00124 $this->watched = false; 00125 } else { 00126 $this->watched = true; 00127 $this->timestamp = $row->wl_notificationtimestamp; 00128 } 00129 } 00130 00135 private function isAllowed( $what ) { 00136 return !$this->mCheckRights || $this->mUser->isAllowed( $what ); 00137 } 00138 00143 public function isWatched() { 00144 if ( !$this->isAllowed( 'viewmywatchlist' ) ) { 00145 return false; 00146 } 00147 00148 $this->load(); 00149 return $this->watched; 00150 } 00151 00158 public function getNotificationTimestamp() { 00159 if ( !$this->isAllowed( 'viewmywatchlist' ) ) { 00160 return false; 00161 } 00162 00163 $this->load(); 00164 if ( $this->watched ) { 00165 return $this->timestamp; 00166 } else { 00167 return false; 00168 } 00169 } 00170 00177 public function resetNotificationTimestamp( $force = '' ) { 00178 // Only loggedin user can have a watchlist 00179 if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) { 00180 return; 00181 } 00182 00183 if ( $force != 'force' ) { 00184 $this->load(); 00185 if ( !$this->watched || $this->timestamp === null ) { 00186 return; 00187 } 00188 } 00189 00190 // If the page is watched by the user (or may be watched), update the timestamp on any 00191 // any matching rows 00192 $dbw = wfGetDB( DB_MASTER ); 00193 $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => null ), 00194 $this->dbCond(), __METHOD__ ); 00195 $this->timestamp = null; 00196 } 00197 00203 public function addWatch() { 00204 wfProfileIn( __METHOD__ ); 00205 00206 // Only loggedin user can have a watchlist 00207 if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) { 00208 wfProfileOut( __METHOD__ ); 00209 return false; 00210 } 00211 00212 // Use INSERT IGNORE to avoid overwriting the notification timestamp 00213 // if there's already an entry for this page 00214 $dbw = wfGetDB( DB_MASTER ); 00215 $dbw->insert( 'watchlist', 00216 array( 00217 'wl_user' => $this->getUserId(), 00218 'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ), 00219 'wl_title' => $this->getTitleDBkey(), 00220 'wl_notificationtimestamp' => null 00221 ), __METHOD__, 'IGNORE' ); 00222 00223 // Every single watched page needs now to be listed in watchlist; 00224 // namespace:page and namespace_talk:page need separate entries: 00225 $dbw->insert( 'watchlist', 00226 array( 00227 'wl_user' => $this->getUserId(), 00228 'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ), 00229 'wl_title' => $this->getTitleDBkey(), 00230 'wl_notificationtimestamp' => null 00231 ), __METHOD__, 'IGNORE' ); 00232 00233 $this->watched = true; 00234 00235 wfProfileOut( __METHOD__ ); 00236 return true; 00237 } 00238 00243 public function removeWatch() { 00244 wfProfileIn( __METHOD__ ); 00245 00246 // Only loggedin user can have a watchlist 00247 if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) { 00248 wfProfileOut( __METHOD__ ); 00249 return false; 00250 } 00251 00252 $success = false; 00253 $dbw = wfGetDB( DB_MASTER ); 00254 $dbw->delete( 'watchlist', 00255 array( 00256 'wl_user' => $this->getUserId(), 00257 'wl_namespace' => MWNamespace::getSubject( $this->getTitleNs() ), 00258 'wl_title' => $this->getTitleDBkey(), 00259 ), __METHOD__ 00260 ); 00261 if ( $dbw->affectedRows() ) { 00262 $success = true; 00263 } 00264 00265 # the following code compensates the new behavior, introduced by the 00266 # enotif patch, that every single watched page needs now to be listed 00267 # in watchlist namespace:page and namespace_talk:page had separate 00268 # entries: clear them 00269 $dbw->delete( 'watchlist', 00270 array( 00271 'wl_user' => $this->getUserId(), 00272 'wl_namespace' => MWNamespace::getTalk( $this->getTitleNs() ), 00273 'wl_title' => $this->getTitleDBkey(), 00274 ), __METHOD__ 00275 ); 00276 00277 if ( $dbw->affectedRows() ) { 00278 $success = true; 00279 } 00280 00281 $this->watched = false; 00282 00283 wfProfileOut( __METHOD__ ); 00284 return $success; 00285 } 00286 00294 public static function duplicateEntries( $ot, $nt ) { 00295 WatchedItem::doDuplicateEntries( $ot->getSubjectPage(), $nt->getSubjectPage() ); 00296 WatchedItem::doDuplicateEntries( $ot->getTalkPage(), $nt->getTalkPage() ); 00297 } 00298 00307 private static function doDuplicateEntries( $ot, $nt ) { 00308 $oldnamespace = $ot->getNamespace(); 00309 $newnamespace = $nt->getNamespace(); 00310 $oldtitle = $ot->getDBkey(); 00311 $newtitle = $nt->getDBkey(); 00312 00313 $dbw = wfGetDB( DB_MASTER ); 00314 $res = $dbw->select( 'watchlist', 'wl_user', 00315 array( 'wl_namespace' => $oldnamespace, 'wl_title' => $oldtitle ), 00316 __METHOD__, 'FOR UPDATE' 00317 ); 00318 # Construct array to replace into the watchlist 00319 $values = array(); 00320 foreach ( $res as $s ) { 00321 $values[] = array( 00322 'wl_user' => $s->wl_user, 00323 'wl_namespace' => $newnamespace, 00324 'wl_title' => $newtitle 00325 ); 00326 } 00327 00328 if ( empty( $values ) ) { 00329 // Nothing to do 00330 return true; 00331 } 00332 00333 # Perform replace 00334 # Note that multi-row replace is very efficient for MySQL but may be inefficient for 00335 # some other DBMSes, mostly due to poor simulation by us 00336 $dbw->replace( 'watchlist', array( array( 'wl_user', 'wl_namespace', 'wl_title' ) ), $values, __METHOD__ ); 00337 return true; 00338 } 00339 }