MediaWiki REL1_36
RollbackAction.php
Go to the documentation of this file.
1<?php
26
33
34 public function getName() {
35 return 'rollback';
36 }
37
38 public function getRestriction() {
39 return 'rollback';
40 }
41
42 protected function usesOOUI() {
43 return true;
44 }
45
46 protected function getDescription() {
47 return '';
48 }
49
50 public function doesWrites() {
51 return true;
52 }
53
54 public function onSuccess() {
55 return false;
56 }
57
58 public function onSubmit( $data ) {
59 return false;
60 }
61
62 protected function alterForm( HTMLForm $form ) {
63 $form->setWrapperLegendMsg( 'confirm-rollback-top' );
64 $form->setSubmitTextMsg( 'confirm-rollback-button' );
65 $form->setTokenSalt( 'rollback' );
66
67 $from = $this->getRequest()->getVal( 'from' );
68 if ( $from === null ) {
69 throw new BadRequestError( 'rollbackfailed', 'rollback-missingparam' );
70 }
71 foreach ( [ 'from', 'bot', 'hidediff', 'summary', 'token' ] as $param ) {
72 $val = $this->getRequest()->getVal( $param );
73 if ( $val !== null ) {
74 $form->addHiddenField( $param, $val );
75 }
76 }
77 }
78
84 public function show() {
85 $this->setHeaders();
86 // This will throw exceptions if there's a problem
87 $this->checkCanExecute( $this->getUser() );
88
89 if ( $this->getUser()->getOption( 'showrollbackconfirmation' ) == false ||
90 $this->getRequest()->wasPosted() ) {
91 $this->handleRollbackRequest();
92 } else {
94 }
95 }
96
97 public function handleRollbackRequest() {
99 $this->getOutput()->addModuleStyles( 'mediawiki.interface.helpers.styles' );
100
101 $request = $this->getRequest();
102 $user = $this->getUser();
103 $from = $request->getVal( 'from' );
104 $rev = $this->getWikiPage()->getRevisionRecord();
105 if ( $from === null ) {
106 throw new ErrorPageError( 'rollbackfailed', 'rollback-missingparam' );
107 }
108 if ( !$rev ) {
109 throw new ErrorPageError( 'rollbackfailed', 'rollback-missingrevision' );
110 }
111
112 $revUser = $rev->getUser();
113 $userText = $revUser ? $revUser->getName() : '';
114 if ( $from !== $userText ) {
115 throw new ErrorPageError( 'rollbackfailed', 'alreadyrolled', [
116 $this->getTitle()->getPrefixedText(),
117 wfEscapeWikiText( $from ),
118 $userText
119 ] );
120 }
121
122 $data = null;
123 $errors = $this->getWikiPage()->doRollback(
124 $from,
125 $request->getText( 'summary' ),
126 $request->getVal( 'token' ),
127 $request->getBool( 'bot' ),
128 $data,
129 $this->getContext()->getAuthority()
130 );
131
132 if ( in_array( [ 'actionthrottledtext' ], $errors ) ) {
133 throw new ThrottledError;
134 }
135
136 if ( $this->hasRollbackRelatedErrors( $errors ) ) {
137 $this->getOutput()->setPageTitle( $this->msg( 'rollbackfailed' ) );
138 $errArray = $errors[0];
139 $errMsg = array_shift( $errArray );
140 $this->getOutput()->addWikiMsgArray( $errMsg, $errArray );
141
142 if ( isset( $data['current-revision-record'] ) ) {
144 $current = $data['current-revision-record'];
145
146 if ( $current->getComment() != null ) {
147 $this->getOutput()->addWikiMsg(
148 'editcomment',
151 $current->getComment()->text
152 )
153 )
154 );
155 }
156 }
157
158 return;
159 }
160
161 # NOTE: Permission errors already handled by Action::checkExecute.
162 if ( $errors == [ [ 'readonlytext' ] ] ) {
163 throw new ReadOnlyError;
164 }
165
166 # XXX: Would be nice if ErrorPageError could take multiple errors, and/or a status object.
167 # Right now, we only show the first error
168 foreach ( $errors as $error ) {
169 throw new ErrorPageError( 'rollbackfailed', $error[0], array_slice( $error, 1 ) );
170 }
171
173 $current = $data['current-revision-record'];
174 $target = $data['target-revision-record'];
175 $newId = $data['newid'];
176 $this->getOutput()->setPageTitle( $this->msg( 'actioncomplete' ) );
177 $this->getOutput()->setRobotPolicy( 'noindex,nofollow' );
178
179 $old = Linker::revUserTools( $current );
180 $new = Linker::revUserTools( $target );
181
182 $currentUser = $current->getUser( RevisionRecord::FOR_THIS_USER, $user );
183 $targetUser = $target->getUser( RevisionRecord::FOR_THIS_USER, $user );
184 $this->getOutput()->addHTML(
185 $this->msg( 'rollback-success' )
186 ->rawParams( $old, $new )
187 ->params( $currentUser ? $currentUser->getName() : '' )
188 ->params( $targetUser ? $targetUser->getName() : '' )
189 ->parseAsBlock()
190 );
191
192 $userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
193
194 if ( $userOptionsLookup->getBoolOption( $user, 'watchrollback' ) ) {
195 $user->addWatch( $this->getTitle(), User::IGNORE_USER_RIGHTS );
196 }
197
198 $this->getOutput()->returnToMain( false, $this->getTitle() );
199
200 if ( !$request->getBool( 'hidediff', false ) &&
201 !$userOptionsLookup->getBoolOption( $this->getUser(), 'norollbackdiff' )
202 ) {
203 $contentModel = $current->getSlot( SlotRecord::MAIN, RevisionRecord::RAW )
204 ->getModel();
205 $contentHandler = MediaWikiServices::getInstance()
206 ->getContentHandlerFactory()
207 ->getContentHandler( $contentModel );
208 $de = $contentHandler->createDifferenceEngine(
209 $this->getContext(),
210 $current->getId(),
211 $newId,
212 false,
213 true
214 );
215 $de->showDiff( '', '' );
216 }
217 }
218
223 private function enableTransactionalTimelimit() {
224 // If Rollbacks are made POST-only, use $this->useTransactionalTimeLimit()
226 if ( !$this->getRequest()->wasPosted() ) {
231 $fname = __METHOD__;
232 $trxLimits = $this->context->getConfig()->get( 'TrxProfilerLimits' );
233 $trxProfiler = Profiler::instance()->getTransactionProfiler();
234 $trxProfiler->redefineExpectations( $trxLimits['POST'], $fname );
235 DeferredUpdates::addCallableUpdate( static function () use ( $trxProfiler, $trxLimits, $fname
236 ) {
237 $trxProfiler->redefineExpectations( $trxLimits['PostSend-POST'], $fname );
238 } );
239 }
240 }
241
242 private function showRollbackConfirmationForm() {
243 $form = $this->getForm();
244 if ( $form->show() ) {
245 $this->onSuccess();
246 }
247 }
248
249 protected function getFormFields() {
250 return [
251 'intro' => [
252 'type' => 'info',
253 'vertical-label' => true,
254 'raw' => true,
255 'default' => $this->msg( 'confirm-rollback-bottom' )->parse()
256 ]
257 ];
258 }
259
260 private function hasRollbackRelatedErrors( array $errors ) {
261 return isset( $errors[0][0] ) &&
262 ( $errors[0][0] == 'alreadyrolled' ||
263 $errors[0][0] == 'cantrollback'
264 );
265 }
266}
wfTransactionalTimeLimit()
Raise the request time limit to $wgTransactionalTimeLimit.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
getWikiPage()
Get a WikiPage object.
Definition Action.php:267
checkCanExecute(User $user)
Checks if the given user (identified by an object) can perform this action.
Definition Action.php:410
getTitle()
Shortcut to get the Title object from the page.
Definition Action.php:288
getContext()
Get the IContextSource in use here.
Definition Action.php:204
getOutput()
Get the OutputPage being used for this instance.
Definition Action.php:228
getUser()
Shortcut to get the User being used for this instance.
Definition Action.php:238
setHeaders()
Set output headers for noindexing etc.
Definition Action.php:471
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition Action.php:300
getRequest()
Get the WebRequest being used for this instance.
Definition Action.php:218
An error page that emits an HTTP 400 Bad Request status code.
An error page which can definitely be safely rendered using the OutputPage.
An action which shows a form and does something based on the input from the form.
getForm()
Get the HTMLForm to control behavior.
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:140
setSubmitTextMsg( $msg)
Set the text for the submit button to a message.
setWrapperLegendMsg( $msg)
Prompt the whole form to be wrapped in a "<fieldset>", with this message as its "<legend>" element.
addHiddenField( $name, $value, array $attribs=[])
Add a hidden field to the output.
Definition HTMLForm.php:965
setTokenSalt( $salt)
Set the salt for the edit token.
static revUserTools( $rev, $isPublic=false, $useParentheses=true)
Generate a user tool link cluster if the current user is allowed to view it.
Definition Linker.php:1147
static formatComment( $comment, $title=null, $local=false, $wikiId=null)
This function is called by all recent changes variants, by the page history, and by the user contribu...
Definition Linker.php:1202
MediaWikiServices is the service locator for the application scope of MediaWiki.
Page revision base class.
Value object representing a content slot associated with a page revision.
static rawParam( $raw)
Definition Message.php:1087
Show an error when the wiki is locked/read-only and the user tries to do something that requires writ...
User interface for the rollback action.
getFormFields()
Get an HTMLForm descriptor array.
getDescription()
Returns the description that goes below the <h1> tag.
enableTransactionalTimelimit()
Enables transactional time limit for POST and GET requests to RollbackAction.
usesOOUI()
Whether the form should use OOUI.
onSubmit( $data)
Process the form on POST submission.
alterForm(HTMLForm $form)
Play with the HTMLForm if you need to more substantially.
getRestriction()
Get the permission required to perform this action.
onSuccess()
Do something exciting on successful processing of the form.
hasRollbackRelatedErrors(array $errors)
getName()
Return the name of the action this object responds to.
Show an error when the user hits a rate limit.
const IGNORE_USER_RIGHTS
Definition User.php:102