74 private $mergeHistoryFactory;
77 private $linkBatchFactory;
80 private $loadBalancer;
83 private $revisionStore;
97 parent::__construct(
'MergeHistory',
'mergehistory' );
98 $this->mergeHistoryFactory = $mergeHistoryFactory;
99 $this->linkBatchFactory = $linkBatchFactory;
100 $this->loadBalancer = $loadBalancer;
101 $this->revisionStore = $revisionStore;
111 private function loadRequestParams() {
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 ) {
134 $this->mTargetObj =
null;
135 $this->mDestObj =
null;
145 $this->loadRequestParams();
150 if ( $this->mTargetID && $this->mDestID && $this->mAction ==
'submit' && $this->mMerge ) {
156 if ( !$this->mSubmitted ) {
157 $this->showMergeForm();
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 ) ) {
184 $this->showMergeForm();
185 $this->
getOutput()->addHTML( implode(
"\n", $errors ) );
187 $this->showHistory();
191 private function showMergeForm() {
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' ) .
223 private function showHistory() {
224 $this->showMergeForm();
226 # List all stored revisions
229 $this->linkBatchFactory,
231 $this->revisionStore,
236 $haveRevisions = $revisions->getNumRows() > 0;
239 $out->addModuleStyles( [
'mediawiki.interface.helpers.styles' ] );
241 $action = $titleObj->getLocalURL( [
'action' =>
'submit' ] );
242 # Start the form here
251 $out->addHTML( $top );
253 if ( $haveRevisions ) {
254 # Format the user-visible controls (comment field, submission button)
255 # in a nice little table
258 $this->
msg(
'mergehistory-merge', $this->mTargetObj->getPrefixedText(),
259 $this->mDestObj->getPrefixedText() )->parse() .
262 <td class="mw-label">' .
263 Xml::label( $this->
msg(
'mergehistory-reason' )->text(),
'wpComment' ) .
265 <td class="mw-input">' .
266 Xml::input(
'wpComment', 50, $this->mComment, [
'id' =>
'wpComment' ] ) .
271 <td class=\"mw-submit\">" .
273 $this->
msg(
'mergehistory-submit' )->text(),
274 [
'name' =>
'merge',
'id' =>
'mw-merge-submit' ]
281 $out->addHTML( $table );
285 '<h2 id="mw-mergehistory">' .
286 $this->
msg(
'mergehistory-list' )->escaped() .
"</h2>\n"
289 if ( $haveRevisions ) {
290 $out->addHTML( $revisions->getNavigationBar() );
291 $out->addHTML( $revisions->getBody() );
292 $out->addHTML( $revisions->getNavigationBar() );
294 $out->addWikiMsg(
'mergehistory-empty' );
297 # Show relevant lines from the merge log:
298 $mergeLogPage =
new LogPage(
'merge' );
299 $out->addHTML(
'<h2>' . $mergeLogPage->getName()->escaped() .
"</h2>\n" );
302 # When we submit, go by page ID to avoid some nasty but unlikely collisions.
303 # Such would happen if a page was renamed after the form loaded, but before submit
304 $misc =
Html::hidden(
'targetID', $this->mTargetObj->getArticleID() );
305 $misc .=
Html::hidden(
'destID', $this->mDestObj->getArticleID() );
310 $out->addHTML( $misc );
316 $revRecord = $this->revisionStore->newRevisionFromRow( $row );
321 $last = $this->
msg(
'last' )->escaped();
324 $checkBox = Xml::radio(
'mergepoint', $ts, ( $this->mTimestamp === $ts ) );
328 $pageLink = $linkRenderer->makeKnownLink(
329 $revRecord->getPageAsLinkTarget(),
330 $this->getLanguage()->userTimeAndDate( $ts, $user ),
332 [
'oldid' => $revRecord->getId() ]
334 if ( $revRecord->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
336 $pageLink =
'<span class=" ' . $class .
'">' . $pageLink .
'</span>';
340 if ( !$revRecord->userCan( RevisionRecord::DELETED_TEXT, $this->getAuthority() ) ) {
341 $last = $this->
msg(
'last' )->escaped();
342 } elseif ( isset( $this->prevId[$row->rev_id] ) ) {
343 $last = $linkRenderer->makeKnownLink(
344 $revRecord->getPageAsLinkTarget(),
345 $this->msg(
'last' )->text(),
348 'diff' => $row->rev_id,
349 'oldid' => $this->prevId[$row->rev_id]
356 $size = $row->rev_len;
357 if ( $size !==
null ) {
369 return Html::rawElement(
'li', $classes,
370 $this->
msg(
'mergehistory-revisionrow' )
371 ->rawParams( $checkBox, $last, $pageLink, $userLink, $stxt, $comment, $tagSummary )->escaped() );
386 private function merge() {
387 # Get the titles directly from the IDs, in case the target page params
388 # were spoofed. The queries are done based on the IDs, so it's best to
389 # keep it consistent...
390 $targetTitle = Title::newFromID( $this->mTargetID );
391 $destTitle = Title::newFromID( $this->mDestID );
392 if ( $targetTitle ===
null || $destTitle ===
null ) {
395 if ( $targetTitle->getArticleID() == $destTitle->getArticleID() ) {
400 $mh = $this->mergeHistoryFactory->newMergeHistory( $targetTitle, $destTitle, $this->mTimestamp );
403 $mergeStatus = $mh->merge( $this->
getAuthority(), $this->mComment );
404 if ( !$mergeStatus->isOK() ) {
406 $this->
getOutput()->addWikiMsg( $mergeStatus->getMessage() );
412 $targetLink = $linkRenderer->makeLink(
416 [
'redirect' =>
'no' ]
420 $append = ( $mergeStatus->getValue() ===
'source-deleted' )
421 ? $this->
msg(
'mergehistory-source-deleted', $targetTitle->getPrefixedText() ) :
'';
423 $this->
getOutput()->addWikiMsg( $this->
msg(
'mergehistory-done' )
424 ->rawParams( $targetLink )
425 ->params( $destTitle->getPrefixedText(), $append )
426 ->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 hidden( $name, $value, array $attribs=[])
Convenience function to produce an input element with type=hidden.
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.
static showLogExtract(&$out, $types=[], $page='', $user='', $param=[])
Show log extract.
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)
doesWrites()
Indicates whether this special page may perform database writes.
bool $mSubmitted
Was submitted?
execute( $par)
Default execute method Checks user permissions.
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.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getAuthority()
Shortcut to get the Authority executing this instance.
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.
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
static closeElement( $element)
Shortcut to close an XML element.
static label( $label, $id, $attribs=[])
Convenience function to build an HTML form label.
static openElement( $element, $attribs=null)
This opens an XML element.
static input( $name, $size=false, $value=false, $attribs=[])
Convenience function to build an HTML text input field.
static submitButton( $value, $attribs=[])
Convenience function to build an HTML submit button When $wgUseMediaWikiUIEverywhere is true it will ...
Service for mergehistory actions.