MediaWiki master
ApiSetNotificationTimestamp.php
Go to the documentation of this file.
1<?php
2
12namespace MediaWiki\Api;
13
22use Wikimedia\Timestamp\TimestampFormat as TS;
23
29
31 private $mPageSet = null;
32
33 public function __construct(
34 ApiMain $main,
35 string $action,
36 private readonly IConnectionProvider $dbProvider,
37 private readonly RevisionStore $revisionStore,
38 private readonly WatchedItemStoreInterface $watchedItemStore,
39 private readonly TitleFormatter $titleFormatter,
40 private readonly TitleFactory $titleFactory,
41 ) {
42 parent::__construct( $main, $action );
43 }
44
45 public function execute() {
46 $user = $this->getUser();
47
48 if ( !$user->isRegistered() ) {
49 $this->dieWithError( 'watchlistanontext', 'notloggedin' );
50 }
51 $this->checkUserRightsAny( 'editmywatchlist' );
52
53 $params = $this->extractRequestParams();
54 $this->requireMaxOneParameter( $params, 'timestamp', 'torevid', 'newerthanrevid' );
55
56 $continuationManager = new ApiContinuationManager( $this, [], [] );
57 $this->setContinuationManager( $continuationManager );
58
59 $pageSet = $this->getPageSet();
60 if ( $params['entirewatchlist'] && $pageSet->getDataSource() !== null ) {
61 $this->dieWithError(
62 [
63 'apierror-invalidparammix-cannotusewith',
64 $this->encodeParamName( 'entirewatchlist' ),
65 $pageSet->encodeParamName( $pageSet->getDataSource() )
66 ],
67 'multisource'
68 );
69 }
70
71 $dbw = $this->dbProvider->getPrimaryDatabase();
72
73 $timestamp = null;
74 if ( isset( $params['timestamp'] ) ) {
75 $timestamp = $dbw->timestamp( $params['timestamp'] );
76 }
77
78 if ( !$params['entirewatchlist'] ) {
79 $pageSet->execute();
80 }
81
82 if ( isset( $params['torevid'] ) ) {
83 if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
84 $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'torevid' ) ] );
85 }
86 $titles = $pageSet->getGoodPages();
87 $title = reset( $titles );
88 if ( $title ) {
89 // XXX $title isn't actually used, can we just get rid of the previous six lines?
90 $timestamp = $this->revisionStore->getTimestampFromId(
91 $params['torevid'],
92 IDBAccessObject::READ_LATEST
93 );
94 if ( $timestamp ) {
95 $timestamp = $dbw->timestamp( $timestamp );
96 } else {
97 $timestamp = null;
98 }
99 }
100 } elseif ( isset( $params['newerthanrevid'] ) ) {
101 if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
102 $this->dieWithError( [ 'apierror-multpages', $this->encodeParamName( 'newerthanrevid' ) ] );
103 }
104 $titles = $pageSet->getGoodPages();
105 $title = reset( $titles );
106 if ( $title ) {
107 $timestamp = null;
108 $currRev = $this->revisionStore->getRevisionById(
109 $params['newerthanrevid'],
110 IDBAccessObject::READ_LATEST
111 );
112 if ( $currRev ) {
113 $nextRev = $this->revisionStore->getNextRevision(
114 $currRev,
115 IDBAccessObject::READ_LATEST
116 );
117 if ( $nextRev ) {
118 $timestamp = $dbw->timestamp( $nextRev->getTimestamp() );
119 }
120 }
121 }
122 }
123
124 $apiResult = $this->getResult();
125 $result = [];
126 if ( $params['entirewatchlist'] ) {
127 // Entire watchlist mode: Just update the thing and return a success indicator
128 $this->watchedItemStore->resetAllNotificationTimestampsForUser( $user, $timestamp );
129
130 $result['notificationtimestamp'] = $timestamp === null
131 ? ''
132 : wfTimestamp( TS::ISO_8601, $timestamp );
133 } else {
134 // First, log the invalid titles
135 foreach ( $pageSet->getInvalidTitlesAndReasons() as $r ) {
136 $r['invalid'] = true;
137 $result[] = $r;
138 }
139 foreach ( $pageSet->getMissingPageIDs() as $p ) {
140 $result[] = [
141 'pageid' => $p,
142 'missing' => true,
143 'notwatched' => true,
144 ];
145 }
146 foreach ( $pageSet->getMissingRevisionIDs() as $r ) {
147 $result[] = [
148 'revid' => $r,
149 'missing' => true,
150 'notwatched' => true,
151 ];
152 }
153
154 $pages = $pageSet->getPages();
155 if ( $pages ) {
156 // Now process the valid titles
157 $this->watchedItemStore->setNotificationTimestampsForUser(
158 $user,
159 $timestamp,
160 $pages
161 );
162
163 // Query the results of our update
164 $timestamps = $this->watchedItemStore->getNotificationTimestampsBatch(
165 $user,
166 $pages
167 );
168
169 // Now, put the valid titles into the result
171 foreach ( $pages as $page ) {
172 $ns = $page->getNamespace();
173 $dbkey = $page->getDBkey();
174 $r = [
175 'ns' => $ns,
176 'title' => $this->titleFormatter->getPrefixedText( $page ),
177 ];
178 if ( !$page->exists() ) {
179 $r['missing'] = true;
180 $title = $this->titleFactory->newFromPageIdentity( $page );
181 if ( $title->isKnown() ) {
182 $r['known'] = true;
183 }
184 }
185 if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] )
186 && $timestamps[$ns][$dbkey] !== false
187 ) {
188 $r['notificationtimestamp'] = '';
189 if ( $timestamps[$ns][$dbkey] !== null ) {
190 $r['notificationtimestamp'] = wfTimestamp( TS::ISO_8601, $timestamps[$ns][$dbkey] );
191 }
192 } else {
193 $r['notwatched'] = true;
194 }
195 $result[] = $r;
196 }
197 }
198
199 ApiResult::setIndexedTagName( $result, 'page' );
200 }
201 $apiResult->addValue( null, $this->getModuleName(), $result );
202
203 $this->setContinuationManager( null );
204 $continuationManager->setContinuationIntoResult( $apiResult );
205 }
206
211 private function getPageSet() {
212 $this->mPageSet ??= new ApiPageSet( $this );
213
214 return $this->mPageSet;
215 }
216
218 public function mustBePosted() {
219 return true;
220 }
221
223 public function isWriteMode() {
224 return true;
225 }
226
228 public function needsToken() {
229 return 'csrf';
230 }
231
233 public function getAllowedParams( $flags = 0 ) {
234 $result = [
235 'entirewatchlist' => [
236 ParamValidator::PARAM_TYPE => 'boolean'
237 ],
238 'timestamp' => [
239 ParamValidator::PARAM_TYPE => 'timestamp'
240 ],
241 'torevid' => [
242 ParamValidator::PARAM_TYPE => 'integer'
243 ],
244 'newerthanrevid' => [
245 ParamValidator::PARAM_TYPE => 'integer'
246 ],
247 'continue' => [
248 ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
249 ],
250 ];
251 if ( $flags ) {
252 $result += $this->getPageSet()->getFinalParams( $flags );
253 }
254
255 return $result;
256 }
257
259 protected function getExamplesMessages() {
260 $title = Title::newMainPage()->getPrefixedText();
261 $mp = rawurlencode( $title );
262
263 return [
264 'action=setnotificationtimestamp&entirewatchlist=&token=123ABC'
265 => 'apihelp-setnotificationtimestamp-example-all',
266 "action=setnotificationtimestamp&titles={$mp}&token=123ABC"
267 => 'apihelp-setnotificationtimestamp-example-page',
268 "action=setnotificationtimestamp&titles={$mp}&" .
269 'timestamp=2012-01-01T00:00:00Z&token=123ABC'
270 => 'apihelp-setnotificationtimestamp-example-pagetimestamp',
271 'action=setnotificationtimestamp&generator=allpages&gapnamespace=2&token=123ABC'
272 => 'apihelp-setnotificationtimestamp-example-allpages',
273 ];
274 }
275
277 public function getHelpUrls() {
278 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:SetNotificationTimestamp';
279 }
280}
281
283class_alias( ApiSetNotificationTimestamp::class, 'ApiSetNotificationTimestamp' );
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:60
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1522
checkUserRightsAny( $rights)
Helper function for permission-denied errors.
Definition ApiBase.php:1631
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:557
getResult()
Get the result object.
Definition ApiBase.php:696
requireMaxOneParameter( $params,... $required)
Dies if more than one parameter from a certain set of parameters are set and not false.
Definition ApiBase.php:1012
setContinuationManager(?ApiContinuationManager $manager=null)
Definition ApiBase.php:743
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:166
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition ApiBase.php:815
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:837
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:66
This class contains a list of pages that the client has requested.
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
API interface for setting the wl_notificationtimestamp field.
getHelpUrls()
Return links to more detailed help pages about the module.1.25, returning boolean false is deprecated...
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
isWriteMode()
Indicates whether this module requires write access to the wiki.API modules must override this method...
__construct(ApiMain $main, string $action, private readonly IConnectionProvider $dbProvider, private readonly RevisionStore $revisionStore, private readonly WatchedItemStoreInterface $watchedItemStore, private readonly TitleFormatter $titleFormatter, private readonly TitleFactory $titleFactory,)
mustBePosted()
Indicates whether this module must be called with a POST request.Implementations of this method must ...
needsToken()
Returns the token type this module requires in order to execute.Modules are strongly encouraged to us...
getExamplesMessages()
Returns usage examples for this module.Return value has query strings as keys, with values being eith...
Service for looking up page revisions.
Creates Title objects.
A title formatter service for MediaWiki.
Represents a title within MediaWiki.
Definition Title.php:69
Service for formatting and validating API parameters.
Interface for objects (potentially) representing an editable wiki page.
Provide primary and replica IDatabase connections.
Interface for database access objects.
Helper trait for implementations \DAO.