4 * API for MediaWiki 1.14+
6 * Copyright © 2012 Wikimedia Foundation and contributors
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/gpl.html
26 namespace MediaWiki\Api
;
28 use MediaWiki\Revision\RevisionStore
;
29 use MediaWiki\Title\Title
;
30 use MediaWiki\Title\TitleFactory
;
31 use MediaWiki\Title\TitleFormatter
;
32 use MediaWiki\Watchlist\WatchedItemStoreInterface
;
33 use Wikimedia\ParamValidator\ParamValidator
;
34 use Wikimedia\Rdbms\IConnectionProvider
;
35 use Wikimedia\Rdbms\IDBAccessObject
;
38 * API interface for setting the wl_notificationtimestamp field
41 class ApiSetNotificationTimestamp
extends ApiBase
{
43 /** @var ApiPageSet|null */
44 private $mPageSet = null;
46 private RevisionStore
$revisionStore;
47 private IConnectionProvider
$dbProvider;
48 private WatchedItemStoreInterface
$watchedItemStore;
49 private TitleFormatter
$titleFormatter;
50 private TitleFactory
$titleFactory;
52 public function __construct(
55 IConnectionProvider
$dbProvider,
56 RevisionStore
$revisionStore,
57 WatchedItemStoreInterface
$watchedItemStore,
58 TitleFormatter
$titleFormatter,
59 TitleFactory
$titleFactory
61 parent
::__construct( $main, $action );
63 $this->dbProvider
= $dbProvider;
64 $this->revisionStore
= $revisionStore;
65 $this->watchedItemStore
= $watchedItemStore;
66 $this->titleFormatter
= $titleFormatter;
67 $this->titleFactory
= $titleFactory;
70 public function execute() {
71 $user = $this->getUser();
73 if ( !$user->isRegistered() ) {
74 $this->dieWithError( 'watchlistanontext', 'notloggedin' );
76 $this->checkUserRightsAny( 'editmywatchlist' );
78 $params = $this->extractRequestParams();
79 $this->requireMaxOneParameter( $params, 'timestamp', 'torevid', 'newerthanrevid' );
81 $continuationManager = new ApiContinuationManager( $this, [], [] );
82 $this->setContinuationManager( $continuationManager );
84 $pageSet = $this->getPageSet();
85 if ( $params['entirewatchlist'] && $pageSet->getDataSource() !== null ) {
88 'apierror-invalidparammix-cannotusewith',
89 $this->encodeParamName( 'entirewatchlist' ),
90 $pageSet->encodeParamName( $pageSet->getDataSource() )
96 $dbw = $this->dbProvider
->getPrimaryDatabase();
99 if ( isset( $params['timestamp'] ) ) {
100 $timestamp = $dbw->timestamp( $params['timestamp'] );
103 if ( !$params['entirewatchlist'] ) {
107 if ( isset( $params['torevid'] ) ) {
108 if ( $params['entirewatchlist'] ||
$pageSet->getGoodTitleCount() > 1 ) {
109 $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'torevid' ) ] );
111 $titles = $pageSet->getGoodPages();
112 $title = reset( $titles );
114 // XXX $title isn't actually used, can we just get rid of the previous six lines?
115 $timestamp = $this->revisionStore
->getTimestampFromId(
117 IDBAccessObject
::READ_LATEST
120 $timestamp = $dbw->timestamp( $timestamp );
125 } elseif ( isset( $params['newerthanrevid'] ) ) {
126 if ( $params['entirewatchlist'] ||
$pageSet->getGoodTitleCount() > 1 ) {
127 $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'newerthanrevid' ) ] );
129 $titles = $pageSet->getGoodPages();
130 $title = reset( $titles );
133 $currRev = $this->revisionStore
->getRevisionById(
134 $params['newerthanrevid'],
135 IDBAccessObject
::READ_LATEST
138 $nextRev = $this->revisionStore
->getNextRevision(
140 IDBAccessObject
::READ_LATEST
143 $timestamp = $dbw->timestamp( $nextRev->getTimestamp() );
149 $apiResult = $this->getResult();
151 if ( $params['entirewatchlist'] ) {
152 // Entire watchlist mode: Just update the thing and return a success indicator
153 $this->watchedItemStore
->resetAllNotificationTimestampsForUser( $user, $timestamp );
155 $result['notificationtimestamp'] = $timestamp === null
157 : wfTimestamp( TS_ISO_8601
, $timestamp );
159 // First, log the invalid titles
160 foreach ( $pageSet->getInvalidTitlesAndReasons() as $r ) {
161 $r['invalid'] = true;
164 foreach ( $pageSet->getMissingPageIDs() as $p ) {
166 $page['pageid'] = $p;
167 $page['missing'] = true;
168 $page['notwatched'] = true;
171 foreach ( $pageSet->getMissingRevisionIDs() as $r ) {
174 $rev['missing'] = true;
175 $rev['notwatched'] = true;
179 $pages = $pageSet->getPages();
181 // Now process the valid titles
182 $this->watchedItemStore
->setNotificationTimestampsForUser(
188 // Query the results of our update
189 $timestamps = $this->watchedItemStore
->getNotificationTimestampsBatch(
194 // Now, put the valid titles into the result
195 /** @var \MediaWiki\Page\PageIdentity $page */
196 foreach ( $pages as $page ) {
197 $ns = $page->getNamespace();
198 $dbkey = $page->getDBkey();
201 'title' => $this->titleFormatter
->getPrefixedText( $page ),
203 if ( !$page->exists() ) {
204 $r['missing'] = true;
205 $title = $this->titleFactory
->newFromPageIdentity( $page );
206 if ( $title->isKnown() ) {
210 if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] )
211 && $timestamps[$ns][$dbkey] !== false
213 $r['notificationtimestamp'] = '';
214 if ( $timestamps[$ns][$dbkey] !== null ) {
215 $r['notificationtimestamp'] = wfTimestamp( TS_ISO_8601
, $timestamps[$ns][$dbkey] );
218 $r['notwatched'] = true;
224 ApiResult
::setIndexedTagName( $result, 'page' );
226 $apiResult->addValue( null, $this->getModuleName(), $result );
228 $this->setContinuationManager( null );
229 $continuationManager->setContinuationIntoResult( $apiResult );
233 * Get a cached instance of an ApiPageSet object
236 private function getPageSet() {
237 $this->mPageSet ??
= new ApiPageSet( $this );
239 return $this->mPageSet
;
242 public function mustBePosted() {
246 public function isWriteMode() {
250 public function needsToken() {
254 public function getAllowedParams( $flags = 0 ) {
256 'entirewatchlist' => [
257 ParamValidator
::PARAM_TYPE
=> 'boolean'
260 ParamValidator
::PARAM_TYPE
=> 'timestamp'
263 ParamValidator
::PARAM_TYPE
=> 'integer'
265 'newerthanrevid' => [
266 ParamValidator
::PARAM_TYPE
=> 'integer'
269 ApiBase
::PARAM_HELP_MSG
=> 'api-help-param-continue',
273 $result +
= $this->getPageSet()->getFinalParams( $flags );
279 protected function getExamplesMessages() {
280 $title = Title
::newMainPage()->getPrefixedText();
281 $mp = rawurlencode( $title );
284 'action=setnotificationtimestamp&entirewatchlist=&token=123ABC'
285 => 'apihelp-setnotificationtimestamp-example-all',
286 "action=setnotificationtimestamp&titles={$mp}&token=123ABC"
287 => 'apihelp-setnotificationtimestamp-example-page',
288 "action=setnotificationtimestamp&titles={$mp}&" .
289 'timestamp=2012-01-01T00:00:00Z&token=123ABC'
290 => 'apihelp-setnotificationtimestamp-example-pagetimestamp',
291 'action=setnotificationtimestamp&generator=allpages&gapnamespace=2&token=123ABC'
292 => 'apihelp-setnotificationtimestamp-example-allpages',
296 public function getHelpUrls() {
297 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:SetNotificationTimestamp';
301 /** @deprecated class alias since 1.43 */
302 class_alias( ApiSetNotificationTimestamp
::class, 'ApiSetNotificationTimestamp' );