Index: trunk/phase3/includes/Defines.php |
— | — | @@ -195,6 +195,19 @@ |
196 | 196 | define( 'EDIT_AUTOSUMMARY', 64 ); |
197 | 197 | /**#@-*/ |
198 | 198 | |
| 199 | +/**#@+ |
| 200 | + * Article::doRollback() return values |
| 201 | + */ |
| 202 | +define('ROLLBACK_SUCCES', 0); |
| 203 | +define('ROLLBACK_PERM', 1); // Permission denied |
| 204 | +define('ROLLBACK_BLOCKED', 2); // User has been blocked |
| 205 | +define('ROLLBACK_READONLY', 3); // Wiki is in read-only mode |
| 206 | +define('ROLLBACK_BADTOKEN', 4); // Invalid token specified |
| 207 | +define('ROLLBACK_BADARTICLE', 5); // $article is not a valid Article |
| 208 | +define('ROLLBACK_ALREADYROLLED', 6); // Someone else already rolled this back. $info['usertext'] and $info['comment'] will be set |
| 209 | +define('ROLLBACK_ONLYAUTHOR', 7); // User is the only author of the page |
| 210 | +define('ROLLBACK_EDITFAILED', 8); // Article::doEdit() failed. This is a very weird error |
| 211 | + |
199 | 212 | /** |
200 | 213 | * Flags for Database::makeList() |
201 | 214 | * These are also available as Database class constants |
Index: trunk/phase3/includes/Article.php |
— | — | @@ -2155,119 +2155,152 @@ |
2156 | 2156 | return true; |
2157 | 2157 | } |
2158 | 2158 | |
2159 | | - /** |
2160 | | - * Revert a modification |
| 2159 | + /** Backend rollback implementation. UI logic is in rollback() |
| 2160 | + * @param string $user - Name of the user whose edits to rollback. |
| 2161 | + * @param string $token - Rollback token. |
| 2162 | + * @param bool $bot - If true, mark all reverted edits as bot. |
| 2163 | + * @param string $summary - Custom summary. Set to default summary if empty. |
| 2164 | + * @param array $info - Reference to associative array that will be set to contain the revision ID, edit summary, etc. |
| 2165 | + * @return ROLLBACK_SUCCES on succes, ROLLBACK_* on failure |
2161 | 2166 | */ |
2162 | | - function rollback() { |
2163 | | - global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol; |
| 2167 | + public function doRollback($user, $token, $bot = false, $summary = "", &$info = NULL) |
| 2168 | + { |
| 2169 | + global $wgUser, $wgUseRCPatrol; |
| 2170 | + if(!$wgUser->isAllowed('rollback')) |
| 2171 | + return ROLLBACK_PERM; |
| 2172 | + if($wgUser->isBlocked()) |
| 2173 | + return ROLLBACK_BLOCKED; |
| 2174 | + if(wfReadOnly()) |
| 2175 | + return ROLLBACK_READONLY; |
2164 | 2176 | |
2165 | | - if( $wgUser->isAllowed( 'rollback' ) ) { |
2166 | | - if( $wgUser->isBlocked() ) { |
2167 | | - $wgOut->blockedPage(); |
2168 | | - return; |
2169 | | - } |
2170 | | - } else { |
2171 | | - $wgOut->permissionRequired( 'rollback' ); |
2172 | | - return; |
2173 | | - } |
| 2177 | + // Check token first |
| 2178 | + if(!$wgUser->matchEditToken($token, array($this->mTitle->getPrefixedText(), $user))) |
| 2179 | + return ROLLBACK_BADTOKEN; |
2174 | 2180 | |
2175 | | - if ( wfReadOnly() ) { |
2176 | | - $wgOut->readOnlyPage( $this->getContent() ); |
2177 | | - return; |
2178 | | - } |
2179 | | - if( !$wgUser->matchEditToken( $wgRequest->getVal( 'token' ), |
2180 | | - array( $this->mTitle->getPrefixedText(), |
2181 | | - $wgRequest->getVal( 'from' ) ) ) ) { |
2182 | | - $wgOut->setPageTitle( wfMsg( 'rollbackfailed' ) ); |
2183 | | - $wgOut->addWikiText( wfMsg( 'sessionfailure' ) ); |
2184 | | - return; |
2185 | | - } |
2186 | | - $dbw = wfGetDB( DB_MASTER ); |
| 2181 | + $dbw = wfGetDB(DB_MASTER); |
| 2182 | + $current = Revision::newFromTitle($this->mTitle); |
| 2183 | + if(is_null($current)) |
| 2184 | + return ROLLBACK_BADARTICLE; |
2187 | 2185 | |
2188 | | - # Enhanced rollback, marks edits rc_bot=1 |
2189 | | - $bot = $wgRequest->getBool( 'bot' ); |
2190 | | - |
2191 | | - # Replace all this user's current edits with the next one down |
2192 | | - |
2193 | | - # Get the last editor |
2194 | | - $current = Revision::newFromTitle( $this->mTitle ); |
2195 | | - if( is_null( $current ) ) { |
2196 | | - # Something wrong... no page? |
2197 | | - $wgOut->addHTML( wfMsg( 'notanarticle' ) ); |
2198 | | - return; |
| 2186 | + // Check if someone else was there first |
| 2187 | + if($user != $current->getUserText()) |
| 2188 | + { |
| 2189 | + $info['usertext'] = $current->getUserText(); |
| 2190 | + $info['comment'] = $current->getComment(); |
| 2191 | + return ROLLBACK_ALREADYROLLED; |
2199 | 2192 | } |
2200 | | - |
2201 | | - $from = str_replace( '_', ' ', $wgRequest->getVal( 'from' ) ); |
2202 | | - if( $from != $current->getUserText() ) { |
2203 | | - $wgOut->setPageTitle( wfMsg('rollbackfailed') ); |
2204 | | - $wgOut->addWikiText( wfMsg( 'alreadyrolled', |
2205 | | - htmlspecialchars( $this->mTitle->getPrefixedText()), |
2206 | | - htmlspecialchars( $from ), |
2207 | | - htmlspecialchars( $current->getUserText() ) ) ); |
2208 | | - if( $current->getComment() != '') { |
2209 | | - $wgOut->addHTML( |
2210 | | - wfMsg( 'editcomment', |
2211 | | - $wgUser->getSkin()->formatComment( $current->getComment() ) ) ); |
2212 | | - } |
2213 | | - return; |
2214 | | - } |
2215 | | - |
2216 | | - # Get the last edit not by this guy |
2217 | | - $user = intval( $current->getUser() ); |
2218 | | - $user_text = $dbw->addQuotes( $current->getUserText() ); |
2219 | | - $s = $dbw->selectRow( 'revision', |
2220 | | - array( 'rev_id', 'rev_timestamp' ), |
| 2193 | + // Get the last edit not by $user |
| 2194 | + $userid = intval($current->getUser()); |
| 2195 | + $s = $dbw->selectRow('revision', |
| 2196 | + array('rev_id', 'rev_timestamp'), |
2221 | 2197 | array( |
2222 | 2198 | 'rev_page' => $current->getPage(), |
2223 | | - "rev_user <> {$user} OR rev_user_text <> {$user_text}" |
| 2199 | + "rev_user <> $userid OR rev_user_text <> {$dbw->addQuotes($user)}" |
2224 | 2200 | ), __METHOD__, |
2225 | 2201 | array( |
2226 | 2202 | 'USE INDEX' => 'page_timestamp', |
2227 | | - 'ORDER BY' => 'rev_timestamp DESC' ) |
2228 | | - ); |
2229 | | - if( $s === false ) { |
2230 | | - # Something wrong |
2231 | | - $wgOut->setPageTitle(wfMsg('rollbackfailed')); |
2232 | | - $wgOut->addHTML( wfMsg( 'cantrollback' ) ); |
2233 | | - return; |
2234 | | - } |
| 2203 | + 'ORDER BY' => 'rev_timestamp DESC' |
| 2204 | + )); |
| 2205 | + if($s === false) |
| 2206 | + return ROLLBACK_ONLYAUTHOR; |
| 2207 | + $target = Revision::newFromID($s->rev_id); |
2235 | 2208 | |
| 2209 | + // If the reverted edits should be marked bot or patrolled, do so |
2236 | 2210 | $set = array(); |
2237 | | - if ( $bot ) { |
2238 | | - # Mark all reverted edits as bot |
| 2211 | + if($bot) |
2239 | 2212 | $set['rc_bot'] = 1; |
2240 | | - } |
2241 | | - if ( $wgUseRCPatrol ) { |
2242 | | - # Mark all reverted edits as patrolled |
| 2213 | + if($wgUseRCPatrol) |
2243 | 2214 | $set['rc_patrolled'] = 1; |
2244 | | - } |
| 2215 | + if($set) |
| 2216 | + $dbw->update('recentchanges', $set, |
| 2217 | + array( |
| 2218 | + 'rc_cur_id' => $current->getPage(), |
| 2219 | + 'rc_user_text' => $user, |
| 2220 | + "rc_timestamp > '{$s->rev_timestamp}'" |
| 2221 | + ), __METHOD__ |
| 2222 | + ); |
2245 | 2223 | |
2246 | | - if ( $set ) { |
2247 | | - $dbw->update( 'recentchanges', $set, |
2248 | | - array( /* WHERE */ |
2249 | | - 'rc_cur_id' => $current->getPage(), |
2250 | | - 'rc_user_text' => $current->getUserText(), |
2251 | | - "rc_timestamp > '{$s->rev_timestamp}'", |
2252 | | - ), __METHOD__ |
2253 | | - ); |
2254 | | - } |
| 2224 | + // Generate an edit summary |
| 2225 | + if(empty($summary)) |
| 2226 | + $summary = wfMsgForContent('revertpage', $target->getUserText(), $user); |
2255 | 2227 | |
2256 | | - # Get the edit summary |
2257 | | - $target = Revision::newFromId( $s->rev_id ); |
2258 | | - $newComment = wfMsgForContent( 'revertpage', $target->getUserText(), $from ); |
2259 | | - $newComment = $wgRequest->getText( 'summary', $newComment ); |
| 2228 | + // Now we *finally* get to commit the edit |
| 2229 | + $flags = EDIT_UPDATE | EDIT_MINOR; |
| 2230 | + if($bot) |
| 2231 | + $flags |= EDIT_FORCE_BOT; |
| 2232 | + if(!$this->doEdit($target->getText(), $summary, $flags)) |
| 2233 | + return ROLLBACK_EDITFAILED; |
2260 | 2234 | |
2261 | | - # Save it! |
2262 | | - $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); |
2263 | | - $wgOut->setRobotpolicy( 'noindex,nofollow' ); |
2264 | | - $wgOut->addHTML( '<h2>' . htmlspecialchars( $newComment ) . "</h2>\n<hr />\n" ); |
| 2235 | + if(is_null($info)) |
| 2236 | + // Save time |
| 2237 | + return ROLLBACK_SUCCESS; |
2265 | 2238 | |
2266 | | - $this->updateArticle( $target->getText(), $newComment, 1, $this->mTitle->userIsWatching(), $bot ); |
| 2239 | + $info['title'] = $this->mTitle->getPrefixedText(); |
| 2240 | + $info['pageid'] = $current->getPage(); |
| 2241 | + $info['summary'] = $summary; |
| 2242 | + // NOTE: If the rollback turned out to be a null edit, revid and old_revid will be equal |
| 2243 | + $info['revid'] = $this->mTitle->getLatestRevID(); // The revid of your rollback |
| 2244 | + $info['old_revid'] = $current->getId(); // The revid of the last edit before your rollback |
| 2245 | + $info['last_revid'] = $s->rev_id; // The revid of the last edit that was not rolled back |
| 2246 | + $info['user'] = $user; // The name of the victim |
| 2247 | + $info['userid'] = $userid; // And their userid |
| 2248 | + $info['to'] = $target->getUserText(); // The user whose last version was reverted to |
| 2249 | + if($bot) |
| 2250 | + $info['bot'] = ""; |
| 2251 | + return ROLLBACK_SUCCESS; |
| 2252 | + } |
2267 | 2253 | |
2268 | | - $wgOut->returnToMain( false ); |
| 2254 | + /** UI entry point for rollbacks. Relies on doRollback() to do the hard work */ |
| 2255 | + function rollback() { |
| 2256 | + global $wgUser, $wgOut, $wgRequest, $wgUseRCPatrol; |
| 2257 | + |
| 2258 | + // Basically, we just call doRollback() and interpret its return value |
| 2259 | + $info = array(); |
| 2260 | + $retval = $this->doRollback($wgRequest->getVal('from'), $wgRequest->getVal('token'), $wgRequest->getBool('bot'), |
| 2261 | + $wgRequest->getText('summary'), &$info); |
| 2262 | + switch($retval) |
| 2263 | + { |
| 2264 | + case ROLLBACK_SUCCESS: |
| 2265 | + case ROLLBACK_EDITFAILED: // Is ignored |
| 2266 | + $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); |
| 2267 | + $wgOut->setRobotpolicy( 'noindex,nofollow' ); |
| 2268 | + $wgOut->addHTML( '<h2>' . htmlspecialchars( $info['summary'] ) . "</h2>\n<hr />\n" ); |
| 2269 | + $this->doRedirect(true); |
| 2270 | + $wgOut->returnToMain(false); |
| 2271 | + return; |
| 2272 | + case ROLLBACK_PERM: |
| 2273 | + $wgOut->permissionRequired('rollback'); |
| 2274 | + return; |
| 2275 | + case ROLLBACK_BLOCKED: |
| 2276 | + $wgOut->blockedPage(); |
| 2277 | + return; |
| 2278 | + case ROLLBACK_READONLY: |
| 2279 | + $wgOut->readOnlyPage($this->getContent()); |
| 2280 | + return; |
| 2281 | + case ROLLBACK_BADTOKEN: |
| 2282 | + $wgOut->setPageTitle(wfMsg('rollbackfailed')); |
| 2283 | + $wgOut->addWikiText(wfMsg('sessionfailure')); |
| 2284 | + return; |
| 2285 | + case ROLLBACK_BADARTICLE: |
| 2286 | + $wgOut->addHTML(wfMsg('notanarticle')); |
| 2287 | + return; |
| 2288 | + case ROLLBACK_ALREADYROLLED: |
| 2289 | + $wgOut->setPageTitle(wfMsg('rollbackfailed')); |
| 2290 | + $wgOut->addWikiText(wfMsg('alreadyrolled', |
| 2291 | + htmlspecialchars($this->mTitle->getPrefixedText()), |
| 2292 | + htmlspecialchars($wgRequest->getVal('from')), |
| 2293 | + htmlspecialchars($info['usertext']))); |
| 2294 | + if($info['comment'] != '') |
| 2295 | + $wgOut->addHTML(wfMsg('editcomment', |
| 2296 | + $wgUser->getSkin()->formatComment($info['comment']))); |
| 2297 | + return; |
| 2298 | + case ROLLBACK_ONLYAUTHOR: |
| 2299 | + $wgOut->setPageTitle(wfMsg('rollbackfailed')); |
| 2300 | + $wgOut->addHTML(wfMsg('cantrollback')); |
| 2301 | + return; |
| 2302 | + } |
2269 | 2303 | } |
2270 | 2304 | |
2271 | | - |
2272 | 2305 | /** |
2273 | 2306 | * Do standard deferred updates after page view |
2274 | 2307 | * @private |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -322,6 +322,7 @@ |
323 | 323 | 'ApiQuerySiteinfo' => 'includes/api/ApiQuerySiteinfo.php', |
324 | 324 | 'ApiQueryWatchlist' => 'includes/api/ApiQueryWatchlist.php', |
325 | 325 | 'ApiResult' => 'includes/api/ApiResult.php', |
| 326 | + 'ApiRollback' => 'includes/api/ApiRollback.php' |
326 | 327 | ); |
327 | 328 | |
328 | 329 | wfProfileIn( __METHOD__ ); |
Index: trunk/phase3/includes/api/ApiQueryInfo.php |
— | — | @@ -49,13 +49,17 @@ |
50 | 50 | } |
51 | 51 | |
52 | 52 | public function execute() { |
| 53 | + global $wgUser; |
53 | 54 | |
54 | 55 | $params = $this->extractRequestParams(); |
55 | 56 | $fld_protection = false; |
56 | 57 | if(!is_null($params['prop'])) { |
57 | 58 | $prop = array_flip($params['prop']); |
58 | 59 | $fld_protection = isset($prop['protection']); |
| 60 | + $fld_lastrevby = isset($prop['lastrevby']); |
59 | 61 | } |
| 62 | + if(!is_null($params['tokens'])) |
| 63 | + $params['tokens'] = array_flip($params['tokens']); |
60 | 64 | |
61 | 65 | $pageSet = $this->getPageSet(); |
62 | 66 | $titles = $pageSet->getGoodTitles(); |
— | — | @@ -85,13 +89,18 @@ |
86 | 90 | $db->freeResult($res); |
87 | 91 | } |
88 | 92 | |
89 | | - foreach ( $titles as $pageid => $unused ) { |
| 93 | + foreach ( $titles as $pageid => $title ) { |
90 | 94 | $pageInfo = array ( |
91 | 95 | 'touched' => wfTimestamp(TS_ISO_8601, $pageTouched[$pageid]), |
92 | 96 | 'lastrevid' => intval($pageLatest[$pageid]), |
93 | 97 | 'counter' => intval($pageCounter[$pageid]), |
94 | | - 'length' => intval($pageLength[$pageid]), |
| 98 | + 'length' => intval($pageLength[$pageid]) |
95 | 99 | ); |
| 100 | + if(isset($params['tokens']) || $fld_lastrevby) |
| 101 | + { |
| 102 | + $lastrev = Revision::newFromId($pageInfo['lastrevid']); |
| 103 | + $pageInfo['lastrevby'] = $lastrev->getUserText(); |
| 104 | + } |
96 | 105 | |
97 | 106 | if ($pageIsRedir[$pageid]) |
98 | 107 | $pageInfo['redirect'] = ''; |
— | — | @@ -108,6 +117,31 @@ |
109 | 118 | } |
110 | 119 | } |
111 | 120 | |
| 121 | + $tokenArr = array(); |
| 122 | + foreach($params['tokens'] as $token => $unused) |
| 123 | + switch($token) |
| 124 | + { |
| 125 | + case 'rollback': |
| 126 | + $tokenArr[$token] = $wgUser->editToken(array($title->getPrefixedText(), $pageInfo['lastrevby'])); |
| 127 | + break; |
| 128 | + case 'edit': |
| 129 | + case 'move': |
| 130 | + case 'delete': |
| 131 | + case 'undelete': |
| 132 | + case 'protect': |
| 133 | + case 'unprotect': |
| 134 | + if($wgUser->isAnon()) |
| 135 | + $tokenArr[$token] = EDIT_TOKEN_SUFFIX; |
| 136 | + else |
| 137 | + $tokenArr[$token] = $wgUser->editToken(); |
| 138 | + // default: can't happen, ignore it if it does happen in some weird way |
| 139 | + } |
| 140 | + if(count($tokenArr) > 0) |
| 141 | + { |
| 142 | + $pageInfo['tokens'] = $tokenArr; |
| 143 | + $result->setIndexedTagName($pageInfo['tokens'], 't'); |
| 144 | + } |
| 145 | + |
112 | 146 | $result->addValue(array ( |
113 | 147 | 'query', |
114 | 148 | 'pages' |
— | — | @@ -121,7 +155,20 @@ |
122 | 156 | ApiBase :: PARAM_DFLT => NULL, |
123 | 157 | ApiBase :: PARAM_ISMULTI => true, |
124 | 158 | ApiBase :: PARAM_TYPE => array ( |
125 | | - 'protection' |
| 159 | + 'protection', |
| 160 | + 'lastrevby' |
| 161 | + )), |
| 162 | + 'tokens' => array( |
| 163 | + ApiBase :: PARAM_DFLT => NULL, |
| 164 | + ApiBase :: PARAM_ISMULTI => true, |
| 165 | + ApiBase :: PARAM_TYPE => array( |
| 166 | + 'edit', |
| 167 | + 'move', |
| 168 | + 'delete', |
| 169 | + 'undelete', |
| 170 | + 'rollback', |
| 171 | + 'protect', |
| 172 | + 'unprotect' |
126 | 173 | )) |
127 | 174 | ); |
128 | 175 | } |
— | — | @@ -130,8 +177,10 @@ |
131 | 178 | return array ( |
132 | 179 | 'prop' => array ( |
133 | 180 | 'Which additional properties to get:', |
134 | | - ' "protection" - List the protection level of each page' |
135 | | - ) |
| 181 | + ' "protection" - List the protection level of each page', |
| 182 | + ' "lastrevby" - The name of the user who made the last edit. You may need this for action=rollback.' |
| 183 | + ), |
| 184 | + 'tokens' => 'Which tokens to get.' |
136 | 185 | ); |
137 | 186 | } |
138 | 187 | |
— | — | @@ -143,7 +192,8 @@ |
144 | 193 | protected function getExamples() { |
145 | 194 | return array ( |
146 | 195 | 'api.php?action=query&prop=info&titles=Main%20Page', |
147 | | - 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page' |
| 196 | + 'api.php?action=query&prop=info&inprop=protection&titles=Main%20Page', |
| 197 | + 'api.php?action=query&prop=info&intokens=edit|rollback&titles=Main%20Page' |
148 | 198 | ); |
149 | 199 | } |
150 | 200 | |
Index: trunk/phase3/includes/api/ApiMain.php |
— | — | @@ -54,6 +54,7 @@ |
55 | 55 | private static $Modules = array ( |
56 | 56 | 'login' => 'ApiLogin', |
57 | 57 | 'query' => 'ApiQuery', |
| 58 | + 'rollback' => 'ApiRollback', |
58 | 59 | 'opensearch' => 'ApiOpenSearch', |
59 | 60 | 'feedwatchlist' => 'ApiFeedWatchlist', |
60 | 61 | 'help' => 'ApiHelp', |
— | — | @@ -104,6 +105,18 @@ |
105 | 106 | $this->mRequest = & $request; |
106 | 107 | |
107 | 108 | $this->mSquidMaxage = 0; |
| 109 | + |
| 110 | + global $wgUser, $wgCookiePrefix; |
| 111 | + if(session_id() == '') |
| 112 | + wfSetupSession(); |
| 113 | + // Reinit $wgUser with info from lg* or the session data. The former overrides the latter |
| 114 | + if(isset($_REQUEST['lguserid']) && isset($_REQUEST['lgusername']) && isset($_REQUEST['lgtoken'])) |
| 115 | + { |
| 116 | + $_SESSION['wsUserID'] = $_REQUEST['lguserid']; |
| 117 | + $_SESSION['wsUserName'] = $_REQUEST['lgusername']; |
| 118 | + $_SESSION['wsToken'] = $_REQUEST['lgtoken']; |
| 119 | + } |
| 120 | + $wgUser = User::newFromSession(); |
108 | 121 | } |
109 | 122 | |
110 | 123 | /** |
Index: trunk/phase3/includes/api/ApiRollback.php |
— | — | @@ -0,0 +1,134 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/* |
| 5 | + * Created on Jun 20, 2007 |
| 6 | + * API for MediaWiki 1.8+ |
| 7 | + * |
| 8 | + * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl |
| 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 | + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 23 | + * http://www.gnu.org/copyleft/gpl.html |
| 24 | + */ |
| 25 | + |
| 26 | +if (!defined('MEDIAWIKI')) { |
| 27 | + // Eclipse helper - will be ignored in production |
| 28 | + require_once ("ApiBase.php"); |
| 29 | +} |
| 30 | + |
| 31 | +/** |
| 32 | + * @addtogroup API |
| 33 | + */ |
| 34 | +class ApiRollback extends ApiBase { |
| 35 | + |
| 36 | + public function __construct($main, $action) { |
| 37 | + parent :: __construct($main, $action); |
| 38 | + } |
| 39 | + |
| 40 | + public function execute() { |
| 41 | + global $wgUser; |
| 42 | + $params = $this->extractRequestParams(); |
| 43 | + |
| 44 | + $titleObj = NULL; |
| 45 | + if(!isset($params['title'])) |
| 46 | + $this->dieUsage('The title parameter must be set', 'notarget'); |
| 47 | + if(!isset($params['user'])) |
| 48 | + $this->dieUsage('The user parameter must be set', 'nouser'); |
| 49 | + if(!isset($params['token'])) |
| 50 | + $this->dieUsage('The token parameter must be set', 'notoken'); |
| 51 | + |
| 52 | + // doRollback() also checks for these, but we wanna save some work |
| 53 | + if(!$wgUser->isAllowed('rollback')) |
| 54 | + $this->dieUsage('You don\'t have permission to rollback', 'permissiondenied'); |
| 55 | + if($wgUser->isBlocked()) |
| 56 | + $this->dieUsage('You have been blocked from editing', 'blocked'); |
| 57 | + if(wfReadOnly()) |
| 58 | + $this->dieUsage('The wiki is in read-only mode', 'readonly'); |
| 59 | + |
| 60 | + $titleObj = Title::newFromText($params['title']); |
| 61 | + if(!$titleObj) |
| 62 | + $this->dieUsage("bad title {$params['title']}", 'invalidtitle'); |
| 63 | + |
| 64 | + $articleObj = new Article($titleObj); |
| 65 | + $summary = (isset($params['summary']) ? $params['summary'] : ""); |
| 66 | + $info = array(); |
| 67 | + $retval = $articleObj->doRollback($params['user'], $params['token'], isset($params['markbot']), $summary, &$info); |
| 68 | + |
| 69 | + switch($retval) |
| 70 | + { |
| 71 | + case ROLLBACK_SUCCESS: |
| 72 | + break; // We'll deal with that later |
| 73 | + case ROLLBACK_PERM: |
| 74 | + $this->dieUsage('You don\'t have permission to rollback', 'permissiondenied'); |
| 75 | + case ROLLBACK_BLOCKED: // If we get BLOCKED or PERM that's very weird, but it's possible |
| 76 | + $this->dieUsage('You have been blocked from editing', 'blocked'); |
| 77 | + case ROLLBACK_READONLY: |
| 78 | + $this->dieUsage('The wiki is in read-only mode', 'readonly'); |
| 79 | + case ROLLBACK_BADTOKEN: |
| 80 | + $this->dieUsage('Invalid token', 'badtoken'); |
| 81 | + case ROLLBACK_BADARTICLE: |
| 82 | + $this->dieUsage("The article ``{$params['title']}'' doesn't exist", 'missingtitle'); |
| 83 | + case ROLLBACK_ALREADYROLLED: |
| 84 | + $this->dieUsage('The edit(s) you tried to rollback is/are already rolled back', 'alreadyrolled'); |
| 85 | + case ROLLBACK_ONLYAUTHOR: |
| 86 | + $this->dieUsage("{$params['user']} is the only author of the page", 'onlyauthor'); |
| 87 | + case ROLLBACK_EDITFAILED: |
| 88 | + $this->dieDebug(__METHOD__, 'Article::doEdit() failed'); |
| 89 | + default: |
| 90 | + // rollback() has apparently invented a new error, which is extremely weird |
| 91 | + $this->dieDebug(__METHOD__, "rollback() returned an unknown error ($retval)"); |
| 92 | + } |
| 93 | + // $retval has to be ROLLBACK_SUCCESS if we get here |
| 94 | + $this->getResult()->addValue(null, 'rollback', $info); |
| 95 | + } |
| 96 | + |
| 97 | + protected function getAllowedParams() { |
| 98 | + return array ( |
| 99 | + 'title' => null, |
| 100 | + 'user' => null, |
| 101 | + 'token' => null, |
| 102 | + 'summary' => null, |
| 103 | + 'markbot' => null |
| 104 | + ); |
| 105 | + } |
| 106 | + |
| 107 | + protected function getParamDescription() { |
| 108 | + return array ( |
| 109 | + 'title' => 'Title of the page you want to rollback.', |
| 110 | + 'user' => 'Name of the user whose edits are to be rolled back. If set incorrectly, you\'ll get a badtoken error.', |
| 111 | + 'token' => 'A rollback token previously retrieved through prop=info', |
| 112 | + 'summary' => 'Custom edit summary. If not set, default summary will be used.', |
| 113 | + 'markbot' => 'Mark the reverted edits and the revert as bot edits' |
| 114 | + ); |
| 115 | + } |
| 116 | + |
| 117 | + protected function getDescription() { |
| 118 | + return array( |
| 119 | + 'Undoes the last edit to the page. If the last user who edited the page made multiple edits in a row,', |
| 120 | + 'they will all be rolled back. You need to be logged in as a sysop to use this function, see also action=login.' |
| 121 | + ); |
| 122 | + } |
| 123 | + |
| 124 | + protected function getExamples() { |
| 125 | + return array ( |
| 126 | + 'api.php?action=rollback&title=Main%20Page&user=Catrope&token=123ABC', |
| 127 | + 'api.php?action=rollback&title=Main%20Page&user=217.121.114.116&token=123ABC&summary=Reverting%20vandalism&markbot=1' |
| 128 | + ); |
| 129 | + } |
| 130 | + |
| 131 | + public function getVersion() { |
| 132 | + return __CLASS__ . ': $Id: ApiRollback.php 22289 2007-05-20 23:31:44Z yurik $'; |
| 133 | + } |
| 134 | +} |
| 135 | +?> |