Merge "Fix mime detection of easily-confused-with text/plain formats"
[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 $pageSet = $this->getPageSet();
50 if ( $params['entirewatchlist'] && $pageSet->getDataSource() !== null ) {
51 $this->dieUsage(
52 "Cannot use 'entirewatchlist' at the same time as '{$pageSet->getDataSource()}'",
53 'multisource'
54 );
55 }
56
57 $dbw = wfGetDB( DB_MASTER, 'api' );
58
59 $timestamp = null;
60 if ( isset( $params['timestamp'] ) ) {
61 $timestamp = $dbw->timestamp( $params['timestamp'] );
62 }
63
64 if ( !$params['entirewatchlist'] ) {
65 $pageSet->execute();
66 }
67
68 if ( isset( $params['torevid'] ) ) {
69 if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
70 $this->dieUsage( 'torevid may only be used with a single page', 'multpages' );
71 }
72 $title = reset( $pageSet->getGoodTitles() );
73 if ( $title ) {
74 $timestamp = Revision::getTimestampFromId( $title, $params['torevid'] );
75 if ( $timestamp ) {
76 $timestamp = $dbw->timestamp( $timestamp );
77 } else {
78 $timestamp = null;
79 }
80 }
81 } elseif ( isset( $params['newerthanrevid'] ) ) {
82 if ( $params['entirewatchlist'] || $pageSet->getGoodTitleCount() > 1 ) {
83 $this->dieUsage( 'newerthanrevid may only be used with a single page', 'multpages' );
84 }
85 $title = reset( $pageSet->getGoodTitles() );
86 if ( $title ) {
87 $revid = $title->getNextRevisionID( $params['newerthanrevid'] );
88 if ( $revid ) {
89 $timestamp = $dbw->timestamp( Revision::getTimestampFromId( $title, $revid ) );
90 } else {
91 $timestamp = null;
92 }
93 }
94 }
95
96 $apiResult = $this->getResult();
97 $result = array();
98 if ( $params['entirewatchlist'] ) {
99 // Entire watchlist mode: Just update the thing and return a success indicator
100 $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $timestamp ),
101 array( 'wl_user' => $user->getID() ),
102 __METHOD__
103 );
104
105 $result['notificationtimestamp'] = is_null( $timestamp )
106 ? ''
107 : wfTimestamp( TS_ISO_8601, $timestamp );
108 } else {
109 // First, log the invalid titles
110 foreach ( $pageSet->getInvalidTitles() as $title ) {
111 $r = array();
112 $r['title'] = $title;
113 $r['invalid'] = '';
114 $result[] = $r;
115 }
116 foreach ( $pageSet->getMissingPageIDs() as $p ) {
117 $page = array();
118 $page['pageid'] = $p;
119 $page['missing'] = '';
120 $page['notwatched'] = '';
121 $result[] = $page;
122 }
123 foreach ( $pageSet->getMissingRevisionIDs() as $r ) {
124 $rev = array();
125 $rev['revid'] = $r;
126 $rev['missing'] = '';
127 $rev['notwatched'] = '';
128 $result[] = $rev;
129 }
130
131 if ( $pageSet->getTitles() ) {
132 // Now process the valid titles
133 $lb = new LinkBatch( $pageSet->getTitles() );
134 $dbw->update( 'watchlist', array( 'wl_notificationtimestamp' => $timestamp ),
135 array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
136 __METHOD__
137 );
138
139 // Query the results of our update
140 $timestamps = array();
141 $res = $dbw->select(
142 'watchlist',
143 array( 'wl_namespace', 'wl_title', 'wl_notificationtimestamp' ),
144 array( 'wl_user' => $user->getID(), $lb->constructSet( 'wl', $dbw ) ),
145 __METHOD__
146 );
147 foreach ( $res as $row ) {
148 $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp;
149 }
150
151 // Now, put the valid titles into the result
152 /** @var $title Title */
153 foreach ( $pageSet->getTitles() as $title ) {
154 $ns = $title->getNamespace();
155 $dbkey = $title->getDBkey();
156 $r = array(
157 'ns' => intval( $ns ),
158 'title' => $title->getPrefixedText(),
159 );
160 if ( !$title->exists() ) {
161 $r['missing'] = '';
162 }
163 if ( isset( $timestamps[$ns] ) && array_key_exists( $dbkey, $timestamps[$ns] ) ) {
164 $r['notificationtimestamp'] = '';
165 if ( $timestamps[$ns][$dbkey] !== null ) {
166 $r['notificationtimestamp'] = wfTimestamp( TS_ISO_8601, $timestamps[$ns][$dbkey] );
167 }
168 } else {
169 $r['notwatched'] = '';
170 }
171 $result[] = $r;
172 }
173 }
174
175 $apiResult->setIndexedTagName( $result, 'page' );
176 }
177 $apiResult->addValue( null, $this->getModuleName(), $result );
178 }
179
180 /**
181 * Get a cached instance of an ApiPageSet object
182 * @return ApiPageSet
183 */
184 private function getPageSet() {
185 if ( !isset( $this->mPageSet ) ) {
186 $this->mPageSet = new ApiPageSet( $this );
187 }
188
189 return $this->mPageSet;
190 }
191
192 public function mustBePosted() {
193 return true;
194 }
195
196 public function isWriteMode() {
197 return true;
198 }
199
200 public function needsToken() {
201 return true;
202 }
203
204 public function getTokenSalt() {
205 return '';
206 }
207
208 public function getAllowedParams( $flags = 0 ) {
209 $result = array(
210 'entirewatchlist' => array(
211 ApiBase::PARAM_TYPE => 'boolean'
212 ),
213 'token' => null,
214 'timestamp' => array(
215 ApiBase::PARAM_TYPE => 'timestamp'
216 ),
217 'torevid' => array(
218 ApiBase::PARAM_TYPE => 'integer'
219 ),
220 'newerthanrevid' => array(
221 ApiBase::PARAM_TYPE => 'integer'
222 ),
223 );
224 if ( $flags ) {
225 $result += $this->getPageSet()->getFinalParams( $flags );
226 }
227
228 return $result;
229 }
230
231 public function getParamDescription() {
232 return $this->getPageSet()->getFinalParamDescription() + array(
233 'entirewatchlist' => 'Work on all watched pages',
234 'timestamp' => 'Timestamp to which to set the notification timestamp',
235 'torevid' => 'Revision to set the notification timestamp to (one page only)',
236 'newerthanrevid' => 'Revision to set the notification timestamp newer than (one page only)',
237 'token' => 'A token previously acquired via prop=info',
238 );
239 }
240
241 public function getResultProperties() {
242 return array(
243 ApiBase::PROP_LIST => true,
244 ApiBase::PROP_ROOT => array(
245 'notificationtimestamp' => array(
246 ApiBase::PROP_TYPE => 'timestamp',
247 ApiBase::PROP_NULLABLE => true
248 )
249 ),
250 '' => array(
251 'ns' => array(
252 ApiBase::PROP_TYPE => 'namespace',
253 ApiBase::PROP_NULLABLE => true
254 ),
255 'title' => array(
256 ApiBase::PROP_TYPE => 'string',
257 ApiBase::PROP_NULLABLE => true
258 ),
259 'pageid' => array(
260 ApiBase::PROP_TYPE => 'integer',
261 ApiBase::PROP_NULLABLE => true
262 ),
263 'revid' => array(
264 ApiBase::PROP_TYPE => 'integer',
265 ApiBase::PROP_NULLABLE => true
266 ),
267 'invalid' => 'boolean',
268 'missing' => 'boolean',
269 'notwatched' => 'boolean',
270 'notificationtimestamp' => array(
271 ApiBase::PROP_TYPE => 'timestamp',
272 ApiBase::PROP_NULLABLE => true
273 )
274 )
275 );
276 }
277
278 public function getDescription() {
279 return array( 'Update the notification timestamp for watched pages.',
280 'This affects the highlighting of changed pages in the watchlist and history,',
281 'and the sending of email when the "Email me when a page on my watchlist is',
282 'changed" preference is enabled.'
283 );
284 }
285
286 public function getPossibleErrors() {
287 $ps = $this->getPageSet();
288
289 return array_merge(
290 parent::getPossibleErrors(),
291 $ps->getFinalPossibleErrors(),
292 $this->getRequireMaxOneParameterErrorMessages(
293 array( 'timestamp', 'torevid', 'newerthanrevid' ) ),
294 $this->getRequireOnlyOneParameterErrorMessages(
295 array_merge( array( 'entirewatchlist' ), array_keys( $ps->getFinalParams() ) ) ),
296 array(
297 array( 'code' => 'notloggedin', 'info'
298 => 'Anonymous users cannot use watchlist change notifications' ),
299 array( 'code' => 'multpages', 'info' => 'torevid may only be used with a single page' ),
300 array( 'code' => 'multpages', 'info' => 'newerthanrevid may only be used with a single page' ),
301 )
302 );
303 }
304
305 public function getExamples() {
306 return array(
307 'api.php?action=setnotificationtimestamp&entirewatchlist=&token=123ABC'
308 => 'Reset the notification status for the entire watchlist',
309 'api.php?action=setnotificationtimestamp&titles=Main_page&token=123ABC'
310 => 'Reset the notification status for "Main page"',
311 'api.php?action=setnotificationtimestamp&titles=Main_page&' .
312 'timestamp=2012-01-01T00:00:00Z&token=123ABC'
313 => 'Set the notification timestamp for "Main page" so all edits ' .
314 'since 1 January 2012 are unviewed',
315 );
316 }
317
318 public function getHelpUrls() {
319 return 'https://www.mediawiki.org/wiki/API:SetNotificationTimestamp';
320 }
321 }