MediaWiki  master
ApiRollback.php
Go to the documentation of this file.
1 <?php
30 
34 class ApiRollback extends ApiBase {
35 
37 
39  private $rollbackPageFactory;
40 
41  public function __construct(
42  ApiMain $mainModule,
43  $moduleName,
44  RollbackPageFactory $rollbackPageFactory,
45  WatchlistManager $watchlistManager,
46  UserOptionsLookup $userOptionsLookup
47  ) {
48  parent::__construct( $mainModule, $moduleName );
49  $this->rollbackPageFactory = $rollbackPageFactory;
50 
51  // Variables needed in ApiWatchlistTrait trait
52  $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
53  $this->watchlistMaxDuration =
54  $this->getConfig()->get( MainConfigNames::WatchlistExpiryMaxDuration );
55  $this->watchlistManager = $watchlistManager;
56  $this->userOptionsLookup = $userOptionsLookup;
57  }
58 
62  private $mTitleObj = null;
63 
67  private $mUser = null;
68 
69  public function execute() {
71 
72  $user = $this->getUser();
73  $params = $this->extractRequestParams();
74 
75  $titleObj = $this->getRbTitle( $params );
76 
77  // If change tagging was requested, check that the user is allowed to tag,
78  // and the tags are valid. TODO: move inside rollback command?
79  if ( $params['tags'] ) {
80  $tagStatus = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $this->getAuthority() );
81  if ( !$tagStatus->isOK() ) {
82  $this->dieStatus( $tagStatus );
83  }
84  }
85 
86  // @TODO: remove this hack once rollback uses POST (T88044)
87  $fname = __METHOD__;
88  $trxLimits = $this->getConfig()->get( MainConfigNames::TrxProfilerLimits );
89  $trxProfiler = Profiler::instance()->getTransactionProfiler();
90  $trxProfiler->redefineExpectations( $trxLimits['POST'], $fname );
91  DeferredUpdates::addCallableUpdate( static function () use ( $trxProfiler, $trxLimits, $fname ) {
92  $trxProfiler->redefineExpectations( $trxLimits['PostSend-POST'], $fname );
93  } );
94 
95  $rollbackResult = $this->rollbackPageFactory
96  ->newRollbackPage( $titleObj, $this->getAuthority(), $this->getRbUser( $params ) )
97  ->setSummary( $params['summary'] )
98  ->markAsBot( $params['markbot'] )
99  ->setChangeTags( $params['tags'] )
100  ->rollbackIfAllowed();
101 
102  if ( !$rollbackResult->isGood() ) {
103  $this->dieStatus( $rollbackResult );
104  }
105 
106  $watch = $params['watchlist'] ?? 'preferences';
107  $watchlistExpiry = $this->getExpiryFromParams( $params );
108 
109  // Watch pages
110  $this->setWatch( $watch, $titleObj, $user, 'watchrollback', $watchlistExpiry );
111 
112  $details = $rollbackResult->getValue();
113  $currentRevisionRecord = $details['current-revision-record'];
114  $targetRevisionRecord = $details['target-revision-record'];
115 
116  $info = [
117  'title' => $titleObj->getPrefixedText(),
118  'pageid' => $currentRevisionRecord->getPageId(),
119  'summary' => $details['summary'],
120  'revid' => (int)$details['newid'],
121  // The revision being reverted (previously the current revision of the page)
122  'old_revid' => $currentRevisionRecord->getID(),
123  // The revision being restored (the last revision before revision(s) by the reverted user)
124  'last_revid' => $targetRevisionRecord->getID()
125  ];
126 
127  $this->getResult()->addValue( null, $this->getModuleName(), $info );
128  }
129 
130  public function mustBePosted() {
131  return true;
132  }
133 
134  public function isWriteMode() {
135  return true;
136  }
137 
138  public function getAllowedParams() {
139  $params = [
140  'title' => null,
141  'pageid' => [
142  ParamValidator::PARAM_TYPE => 'integer'
143  ],
144  'tags' => [
145  ParamValidator::PARAM_TYPE => 'tags',
146  ParamValidator::PARAM_ISMULTI => true,
147  ],
148  'user' => [
149  ParamValidator::PARAM_TYPE => 'user',
150  UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'id', 'interwiki' ],
151  UserDef::PARAM_RETURN_OBJECT => true,
152  ParamValidator::PARAM_REQUIRED => true
153  ],
154  'summary' => '',
155  'markbot' => false,
156  ];
157 
158  // Params appear in the docs in the order they are defined,
159  // which is why this is here (we want it above the token param).
160  $params += $this->getWatchlistParams();
161 
162  return $params + [
163  'token' => [
164  // Standard definition automatically inserted
165  ApiBase::PARAM_HELP_MSG_APPEND => [ 'api-help-param-token-webui' ],
166  ],
167  ];
168  }
169 
170  public function needsToken() {
171  return 'rollback';
172  }
173 
179  private function getRbUser( array $params ): UserIdentity {
180  if ( $this->mUser !== null ) {
181  return $this->mUser;
182  }
183 
184  $this->mUser = $params['user'];
185 
186  return $this->mUser;
187  }
188 
194  private function getRbTitle( array $params ) {
195  if ( $this->mTitleObj !== null ) {
196  return $this->mTitleObj;
197  }
198 
199  $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
200 
201  if ( isset( $params['title'] ) ) {
202  $this->mTitleObj = Title::newFromText( $params['title'] );
203  if ( !$this->mTitleObj || $this->mTitleObj->isExternal() ) {
204  $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
205  }
206  } elseif ( isset( $params['pageid'] ) ) {
207  $this->mTitleObj = Title::newFromID( $params['pageid'] );
208  if ( !$this->mTitleObj ) {
209  $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
210  }
211  }
212 
213  if ( !$this->mTitleObj->exists() ) {
214  $this->dieWithError( 'apierror-missingtitle' );
215  }
216 
217  return $this->mTitleObj;
218  }
219 
220  protected function getExamplesMessages() {
221  return [
222  'action=rollback&title=Main%20Page&user=Example&token=123ABC' =>
223  'apihelp-rollback-example-simple',
224  'action=rollback&title=Main%20Page&user=192.0.2.5&' .
225  'token=123ABC&summary=Reverting%20vandalism&markbot=1' =>
226  'apihelp-rollback-example-summary',
227  ];
228  }
229 
230  public function getHelpUrls() {
231  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Rollback';
232  }
233 }
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:82
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:56
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition: ApiBase.php:170
getResult()
Get the result object.
Definition: ApiBase.php:629
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:765
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:498
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1516
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition: ApiBase.php:1298
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:52
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:41
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiRollback.php:69
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:635
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.
Provides access to user options.
static instance()
Singleton.
Definition: Profiler.php:69
static newFromID( $id, $flags=0)
Create a new Title from an article ID.
Definition: Title.php:518
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:370
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