MediaWiki  master
ApiRollback.php
Go to the documentation of this file.
1 <?php
31 
35 class ApiRollback extends ApiBase {
36 
38 
40  private $rollbackPageFactory;
41 
42  public function __construct(
43  ApiMain $mainModule,
44  $moduleName,
45  RollbackPageFactory $rollbackPageFactory,
46  WatchlistManager $watchlistManager,
47  UserOptionsLookup $userOptionsLookup
48  ) {
49  parent::__construct( $mainModule, $moduleName );
50  $this->rollbackPageFactory = $rollbackPageFactory;
51 
52  // Variables needed in ApiWatchlistTrait trait
53  $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
54  $this->watchlistMaxDuration =
55  $this->getConfig()->get( MainConfigNames::WatchlistExpiryMaxDuration );
56  $this->watchlistManager = $watchlistManager;
57  $this->userOptionsLookup = $userOptionsLookup;
58  }
59 
63  private $mTitleObj = null;
64 
68  private $mUser = null;
69 
70  public function execute() {
72 
73  $user = $this->getUser();
74  $params = $this->extractRequestParams();
75 
76  $titleObj = $this->getRbTitle( $params );
77 
78  // If change tagging was requested, check that the user is allowed to tag,
79  // and the tags are valid. TODO: move inside rollback command?
80  if ( $params['tags'] ) {
81  $tagStatus = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $this->getAuthority() );
82  if ( !$tagStatus->isOK() ) {
83  $this->dieStatus( $tagStatus );
84  }
85  }
86 
87  // @TODO: remove this hack once rollback uses POST (T88044)
88  $fname = __METHOD__;
89  $trxLimits = $this->getConfig()->get( MainConfigNames::TrxProfilerLimits );
90  $trxProfiler = Profiler::instance()->getTransactionProfiler();
91  $trxProfiler->redefineExpectations( $trxLimits['POST'], $fname );
92  DeferredUpdates::addCallableUpdate( static function () use ( $trxProfiler, $trxLimits, $fname ) {
93  $trxProfiler->redefineExpectations( $trxLimits['PostSend-POST'], $fname );
94  } );
95 
96  $rollbackResult = $this->rollbackPageFactory
97  ->newRollbackPage( $titleObj, $this->getAuthority(), $this->getRbUser( $params ) )
98  ->setSummary( $params['summary'] )
99  ->markAsBot( $params['markbot'] )
100  ->setChangeTags( $params['tags'] )
101  ->rollbackIfAllowed();
102 
103  if ( !$rollbackResult->isGood() ) {
104  $this->dieStatus( $rollbackResult );
105  }
106 
107  $watch = $params['watchlist'] ?? 'preferences';
108  $watchlistExpiry = $this->getExpiryFromParams( $params );
109 
110  // Watch pages
111  $this->setWatch( $watch, $titleObj, $user, 'watchrollback', $watchlistExpiry );
112 
113  $details = $rollbackResult->getValue();
114  $currentRevisionRecord = $details['current-revision-record'];
115  $targetRevisionRecord = $details['target-revision-record'];
116 
117  $info = [
118  'title' => $titleObj->getPrefixedText(),
119  'pageid' => $currentRevisionRecord->getPageId(),
120  'summary' => $details['summary'],
121  'revid' => (int)$details['newid'],
122  // The revision being reverted (previously the current revision of the page)
123  'old_revid' => $currentRevisionRecord->getID(),
124  // The revision being restored (the last revision before revision(s) by the reverted user)
125  'last_revid' => $targetRevisionRecord->getID()
126  ];
127 
128  $this->getResult()->addValue( null, $this->getModuleName(), $info );
129  }
130 
131  public function mustBePosted() {
132  return true;
133  }
134 
135  public function isWriteMode() {
136  return true;
137  }
138 
139  public function getAllowedParams() {
140  $params = [
141  'title' => null,
142  'pageid' => [
143  ParamValidator::PARAM_TYPE => 'integer'
144  ],
145  'tags' => [
146  ParamValidator::PARAM_TYPE => 'tags',
147  ParamValidator::PARAM_ISMULTI => true,
148  ],
149  'user' => [
150  ParamValidator::PARAM_TYPE => 'user',
151  UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'id', 'interwiki' ],
152  UserDef::PARAM_RETURN_OBJECT => true,
153  ParamValidator::PARAM_REQUIRED => true
154  ],
155  'summary' => '',
156  'markbot' => false,
157  ];
158 
159  // Params appear in the docs in the order they are defined,
160  // which is why this is here (we want it above the token param).
161  $params += $this->getWatchlistParams();
162 
163  return $params + [
164  'token' => [
165  // Standard definition automatically inserted
166  ApiBase::PARAM_HELP_MSG_APPEND => [ 'api-help-param-token-webui' ],
167  ],
168  ];
169  }
170 
171  public function needsToken() {
172  return 'rollback';
173  }
174 
180  private function getRbUser( array $params ): UserIdentity {
181  if ( $this->mUser !== null ) {
182  return $this->mUser;
183  }
184 
185  $this->mUser = $params['user'];
186 
187  return $this->mUser;
188  }
189 
195  private function getRbTitle( array $params ) {
196  if ( $this->mTitleObj !== null ) {
197  return $this->mTitleObj;
198  }
199 
200  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
201 
202  if ( isset( $params['title'] ) ) {
203  $this->mTitleObj = Title::newFromText( $params['title'] );
204  if ( !$this->mTitleObj || $this->mTitleObj->isExternal() ) {
205  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
206  }
207  } elseif ( isset( $params['pageid'] ) ) {
208  $this->mTitleObj = Title::newFromID( $params['pageid'] );
209  if ( !$this->mTitleObj ) {
210  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
211  }
212  }
213 
214  if ( !$this->mTitleObj->exists() ) {
215  $this->dieWithError( 'apierror-missingtitle' );
216  }
217 
218  return $this->mTitleObj;
219  }
220 
221  protected function getExamplesMessages() {
222  return [
223  'action=rollback&title=Main%20Page&user=Example&token=123ABC' =>
224  'apihelp-rollback-example-simple',
225  'action=rollback&title=Main%20Page&user=192.0.2.5&' .
226  'token=123ABC&summary=Reverting%20vandalism&markbot=1' =>
227  'apihelp-rollback-example-summary',
228  ];
229  }
230 
231  public function getHelpUrls() {
232  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Rollback';
233  }
234 }
getExpiryFromParams(array $params)
Get formatted expiry from the given parameters, or null if no expiry was provided.
setWatch(string $watch, Title $title, User $user, ?string $userOption=null, ?string $expiry=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
getWatchlistParams(array $watchOptions=[])
Get additional allow params specific to watchlisting.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
if(!defined('MW_SETUP_CALLBACK'))
The persistent session ID (if any) loaded at startup.
Definition: WebStart.php:88
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:59
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition: ApiBase.php:173
getResult()
Get the result object.
Definition: ApiBase.php:637
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:773
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:506
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1521
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: ApiBase.php:1305
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:59
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
getHelpUrls()
Return links to more detailed help pages about the module.
isWriteMode()
Indicates whether this module requires write mode.
getExamplesMessages()
Returns usage examples for this module.
__construct(ApiMain $mainModule, $moduleName, RollbackPageFactory $rollbackPageFactory, WatchlistManager $watchlistManager, UserOptionsLookup $userOptionsLookup)
Definition: ApiRollback.php:42
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiRollback.php:70
mustBePosted()
Indicates whether this module must be called with a POST request.
needsToken()
Returns the token type this module requires in order to execute.
static canAddTagsAccompanyingChange(array $tags, Authority $performer=null, $checkBlock=true)
Is it OK to allow the user to apply all the specified tags at the same time as they edit/make the cha...
Definition: ChangeTags.php:637
static addCallableUpdate( $callable, $stage=self::POSTSEND, $dbw=null)
Add an update to the pending update queue that invokes the specified callback when run.
A class containing constants representing the names of configuration variables.
Represents a title within MediaWiki.
Definition: Title.php:82
Provides access to user options.
static instance()
Singleton.
Definition: Profiler.php:108
Service for formatting and validating API parameters.
trait ApiWatchlistTrait
An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to watch a...
Service for page rollback actions.
Interface for objects representing user identity.
return true
Definition: router.php:90