97 parent::__construct(
'MergeHistory',
'mergehistory' );
113 $this->mAction = $request->getRawVal(
'action' );
114 $this->mTarget = $request->getVal(
'target',
'' );
115 $this->mDest = $request->getVal(
'dest',
'' );
116 $this->mSubmitted = $request->getBool(
'submitted' );
118 $this->mTargetID = intval( $request->getVal(
'targetID' ) );
119 $this->mDestID = intval( $request->getVal(
'destID' ) );
120 $this->mTimestamp = $request->getVal(
'mergepoint' );
121 if ( $this->mTimestamp ===
null || !preg_match(
'/[0-9]{14}/', $this->mTimestamp ) ) {
122 $this->mTimestamp =
'';
124 $this->mComment = $request->getText(
'wpComment' );
126 $this->mMerge = $request->wasPosted()
127 && $this->
getUser()->matchEditToken( $request->getVal(
'wpEditToken' ) );
130 if ( $this->mSubmitted ) {
131 $this->mTargetObj = Title::newFromText( $this->mTarget );
132 $this->mDestObj = Title::newFromText( $this->mDest );
134 $this->mTargetObj =
null;
135 $this->mDestObj =
null;
150 if ( $this->mTargetID && $this->mDestID && $this->mAction ==
'submit' && $this->mMerge ) {
156 if ( !$this->mSubmitted ) {
163 if ( !$this->mTargetObj instanceof
Title ) {
164 $errors[] = $this->
msg(
'mergehistory-invalid-source' )->parseAsBlock();
165 } elseif ( !$this->mTargetObj->exists() ) {
166 $errors[] = $this->
msg(
'mergehistory-no-source',
171 if ( !$this->mDestObj instanceof
Title ) {
172 $errors[] = $this->
msg(
'mergehistory-invalid-destination' )->parseAsBlock();
173 } elseif ( !$this->mDestObj->exists() ) {
174 $errors[] = $this->
msg(
'mergehistory-no-destination',
179 if ( $this->mTargetObj && $this->mDestObj && $this->mTargetObj->equals( $this->mDestObj ) ) {
180 $errors[] = $this->
msg(
'mergehistory-same-destination' )->parseAsBlock();
183 if ( count( $errors ) ) {
185 $this->
getOutput()->addHTML( implode(
"\n", $errors ) );
193 $out->addWikiMsg(
'mergehistory-header' );
196 Xml::openElement(
'form', [
200 Xml::element(
'legend', [],
201 $this->
msg(
'mergehistory-box' )->text() ) .
202 Html::hidden(
'title', $this->
getPageTitle()->getPrefixedDBkey() ) .
203 Html::hidden(
'submitted',
'1' ) .
204 Html::hidden(
'mergepoint', $this->mTimestamp ) .
205 Xml::openElement(
'table' ) .
207 <td>' . Xml::label( $this->
msg(
'mergehistory-from' )->text(),
'target' ) .
'</td>
208 <td>' . Xml::input(
'target', 30, $this->mTarget, [
'id' =>
'target' ] ) .
'</td>
210 <td>' . Xml::label( $this->
msg(
'mergehistory-into' )->text(),
'dest' ) .
'</td>
211 <td>' . Xml::input(
'dest', 30, $this->mDest, [
'id' =>
'dest' ] ) .
'</td>
213 Xml::submitButton( $this->
msg(
'mergehistory-go' )->text() ) .
215 Xml::closeElement(
'table' ) .
226 # List all stored revisions
232 $this->linkBatchFactory,
236 $haveRevisions = $revisions->getNumRows() > 0;
240 $action = $titleObj->getLocalURL( [
'action' =>
'submit' ] );
241 # Start the form here
242 $top = Xml::openElement(
250 $out->addHTML( $top );
252 if ( $haveRevisions ) {
253 # Format the user-visible controls (comment field, submission button)
254 # in a nice little table
256 Xml::openElement(
'fieldset' ) .
257 $this->
msg(
'mergehistory-merge', $this->mTargetObj->getPrefixedText(),
258 $this->mDestObj->getPrefixedText() )->parse() .
259 Xml::openElement(
'table', [
'id' =>
'mw-mergehistory-table' ] ) .
261 <td class="mw-label">' .
262 Xml::label( $this->
msg(
'mergehistory-reason' )->text(),
'wpComment' ) .
264 <td class="mw-input">' .
265 Xml::input(
'wpComment', 50, $this->mComment, [
'id' =>
'wpComment' ] ) .
270 <td class=\"mw-submit\">" .
272 $this->
msg(
'mergehistory-submit' )->text(),
273 [
'name' =>
'merge',
'id' =>
'mw-merge-submit' ]
277 Xml::closeElement(
'table' ) .
278 Xml::closeElement(
'fieldset' );
280 $out->addHTML( $table );
284 '<h2 id="mw-mergehistory">' .
285 $this->
msg(
'mergehistory-list' )->escaped() .
"</h2>\n"
288 if ( $haveRevisions ) {
289 $out->addHTML( $revisions->getNavigationBar() );
290 $out->addHTML(
'<ul>' );
291 $out->addHTML( $revisions->getBody() );
292 $out->addHTML(
'</ul>' );
293 $out->addHTML( $revisions->getNavigationBar() );
295 $out->addWikiMsg(
'mergehistory-empty' );
298 # Show relevant lines from the merge log:
299 $mergeLogPage =
new LogPage(
'merge' );
300 $out->addHTML(
'<h2>' . $mergeLogPage->getName()->escaped() .
"</h2>\n" );
301 LogEventsList::showLogExtract( $out,
'merge', $this->mTargetObj );
303 # When we submit, go by page ID to avoid some nasty but unlikely collisions.
304 # Such would happen if a page was renamed after the form loaded, but before submit
305 $misc = Html::hidden(
'targetID', $this->mTargetObj->getArticleID() );
306 $misc .= Html::hidden(
'destID', $this->mDestObj->getArticleID() );
307 $misc .= Html::hidden(
'target', $this->mTarget );
308 $misc .= Html::hidden(
'dest', $this->mDest );
309 $misc .= Html::hidden(
'wpEditToken', $this->
getUser()->getEditToken() );
310 $misc .= Xml::closeElement(
'form' );
311 $out->addHTML( $misc );
317 $revRecord = $this->revisionStore->newRevisionFromRow( $row );
322 $last = $this->
msg(
'last' )->escaped();
325 $checkBox = Xml::radio(
'mergepoint', $ts, ( $this->mTimestamp === $ts ) );
330 $revRecord->getPageAsLinkTarget(),
331 $this->getLanguage()->userTimeAndDate( $ts, $user ),
333 [
'oldid' => $revRecord->getId() ]
335 if ( $revRecord->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
337 $pageLink =
'<span class=" ' . $class .
'">' . $pageLink .
'</span>';
341 if ( !$revRecord->userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
342 $last = $this->
msg(
'last' )->escaped();
343 } elseif ( isset( $this->prevId[$row->rev_id] ) ) {
345 $revRecord->getPageAsLinkTarget(),
346 $this->msg(
'last' )->text(),
349 'diff' => $row->rev_id,
350 'oldid' => $this->prevId[$row->rev_id]
357 $size = $row->rev_len;
358 if ( $size !==
null ) {
363 return Html::rawElement(
'li', [],
364 $this->
msg(
'mergehistory-revisionrow' )
365 ->rawParams( $checkBox, $last, $pageLink, $userLink, $stxt, $comment )->escaped() );
381 # Get the titles directly from the IDs, in case the target page params
382 # were spoofed. The queries are done based on the IDs, so it's best to
383 # keep it consistent...
384 $targetTitle = Title::newFromID( $this->mTargetID );
385 $destTitle = Title::newFromID( $this->mDestID );
386 if ( $targetTitle ===
null || $destTitle ===
null ) {
389 if ( $targetTitle->getArticleID() == $destTitle->getArticleID() ) {
394 $mh = $this->mergeHistoryFactory->newMergeHistory( $targetTitle, $destTitle, $this->mTimestamp );
397 $mergeStatus = $mh->merge( $this->
getUser(), $this->mComment );
398 if ( !$mergeStatus->isOK() ) {
400 $this->
getOutput()->addWikiMsg( $mergeStatus->getMessage() );
410 [
'redirect' =>
'no' ]
414 $append = ( $mergeStatus->getValue() ===
'source-deleted' )
415 ? $this->
msg(
'mergehistory-source-deleted', $targetTitle->getPrefixedText() ) :
'';
417 $this->
getOutput()->addWikiMsg( $this->
msg(
'mergehistory-done' )
418 ->rawParams( $targetLink )
419 ->params( $destTitle->getPrefixedText(), $append )
420 ->numParams( $mh->getMergedRevisionCount() )
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
static getRevisionDeletedClass(RevisionRecord $revisionRecord)
Returns css class of a deleted revision.
static revComment(RevisionRecord $revRecord, $local=false, $isPublic=false, $useParentheses=true)
Wrap and format the given revision's comment block, if the current user is allowed to view it.
static formatRevisionSize( $size)
static revUserTools(RevisionRecord $revRecord, $isPublic=false, $useParentheses=true)
Generate a user tool link cluster if the current user is allowed to view it.
Class to simplify the use of log pages.
Special page allowing users with the appropriate permissions to merge article histories,...
__construct(MergeHistoryFactory $mergeHistoryFactory, LinkBatchFactory $linkBatchFactory, ILoadBalancer $loadBalancer, RevisionStore $revisionStore)
merge()
Actually attempt the history move.
doesWrites()
Indicates whether this special page may perform database writes.
MergeHistoryFactory $mergeHistoryFactory
bool $mSubmitted
Was submitted?
execute( $par)
Default execute method Checks user permissions.
ILoadBalancer $loadBalancer
LinkBatchFactory $linkBatchFactory
RevisionStore $revisionStore
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Parent class for all special pages.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getOutput()
Get the OutputPage being used for this instance.
getUser()
Shortcut to get the User executing this instance.
checkPermissions()
Checks if userCanExecute, and if not throws a PermissionsError.
LinkRenderer null $linkRenderer
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getRequest()
Get the WebRequest being used for this instance.
checkReadOnly()
If the wiki is currently in readonly mode, throws a ReadOnlyError.
getPageTitle( $subpage=false)
Get a self-referential title object.
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Represents a title within MediaWiki.