MediaWiki  master
RollbackAction.php
Go to the documentation of this file.
1 <?php
30 
36 class RollbackAction extends FormAction {
37 
40 
43 
46 
49 
52 
62  public function __construct(
63  Page $page,
70  ) {
71  parent::__construct( $page, $context );
72  $this->contentHandlerFactory = $contentHandlerFactory;
73  $this->rollbackPageFactory = $rollbackPageFactory;
74  $this->userOptionsLookup = $userOptionsLookup;
75  $this->watchlistManager = $watchlistManager;
76  $this->commentFormatter = $commentFormatter;
77  }
78 
79  public function getName() {
80  return 'rollback';
81  }
82 
83  public function getRestriction() {
84  return 'rollback';
85  }
86 
87  protected function usesOOUI() {
88  return true;
89  }
90 
91  protected function getDescription() {
92  return '';
93  }
94 
95  public function doesWrites() {
96  return true;
97  }
98 
99  public function onSuccess() {
100  return false;
101  }
102 
103  public function onSubmit( $data ) {
104  return false;
105  }
106 
107  protected function alterForm( HTMLForm $form ) {
108  $form->setWrapperLegendMsg( 'confirm-rollback-top' );
109  $form->setSubmitTextMsg( 'confirm-rollback-button' );
110  $form->setTokenSalt( 'rollback' );
111 
112  $from = $this->getRequest()->getVal( 'from' );
113  if ( $from === null ) {
114  throw new BadRequestError( 'rollbackfailed', 'rollback-missingparam' );
115  }
116  foreach ( [ 'from', 'bot', 'hidediff', 'summary', 'token' ] as $param ) {
117  $val = $this->getRequest()->getVal( $param );
118  if ( $val !== null ) {
119  $form->addHiddenField( $param, $val );
120  }
121  }
122  }
123 
129  public function show() {
130  if ( !$this->userOptionsLookup->getOption( $this->getUser(), 'showrollbackconfirmation' ) ||
131  $this->getRequest()->wasPosted()
132  ) {
133  $this->handleRollbackRequest();
134  } else {
136  }
137  }
138 
139  public function handleRollbackRequest() {
141  $this->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
142 
143  $request = $this->getRequest();
144  $user = $this->getUser();
145  $from = $request->getVal( 'from' );
146  $rev = $this->getWikiPage()->getRevisionRecord();
147  if ( $from === null ) {
148  throw new ErrorPageError( 'rollbackfailed', 'rollback-missingparam' );
149  }
150  if ( !$rev ) {
151  throw new ErrorPageError( 'rollbackfailed', 'rollback-missingrevision' );
152  }
153 
154  $revUser = $rev->getUser();
155  $userText = $revUser ? $revUser->getName() : '';
156  if ( $from !== $userText ) {
157  throw new ErrorPageError( 'rollbackfailed', 'alreadyrolled', [
158  $this->getTitle()->getPrefixedText(),
159  $from,
160  $userText
161  ] );
162  }
163 
164  if ( !$user->matchEditToken( $request->getVal( 'token' ), 'rollback' ) ) {
165  throw new ErrorPageError( 'sessionfailure-title', 'sessionfailure' );
166  }
167 
168  // The revision has the user suppressed, so the rollback has empty 'from',
169  // so the check above would succeed in that case.
170  if ( !$revUser ) {
171  $revUser = $rev->getUser( RevisionRecord::RAW );
172  }
173 
174  $rollbackResult = $this->rollbackPageFactory
175  ->newRollbackPage( $this->getWikiPage(), $this->getContext()->getAuthority(), $revUser )
176  ->setSummary( $request->getText( 'summary' ) )
177  ->markAsBot( $request->getBool( 'bot' ) )
178  ->rollbackIfAllowed();
179  $data = $rollbackResult->getValue();
180 
181  if ( $rollbackResult->hasMessage( 'actionthrottledtext' ) ) {
182  throw new ThrottledError;
183  }
184 
185  if ( $rollbackResult->hasMessage( 'alreadyrolled' ) || $rollbackResult->hasMessage( 'cantrollback' ) ) {
186  $this->getOutput()->setPageTitle( $this->msg( 'rollbackfailed' ) );
187  $errArray = $rollbackResult->getErrors()[0];
188  $this->getOutput()->addWikiMsgArray( $errArray['message'], $errArray['params'] );
189 
190  if ( isset( $data['current-revision-record'] ) ) {
192  $current = $data['current-revision-record'];
193 
194  if ( $current->getComment() != null ) {
195  $this->getOutput()->addWikiMsg(
196  'editcomment',
198  $this->commentFormatter
199  ->format( $current->getComment()->text )
200  )
201  );
202  }
203  }
204 
205  return;
206  }
207 
208  # NOTE: Permission errors already handled by Action::checkExecute.
209  if ( $rollbackResult->hasMessage( 'readonlytext' ) ) {
210  throw new ReadOnlyError;
211  }
212 
213  # XXX: Would be nice if ErrorPageError could take multiple errors, and/or a status object.
214  # Right now, we only show the first error
215  foreach ( $rollbackResult->getErrors() as $error ) {
216  throw new ErrorPageError( 'rollbackfailed', $error['message'], $error['params'] );
217  }
218 
220  $current = $data['current-revision-record'];
221  $target = $data['target-revision-record'];
222  $newId = $data['newid'];
223  $this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
224  $this->getOutput()->setRobotPolicy( 'noindex,nofollow' );
225 
226  $old = Linker::revUserTools( $current );
227  $new = Linker::revUserTools( $target );
228 
229  $currentUser = $current->getUser( RevisionRecord::FOR_THIS_USER, $user );
230  $targetUser = $target->getUser( RevisionRecord::FOR_THIS_USER, $user );
231  $this->getOutput()->addHTML(
232  $this->msg( 'rollback-success' )
233  ->rawParams( $old, $new )
234  ->params( $currentUser ? $currentUser->getName() : '' )
235  ->params( $targetUser ? $targetUser->getName() : '' )
236  ->parseAsBlock()
237  );
238 
239  if ( $this->userOptionsLookup->getBoolOption( $user, 'watchrollback' ) ) {
240  $this->watchlistManager->addWatchIgnoringRights( $user, $this->getTitle() );
241  }
242 
243  $this->getOutput()->returnToMain( false, $this->getTitle() );
244 
245  if ( !$request->getBool( 'hidediff', false ) &&
246  !$this->userOptionsLookup->getBoolOption( $this->getUser(), 'norollbackdiff' )
247  ) {
248  $contentModel = $current->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )
249  ->getModel();
250  $contentHandler = $this->contentHandlerFactory->getContentHandler( $contentModel );
251  $de = $contentHandler->createDifferenceEngine(
252  $this->getContext(),
253  $current->getId(),
254  $newId,
255  false,
256  true
257  );
258  $de->showDiff( '', '' );
259  }
260  }
261 
266  private function enableTransactionalTimelimit() {
267  // If Rollbacks are made POST-only, use $this->useTransactionalTimeLimit()
269  if ( !$this->getRequest()->wasPosted() ) {
274  $fname = __METHOD__;
275  $trxLimits = $this->context->getConfig()->get( 'TrxProfilerLimits' );
276  $trxProfiler = Profiler::instance()->getTransactionProfiler();
277  $trxProfiler->redefineExpectations( $trxLimits['POST'], $fname );
278  DeferredUpdates::addCallableUpdate( static function () use ( $trxProfiler, $trxLimits, $fname
279  ) {
280  $trxProfiler->redefineExpectations( $trxLimits['PostSend-POST'], $fname );
281  } );
282  }
283  }
284 
285  private function showRollbackConfirmationForm() {
286  $form = $this->getForm();
287  if ( $form->show() ) {
288  $this->onSuccess();
289  }
290  }
291 
292  protected function getFormFields() {
293  return [
294  'intro' => [
295  'type' => 'info',
296  'raw' => true,
297  'default' => $this->msg( 'confirm-rollback-bottom' )->parse()
298  ]
299  ];
300  }
301 }
ReadOnlyError
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
Definition: ReadOnlyError.php:29
RollbackAction\showRollbackConfirmationForm
showRollbackConfirmationForm()
Definition: RollbackAction.php:285
Page
Interface for type hinting (accepts WikiPage, Article, ImagePage, CategoryPage)
Definition: Page.php:29
MediaWiki\Revision\RevisionRecord
Page revision base class.
Definition: RevisionRecord.php:47
RollbackAction\$watchlistManager
WatchlistManager $watchlistManager
Definition: RollbackAction.php:48
RollbackAction\alterForm
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
Definition: RollbackAction.php:107
Linker\revUserTools
static revUserTools(RevisionRecord $revRecord, $isPublic=false, $useParentheses=true)
Generate a user tool link cluster if the current user is allowed to view it.
Definition: Linker.php:1319
Profiler\instance
static instance()
Singleton.
Definition: Profiler.php:69
Action\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: Action.php:146
RollbackAction\show
show()
Definition: RollbackAction.php:129
RollbackAction\getDescription
getDescription()
Returns the description that goes below the <h1> tag.
Definition: RollbackAction.php:91
HTMLForm\setTokenSalt
setTokenSalt( $salt)
Set the salt for the edit token.
Definition: HTMLForm.php:1057
Page\RollbackPageFactory
Definition: RollbackPageFactory.php:32
getAuthority
getAuthority()
FormAction
An action which shows a form and does something based on the input from the form.
Definition: FormAction.php:30
MediaWiki\CommentFormatter\CommentFormatter
This is the main service interface for converting single-line comments from various DB comment fields...
Definition: CommentFormatter.php:16
RollbackAction\handleRollbackRequest
handleRollbackRequest()
Definition: RollbackAction.php:139
RollbackAction\getFormFields
getFormFields()
Get an HTMLForm descriptor array.
Definition: RollbackAction.php:292
RollbackAction\__construct
__construct(Page $page, ?IContextSource $context, IContentHandlerFactory $contentHandlerFactory, RollbackPageFactory $rollbackPageFactory, UserOptionsLookup $userOptionsLookup, WatchlistManager $watchlistManager, CommentFormatter $commentFormatter)
Definition: RollbackAction.php:62
RollbackAction\usesOOUI
usesOOUI()
Whether the form should use OOUI.
Definition: RollbackAction.php:87
Action\getContext
getContext()
Get the IContextSource in use here.
Definition: Action.php:132
MediaWiki\Watchlist\WatchlistManager
WatchlistManager service.
Definition: WatchlistManager.php:52
RollbackAction\$userOptionsLookup
UserOptionsLookup $userOptionsLookup
Definition: RollbackAction.php:45
wfTransactionalTimeLimit
wfTransactionalTimeLimit()
Raise the request time limit to $wgTransactionalTimeLimit.
Definition: GlobalFunctions.php:2390
HTMLForm\addHiddenField
addHiddenField( $name, $value, array $attribs=[])
Add a hidden field to the output.
Definition: HTMLForm.php:968
RollbackAction\onSubmit
onSubmit( $data)
Process the form on POST submission.
Definition: RollbackAction.php:103
ThrottledError
Show an error when the user hits a rate limit.
Definition: ThrottledError.php:28
RollbackAction\enableTransactionalTimelimit
enableTransactionalTimelimit()
Enables transactional time limit for POST and GET requests to RollbackAction.
Definition: RollbackAction.php:266
RollbackAction\$rollbackPageFactory
RollbackPageFactory $rollbackPageFactory
Definition: RollbackAction.php:42
Action\getWikiPage
getWikiPage()
Get a WikiPage object.
Definition: Action.php:195
FormAction\getForm
getForm()
Get the HTMLForm to control behavior.
Definition: FormAction.php:81
Action\getUser
getUser()
Shortcut to get the User being used for this instance.
Definition: Action.php:166
Action\$context
IContextSource $context
IContextSource if specified; otherwise we'll use the Context from the Page.
Definition: Action.php:66
RollbackAction\getRestriction
getRestriction()
Get the permission required to perform this action.
Definition: RollbackAction.php:83
MediaWiki\Content\IContentHandlerFactory
Definition: IContentHandlerFactory.php:10
Message\rawParam
static rawParam( $raw)
Definition: Message.php:1116
RollbackAction\$contentHandlerFactory
IContentHandlerFactory $contentHandlerFactory
Definition: RollbackAction.php:39
Action\getTitle
getTitle()
Shortcut to get the Title object from the page.
Definition: Action.php:216
MediaWiki\User\UserOptionsLookup
Provides access to user options.
Definition: UserOptionsLookup.php:29
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:58
HTMLForm\setSubmitTextMsg
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
Definition: HTMLForm.php:1420
RollbackAction
User interface for the rollback action.
Definition: RollbackAction.php:36
Action\$page
WikiPage Article ImagePage CategoryPage Page $page
Page on which we're performing the action.
Definition: Action.php:53
Action\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: Action.php:228
HTMLForm\setWrapperLegendMsg
setWrapperLegendMsg( $msg)
Prompt the whole form to be wrapped in a "<fieldset>", with this message as its "<legend>" element.
Definition: HTMLForm.php:1625
BadRequestError
An error page that emits an HTTP 400 Bad Request status code.
Definition: BadRequestError.php:29
Action\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: Action.php:156
RollbackAction\doesWrites
doesWrites()
Definition: RollbackAction.php:95
RollbackAction\$commentFormatter
CommentFormatter $commentFormatter
Definition: RollbackAction.php:51
RollbackAction\onSuccess
onSuccess()
Do something exciting on successful processing of the form.
Definition: RollbackAction.php:99
ErrorPageError
An error page which can definitely be safely rendered using the OutputPage.
Definition: ErrorPageError.php:30
DeferredUpdates\addCallableUpdate
static addCallableUpdate( $callable, $stage=self::POSTSEND, $dbw=null)
Add an update to the pending update queue that invokes the specified callback when run.
Definition: DeferredUpdates.php:145
RollbackAction\getName
getName()
Return the name of the action this object responds to.
Definition: RollbackAction.php:79
MediaWiki\Revision\SlotRecord
Value object representing a content slot associated with a page revision.
Definition: SlotRecord.php:40
HTMLForm
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:143