Merge "Unsetting the email address for a user when the email address is invalidated."
[lhc/web/wiklou.git] / includes / api / ApiSetNotificationTimestamp.php
1 <?php
2
3 /**
4 * API for MediaWiki 1.14+
5 *
6 * Created on Jun 18, 2012
7 *
8 * Copyright © 2012 Brad Jorsch
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/gpl.html
24 *
25 * @file
26 */
27
28 /**
29 * API interface for setting the wl_notificationtimestamp field
30 * @ingroup API
31 */
32 class ApiSetNotificationTimestamp extends ApiBase {
33
34 private $mPageSet;
35
36 public function execute() {
37 $user = $this->getUser();
38
39 if ( $user->isAnon() ) {
40 $this->dieUsage( 'Anonymous users cannot use watchlist change notifications', 'notloggedin' );
41 }
42 if ( !$user->isAllowed( 'editmywatchlist' ) ) {
43 $this->dieUsage( 'You don\'t have permission to edit your watchlist', 'permissiondenied' );
44 }
45
46 $params = $this->extractRequestParams();
47 $this->requireMaxOneParameter( $params, 'timestamp', 'torevid', 'newerthanrevid' );
48
49 $this->getResult()->beginContinuation( $params['continue'], array(), array() );
50
51 $pageSet = $this->getPageSet();
52 if ( $params['entirewatchlist'] && $pageSet->getDataSource() !== null ) {
53 $this->dieUsage(
54 "Cannot use 'entirewatchlist' at the same time as '{$pageSet->getDataSource()}'",
55 'multisource'
56 );
57 }
58
59 $dbw = wfGetDB( DB_MASTER, 'api' );
60
61 $timestamp = null;
62 if ( isset( $params['timestamp'] ) ) {
63 $timestamp = $dbw->timestamp( $params['timestamp'] );
64 }
65
66 if ( !$params['entirewatchlist'] ) {
67 $pageSet->execute();
68 }
69
70 if ( isset( $params['torevid'] ) ) {
71 if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
72 $this->dieUsage( 'torevid may only be used with a single page', 'multpages' );
73 }
74 $title = reset( $pageSet->getGoodTitles() );
75 if ( $title ) {
76 $timestamp = Revision::getTimestampFromId( $title, $params['torevid'] );
77 if ( $timestamp ) {
78 $timestamp = $dbw->timestamp( $timestamp );
79 } else {
80 $timestamp = null;
81 }
82 }
83 } elseif ( isset( $params['newerthanrevid'] ) ) {
84 if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
85 $this->dieUsage( 'newerthanrevid may only be used with a single page', 'multpages' );
86 }
87 $title = reset( $pageSet->getGoodTitles() );
88 if ( $title ) {
89 $revid = $title->getNextRevisionID( $params['newerthanrevid'] );
90 if ( $revid ) {
91 $timestamp = $dbw->timestamp( Revision::getTimestampFromId( $title, $revid ) );
92 } else {
93 $timestamp = null;
94 }
95 }
96 }
97
98 $apiResult = $this->getResult();
99 $result = array();
100 if ( $params['entirewatchlist'] ) {
101 // Entire watchlist mode: Just update the thing and return a success indicator
102 $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $timestamp ),
103 array( 'wl_user' => $user->getID() ),
104 __METHOD__
105 );
106
107 $result['notificationtimestamp'] = is_null( $timestamp )
108 ? ''
109 : wfTimestamp( TS_ISO_8601, $timestamp );
110 } else {
111 // First, log the invalid titles
112 foreach ( $pageSet->getInvalidTitles() as $title ) {
113 $r = array();
114 $r['title'] = $title;
115 $r['invalid'] = '';
116 $result[] = $r;
117 }
118 foreach ( $pageSet->getMissingPageIDs() as $p ) {
119 $page = array();
120 $page['pageid'] = $p;
121 $page['missing'] = '';
122 $page['notwatched'] = '';
123 $result[] = $page;
124 }
125 foreach ( $pageSet->getMissingRevisionIDs() as $r ) {
126 $rev = array();
127 $rev['revid'] = $r;
128 $rev['missing'] = '';
129 $rev['notwatched'] = '';
130 $result[] = $rev;
131 }
132
133 if ( $pageSet->getTitles() ) {
134 // Now process the valid titles
135 $lb = new LinkBatch( $pageSet->getTitles() );
136 $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $timestamp ),
137 array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
138 __METHOD__
139 );
140
141 // Query the results of our update
142 $timestamps = array();
143 $res = $dbw->select(
144 'watchlist',
145 array( 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ),
146 array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
147 __METHOD__
148 );
149 foreach ( $res as $row ) {
150 $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp;
151 }
152
153 // Now, put the valid titles into the result
154 /** @var $title Title */
155 foreach ( $pageSet->getTitles() as $title ) {
156 $ns = $title->getNamespace();
157 $dbkey = $title->getDBkey();
158 $r = array(
159 'ns' => intval( $ns ),
160 'title' => $title->getPrefixedText(),
161 );
162 if ( !$title->exists() ) {
163 $r['missing'] = '';
164 }
165 if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] ) ) {
166 $r['notificationtimestamp'] = '';
167 if ( $timestamps[$ns][$dbkey] !== null ) {
168 $r['notificationtimestamp'] = wfTimestamp( TS_ISO_8601, $timestamps[$ns][$dbkey] );
169 }
170 } else {
171 $r['notwatched'] = '';
172 }
173 $result[] = $r;
174 }
175 }
176
177 $apiResult->setIndexedTagName( $result, 'page' );
178 }
179 $apiResult->addValue( null, $this->getModuleName(), $result );
180
181 $apiResult->endContinuation();
182 }
183
184 /**
185 * Get a cached instance of an ApiPageSet object
186 * @return ApiPageSet
187 */
188 private function getPageSet() {
189 if ( !isset( $this->mPageSet ) ) {
190 $this->mPageSet = new ApiPageSet( $this );
191 }
192
193 return $this->mPageSet;
194 }
195
196 public function mustBePosted() {
197 return true;
198 }
199
200 public function isWriteMode() {
201 return true;
202 }
203
204 public function needsToken() {
205 return true;
206 }
207
208 public function getTokenSalt() {
209 return '';
210 }
211
212 public function getAllowedParams( $flags = 0 ) {
213 $result = array(
214 'entirewatchlist' => array(
215 ApiBase::PARAM_TYPE => 'boolean'
216 ),
217 'token' => null,
218 'timestamp' => array(
219 ApiBase::PARAM_TYPE => 'timestamp'
220 ),
221 'torevid' => array(
222 ApiBase::PARAM_TYPE => 'integer'
223 ),
224 'newerthanrevid' => array(
225 ApiBase::PARAM_TYPE => 'integer'
226 ),
227 'continue' => '',
228 );
229 if ( $flags ) {
230 $result += $this->getPageSet()->getFinalParams( $flags );
231 }
232
233 return $result;
234 }
235
236 public function getParamDescription() {
237 return $this->getPageSet()->getFinalParamDescription() + array(
238 'entirewatchlist' => 'Work on all watched pages',
239 'timestamp' => 'Timestamp to which to set the notification timestamp',
240 'torevid' => 'Revision to set the notification timestamp to (one page only)',
241 'newerthanrevid' => 'Revision to set the notification timestamp newer than (one page only)',
242 'token' => 'A token previously acquired via prop=info',
243 'continue' => 'When more results are available, use this to continue',
244 );
245 }
246
247 public function getResultProperties() {
248 return array(
249 ApiBase::PROP_LIST => true,
250 ApiBase::PROP_ROOT => array(
251 'notificationtimestamp' => array(
252 ApiBase::PROP_TYPE => 'timestamp',
253 ApiBase::PROP_NULLABLE => true
254 )
255 ),
256 '' => array(
257 'ns' => array(
258 ApiBase::PROP_TYPE => 'namespace',
259 ApiBase::PROP_NULLABLE => true
260 ),
261 'title' => array(
262 ApiBase::PROP_TYPE => 'string',
263 ApiBase::PROP_NULLABLE => true
264 ),
265 'pageid' => array(
266 ApiBase::PROP_TYPE => 'integer',
267 ApiBase::PROP_NULLABLE => true
268 ),
269 'revid' => array(
270 ApiBase::PROP_TYPE => 'integer',
271 ApiBase::PROP_NULLABLE => true
272 ),
273 'invalid' => 'boolean',
274 'missing' => 'boolean',
275 'notwatched' => 'boolean',
276 'notificationtimestamp' => array(
277 ApiBase::PROP_TYPE => 'timestamp',
278 ApiBase::PROP_NULLABLE => true
279 )
280 )
281 );
282 }
283
284 public function getDescription() {
285 return array( 'Update the notification timestamp for watched pages.',
286 'This affects the highlighting of changed pages in the watchlist and history,',
287 'and the sending of email when the "Email me when a page on my watchlist is',
288 'changed" preference is enabled.'
289 );
290 }
291
292 public function getPossibleErrors() {
293 $ps = $this->getPageSet();
294
295 return array_merge(
296 parent::getPossibleErrors(),
297 $ps->getFinalPossibleErrors(),
298 $this->getRequireMaxOneParameterErrorMessages(
299 array( 'timestamp', 'torevid', 'newerthanrevid' ) ),
300 $this->getRequireOnlyOneParameterErrorMessages(
301 array_merge( array( 'entirewatchlist' ), array_keys( $ps->getFinalParams() ) ) ),
302 array(
303 array( 'code' => 'notloggedin', 'info'
304 => 'Anonymous users cannot use watchlist change notifications' ),
305 array( 'code' => 'multpages', 'info' => 'torevid may only be used with a single page' ),
306 array( 'code' => 'multpages', 'info' => 'newerthanrevid may only be used with a single page' ),
307 )
308 );
309 }
310
311 public function getExamples() {
312 return array(
313 'api.php?action=setnotificationtimestamp&entirewatchlist=&token=123ABC'
314 => 'Reset the notification status for the entire watchlist',
315 'api.php?action=setnotificationtimestamp&titles=Main_page&token=123ABC'
316 => 'Reset the notification status for "Main page"',
317 'api.php?action=setnotificationtimestamp&titles=Main_page&' .
318 'timestamp=2012-01-01T00:00:00Z&token=123ABC'
319 => 'Set the notification timestamp for "Main page" so all edits ' .
320 'since 1 January 2012 are unviewed',
321 );
322 }
323
324 public function getHelpUrls() {
325 return 'https://www.mediawiki.org/wiki/API:SetNotificationTimestamp';
326 }
327 }