* @ingroup Watchlist
*/
class WatchedItem {
- var $mTitle, $mUser;
+ /**
+ * Constant to specify that user rights 'editmywatchlist' and
+ * 'viewmywatchlist' should not be checked.
+ * @since 1.22
+ */
+ const IGNORE_USER_RIGHTS = 0;
+
+ /**
+ * Constant to specify that user rights 'editmywatchlist' and
+ * 'viewmywatchlist' should be checked.
+ * @since 1.22
+ */
+ const CHECK_USER_RIGHTS = 1;
+
+ var $mTitle, $mUser, $mCheckRights;
private $loaded = false, $watched, $timestamp;
/**
* Create a WatchedItem object with the given user and title
+ * @since 1.22 $checkRights parameter added
* @param $user User: the user to use for (un)watching
* @param $title Title: the title we're going to (un)watch
+ * @param $checkRights int: Whether to check the 'viewmywatchlist' and 'editmywatchlist' rights.
+ * Pass either WatchedItem::IGNORE_USER_RIGHTS or WatchedItem::CHECK_USER_RIGHTS.
* @return WatchedItem object
*/
- public static function fromUserTitle( $user, $title ) {
+ public static function fromUserTitle( $user, $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
$wl = new WatchedItem;
$wl->mUser = $user;
$wl->mTitle = $title;
+ $wl->mCheckRights = $checkRights;
return $wl;
}
}
$this->loaded = true;
+ // Only loggedin user can have a watchlist
+ if ( $this->mUser->isAnon() ) {
+ $this->watched = false;
+ return;
+ }
+
# Pages and their talk pages are considered equivalent for watching;
# remember that talk namespaces are numbered as page namespace+1.
}
}
+ /**
+ * Check permissions
+ * @param $what string: 'viewmywatchlist' or 'editmywatchlist'
+ */
+ private function isAllowed( $what ) {
+ return !$this->mCheckRights || $this->mUser->isAllowed( $what );
+ }
+
/**
* Is mTitle being watched by mUser?
* @return bool
*/
public function isWatched() {
+ if ( !$this->isAllowed( 'viewmywatchlist' ) ) {
+ return false;
+ }
+
$this->load();
return $this->watched;
}
* the wl_notificationtimestamp field otherwise
*/
public function getNotificationTimestamp() {
+ if ( !$this->isAllowed( 'viewmywatchlist' ) ) {
+ return false;
+ }
+
$this->load();
if ( $this->watched ) {
return $this->timestamp;
*
* @param $force Whether to force the write query to be executed even if the
* page is not watched or the notification timestamp is already NULL.
+ * @param int $oldid The revision id being viewed. If not given or 0, latest revision is assumed.
*/
- public function resetNotificationTimestamp( $force = '' ) {
+ public function resetNotificationTimestamp( $force = '', $oldid = 0 ) {
+ // Only loggedin user can have a watchlist
+ if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
+ return;
+ }
+
if ( $force != 'force' ) {
$this->load();
if ( !$this->watched || $this->timestamp === null ) {
}
}
+ $title = $this->getTitle();
+ if ( !$oldid ) {
+ // No oldid given, assuming latest revision; clear the timestamp.
+ $notificationTimestamp = null;
+ } elseif ( !$title->getNextRevisionID( $oldid ) ) {
+ // Oldid given and is the latest revision for this title; clear the timestamp.
+ $notificationTimestamp = null;
+ } else {
+ // See if the version marked as read is more recent than the one we're viewing.
+ // Call load() if it wasn't called before due to $force.
+ $this->load();
+
+ if ( $this->timestamp === null ) {
+ // This can only happen if $force is enabled.
+ $notificationTimestamp = null;
+ } else {
+ // Oldid given and isn't the latest; update the timestamp.
+ // This will result in no further notification emails being sent!
+ $dbr = wfGetDB( DB_SLAVE );
+ $notificationTimestamp = $dbr->selectField(
+ 'revision', 'rev_timestamp',
+ array( 'rev_page' => $title->getArticleID(), 'rev_id' => $oldid )
+ );
+ // We need to go one second to the future because of various strict comparisons
+ // throughout the codebase
+ $ts = new MWTimestamp( $notificationTimestamp );
+ $ts->timestamp->add( new DateInterval( 'PT1S' ) );
+ $notificationTimestamp = $ts->getTimestamp( TS_MW );
+
+ if ( $notificationTimestamp < $this->timestamp ) {
+ if ( $force != 'force' ) {
+ return;
+ } else {
+ // This is a little silly…
+ $notificationTimestamp = $this->timestamp;
+ }
+ }
+ }
+ }
+
// If the page is watched by the user (or may be watched), update the timestamp on any
// any matching rows
$dbw = wfGetDB( DB_MASTER );
- $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => null ),
+ $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $notificationTimestamp ),
$this->dbCond(), __METHOD__ );
$this->timestamp = null;
}
/**
* Given a title and user (assumes the object is setup), add the watch to the
* database.
- * @return bool (always true)
+ * @return bool
*/
public function addWatch() {
wfProfileIn( __METHOD__ );
+ // Only loggedin user can have a watchlist
+ if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
+ wfProfileOut( __METHOD__ );
+ return false;
+ }
+
// Use INSERT IGNORE to avoid overwriting the notification timestamp
// if there's already an entry for this page
$dbw = wfGetDB( DB_MASTER );
public function removeWatch() {
wfProfileIn( __METHOD__ );
+ // Only loggedin user can have a watchlist
+ if ( wfReadOnly() || $this->mUser->isAnon() || !$this->isAllowed( 'editmywatchlist' ) ) {
+ wfProfileOut( __METHOD__ );
+ return false;
+ }
+
$success = false;
$dbw = wfGetDB( DB_MASTER );
$dbw->delete( 'watchlist',