MediaWiki  master
ApiSetNotificationTimestamp.php
Go to the documentation of this file.
1 <?php
2 
29 
35 
36  private $mPageSet = null;
37 
39  private $revisionStore;
40 
42  private $loadBalancer;
43 
45  private $watchedItemStore;
46 
54  public function __construct(
55  ApiMain $main,
56  $action,
57  ILoadBalancer $loadBalancer,
58  RevisionStore $revisionStore,
59  WatchedItemStoreInterface $watchedItemStore
60  ) {
61  parent::__construct( $main, $action );
62 
63  $this->loadBalancer = $loadBalancer;
64  $this->revisionStore = $revisionStore;
65  $this->watchedItemStore = $watchedItemStore;
66  }
67 
68  public function execute() {
69  $user = $this->getUser();
70 
71  if ( !$user->isRegistered() ) {
72  $this->dieWithError( 'watchlistanontext', 'notloggedin' );
73  }
74  $this->checkUserRightsAny( 'editmywatchlist' );
75 
76  $params = $this->extractRequestParams();
77  $this->requireMaxOneParameter( $params, 'timestamp', 'torevid', 'newerthanrevid' );
78 
79  $continuationManager = new ApiContinuationManager( $this, [], [] );
80  $this->setContinuationManager( $continuationManager );
81 
82  $pageSet = $this->getPageSet();
83  if ( $params['entirewatchlist'] && $pageSet->getDataSource() !== null ) {
84  $this->dieWithError(
85  [
86  'apierror-invalidparammix-cannotusewith',
87  $this->encodeParamName( 'entirewatchlist' ),
88  $pageSet->encodeParamName( $pageSet->getDataSource() )
89  ],
90  'multisource'
91  );
92  }
93 
94  $dbw = $this->loadBalancer->getConnectionRef( DB_PRIMARY, 'api' );
95 
96  $timestamp = null;
97  if ( isset( $params['timestamp'] ) ) {
98  $timestamp = $dbw->timestamp( $params['timestamp'] );
99  }
100 
101  if ( !$params['entirewatchlist'] ) {
102  $pageSet->execute();
103  }
104 
105  if ( isset( $params['torevid'] ) ) {
106  if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
107  $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'torevid' ) ] );
108  }
109  $titles = $pageSet->getGoodTitles();
110  $title = reset( $titles );
111  if ( $title ) {
112  // XXX $title isn't actually used, can we just get rid of the previous six lines?
113  $timestamp = $this->revisionStore->getTimestampFromId(
114  $params['torevid'],
115  IDBAccessObject::READ_LATEST
116  );
117  if ( $timestamp ) {
118  $timestamp = $dbw->timestamp( $timestamp );
119  } else {
120  $timestamp = null;
121  }
122  }
123  } elseif ( isset( $params['newerthanrevid'] ) ) {
124  if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
125  $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'newerthanrevid' ) ] );
126  }
127  $titles = $pageSet->getGoodTitles();
128  $title = reset( $titles );
129  if ( $title ) {
130  $timestamp = null;
131  $currRev = $this->revisionStore->getRevisionById(
132  $params['newerthanrevid'],
133  Title::READ_LATEST
134  );
135  if ( $currRev ) {
136  $nextRev = $this->revisionStore->getNextRevision(
137  $currRev,
138  Title::READ_LATEST
139  );
140  if ( $nextRev ) {
141  $timestamp = $dbw->timestamp( $nextRev->getTimestamp() );
142  }
143  }
144  }
145  }
146 
147  $apiResult = $this->getResult();
148  $result = [];
149  if ( $params['entirewatchlist'] ) {
150  // Entire watchlist mode: Just update the thing and return a success indicator
151  $this->watchedItemStore->resetAllNotificationTimestampsForUser( $user, $timestamp );
152 
153  $result['notificationtimestamp'] = $timestamp === null
154  ? ''
155  : wfTimestamp( TS_ISO_8601, $timestamp );
156  } else {
157  // First, log the invalid titles
158  foreach ( $pageSet->getInvalidTitlesAndReasons() as $r ) {
159  $r['invalid'] = true;
160  $result[] = $r;
161  }
162  foreach ( $pageSet->getMissingPageIDs() as $p ) {
163  $page = [];
164  $page['pageid'] = $p;
165  $page['missing'] = true;
166  $page['notwatched'] = true;
167  $result[] = $page;
168  }
169  foreach ( $pageSet->getMissingRevisionIDs() as $r ) {
170  $rev = [];
171  $rev['revid'] = $r;
172  $rev['missing'] = true;
173  $rev['notwatched'] = true;
174  $result[] = $rev;
175  }
176 
177  if ( $pageSet->getPages() ) {
178  // Now process the valid titles
179  $this->watchedItemStore->setNotificationTimestampsForUser(
180  $user,
181  $timestamp,
182  $pageSet->getPages()
183  );
184 
185  // Query the results of our update
186  $timestamps = $this->watchedItemStore->getNotificationTimestampsBatch(
187  $user,
188  $pageSet->getPages()
189  );
190 
191  // Now, put the valid titles into the result
193  foreach ( $pageSet->getTitles() as $title ) {
194  $ns = $title->getNamespace();
195  $dbkey = $title->getDBkey();
196  $r = [
197  'ns' => $ns,
198  'title' => $title->getPrefixedText(),
199  ];
200  if ( !$title->exists() ) {
201  $r['missing'] = true;
202  if ( $title->isKnown() ) {
203  $r['known'] = true;
204  }
205  }
206  if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] )
207  && $timestamps[$ns][$dbkey] !== false
208  ) {
209  $r['notificationtimestamp'] = '';
210  if ( $timestamps[$ns][$dbkey] !== null ) {
211  $r['notificationtimestamp'] = wfTimestamp( TS_ISO_8601, $timestamps[$ns][$dbkey] );
212  }
213  } else {
214  $r['notwatched'] = true;
215  }
216  $result[] = $r;
217  }
218  }
219 
220  ApiResult::setIndexedTagName( $result, 'page' );
221  }
222  $apiResult->addValue( null, $this->getModuleName(), $result );
223 
224  $this->setContinuationManager( null );
225  $continuationManager->setContinuationIntoResult( $apiResult );
226  }
227 
232  private function getPageSet() {
233  if ( $this->mPageSet === null ) {
234  $this->mPageSet = new ApiPageSet( $this );
235  }
236 
237  return $this->mPageSet;
238  }
239 
240  public function mustBePosted() {
241  return true;
242  }
243 
244  public function isWriteMode() {
245  return true;
246  }
247 
248  public function needsToken() {
249  return 'csrf';
250  }
251 
252  public function getAllowedParams( $flags = 0 ) {
253  $result = [
254  'entirewatchlist' => [
255  ParamValidator::PARAM_TYPE => 'boolean'
256  ],
257  'timestamp' => [
258  ParamValidator::PARAM_TYPE => 'timestamp'
259  ],
260  'torevid' => [
261  ParamValidator::PARAM_TYPE => 'integer'
262  ],
263  'newerthanrevid' => [
264  ParamValidator::PARAM_TYPE => 'integer'
265  ],
266  'continue' => [
267  ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
268  ],
269  ];
270  if ( $flags ) {
271  $result += $this->getPageSet()->getFinalParams( $flags );
272  }
273 
274  return $result;
275  }
276 
277  protected function getExamplesMessages() {
278  return [
279  'action=setnotificationtimestamp&entirewatchlist=&token=123ABC'
280  => 'apihelp-setnotificationtimestamp-example-all',
281  'action=setnotificationtimestamp&titles=Main_page&token=123ABC'
282  => 'apihelp-setnotificationtimestamp-example-page',
283  'action=setnotificationtimestamp&titles=Main_page&' .
284  'timestamp=2012-01-01T00:00:00Z&token=123ABC'
285  => 'apihelp-setnotificationtimestamp-example-pagetimestamp',
286  'action=setnotificationtimestamp&generator=allpages&gapnamespace=2&token=123ABC'
287  => 'apihelp-setnotificationtimestamp-example-allpages',
288  ];
289  }
290 
291  public function getHelpUrls() {
292  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:SetNotificationTimestamp';
293  }
294 }
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:56
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition: ApiBase.php:1458
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1567
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition: ApiBase.php:743
requireMaxOneParameter( $params,... $required)
Die if more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:938
setContinuationManager(ApiContinuationManager $manager=null)
Definition: ApiBase.php:673
getResult()
Get the result object.
Definition: ApiBase.php:629
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:765
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition: ApiBase.php:163
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:498
This manages continuation state.
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:52
This class contains a list of pages that the client has requested.
Definition: ApiPageSet.php:50
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
API interface for setting the wl_notificationtimestamp field.
getExamplesMessages()
Returns usage examples for this module.
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
getHelpUrls()
Return links to more detailed help pages about the module.
mustBePosted()
Indicates whether this module must be called with a POST request.
__construct(ApiMain $main, $action, ILoadBalancer $loadBalancer, RevisionStore $revisionStore, WatchedItemStoreInterface $watchedItemStore)
needsToken()
Returns the token type this module requires in order to execute.
isWriteMode()
Indicates whether this module requires write mode.
Service for looking up page revisions.
Service for formatting and validating API parameters.
Database cluster connection, tracking, load balancing, and transaction manager interface.
const DB_PRIMARY
Definition: defines.php:28