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