70 private LinkBatchFactory $linkBatchFactory;
81 LinkBatchFactory $linkBatchFactory,
87 parent::__construct(
'MergeHistory',
'mergehistory' );
88 $this->mergeHistoryFactory = $mergeHistoryFactory;
89 $this->linkBatchFactory = $linkBatchFactory;
90 $this->dbProvider = $dbProvider;
91 $this->revisionStore = $revisionStore;
92 $this->commentFormatter = $commentFormatter;
93 $this->changeTagsStore = $changeTagsStore;
104 private function loadRequestParams() {
106 $this->mAction = $request->getRawVal(
'action' );
107 $this->mTarget = $request->getVal(
'target',
'' );
108 $this->mDest = $request->getVal(
'dest',
'' );
109 $this->mSubmitted = $request->getBool(
'submitted' );
111 $this->mTargetID = intval( $request->getVal(
'targetID' ) );
112 $this->mDestID = intval( $request->getVal(
'destID' ) );
113 $this->mTimestamp = $request->getVal(
'mergepoint' );
114 if ( $this->mTimestamp ===
null || !preg_match(
'/[0-9]{14}(\|[0-9]+)?/', $this->mTimestamp ) ) {
115 $this->mTimestamp =
'';
117 $this->mTimestampOld = $request->getVal(
'mergepointold' );
118 if ( $this->mTimestampOld ===
null || !preg_match(
'/[0-9]{14}(\|[0-9]+)?/', $this->mTimestamp ) ) {
119 $this->mTimestampOld =
'';
121 $this->mComment = $request->getText(
'wpComment' );
123 $this->mMerge = $request->wasPosted()
124 && $this->
getContext()->getCsrfTokenSet()->matchToken( $request->getVal(
'wpEditToken' ) );
127 if ( $this->mSubmitted ) {
128 $this->mTargetObj = Title::newFromText( $this->mTarget );
129 $this->mDestObj = Title::newFromText( $this->mDest );
131 $this->mTargetObj =
null;
132 $this->mDestObj =
null;
143 $this->loadRequestParams();
147 $status = Status::newGood();
149 if ( $this->mTargetID && $this->mDestID && $this->mAction ==
'submit' && $this->mMerge ) {
155 if ( !$this->mSubmitted ) {
156 $this->showMergeForm();
161 if ( !$this->mTargetObj instanceof
Title ) {
162 $status->merge( Status::newFatal(
'mergehistory-invalid-source' ) );
163 } elseif ( !$this->mTargetObj->exists() ) {
164 $status->merge( Status::newFatal(
165 'mergehistory-no-source',
170 if ( !$this->mDestObj instanceof
Title ) {
171 $status->merge( Status::newFatal(
'mergehistory-invalid-destination' ) );
172 } elseif ( !$this->mDestObj->exists() ) {
173 $status->merge( Status::newFatal(
174 'mergehistory-no-destination',
179 if ( $this->mTargetObj && $this->mDestObj && $this->mTargetObj->equals( $this->mDestObj ) ) {
180 $status->merge( Status::newFatal(
'mergehistory-same-destination' ) );
183 $this->mStatus = $status;
185 $this->showMergeForm();
187 if ( $this->mStatus->isGood() ) {
188 $this->showHistory();
192 private function showMergeForm() {
194 $out->addWikiMsg(
'mergehistory-header' );
200 'name' =>
'submitted'
210 'name' =>
'mergepoint'
215 'name' =>
'mergepointold'
219 'label-message' =>
'mergehistory-from',
226 'label-message' =>
'mergehistory-into',
233 $form = HTMLForm::factory(
'ooui', $fields, $this->
getContext() );
234 $form->setWrapperLegendMsg(
'mergehistory-box' )
235 ->setSubmitTextMsg(
'mergehistory-go' )
238 ->displayForm( $this->mStatus );
243 private function showHistory() {
244 # List all stored revisions
245 $revisions =
new MergeHistoryPager(
248 $this->linkBatchFactory,
250 $this->revisionStore,
251 $this->commentFormatter,
252 $this->changeTagsStore,
259 $haveRevisions = $revisions->getNumRows() > 0;
262 $out->addModuleStyles( [
263 'mediawiki.interface.helpers.styles',
266 $out->addModules(
'mediawiki.special.mergeHistory' );
268 $action = $titleObj->getLocalURL( [
'action' =>
'submit' ] );
269 # Start the form here
273 'name' =>
'targetID',
274 'default' => $this->mTargetObj->getArticleID()
279 'default' => $this->mDestObj->getArticleID()
292 if ( $haveRevisions ) {
296 'default' => $this->
msg(
'mergehistory-merge', $this->mTargetObj->getPrefixedText(),
297 $this->mDestObj->getPrefixedText() )->parse(),
299 'cssclass' =>
'mw-mergehistory-explanation',
300 'section' =>
'mergehistory-submit'
304 'name' =>
'wpComment',
305 'label-message' =>
'mergehistory-reason',
308 'section' =>
'mergehistory-submit'
312 'default' => $this->
msg(
'mergehistory-submit' ),
313 'section' =>
'mergehistory-submit',
314 'id' =>
'mw-merge-submit',
319 $form = HTMLForm::factory(
'ooui', $fields, $this->
getContext() );
320 $form->addHiddenField(
'wpEditToken', $form->getCsrfTokenSet()->getToken() )
322 ->setAction( $action )
323 ->suppressDefaultSubmit();
325 if ( $haveRevisions ) {
326 $form->setFooterHtml(
327 '<h2 id="mw-mergehistory">' . $this->
msg(
'mergehistory-list' )->escaped() .
'</h2>' .
328 $revisions->getNavigationBar() .
329 $revisions->getBody() .
330 $revisions->getNavigationBar()
333 $form->setFooterHtml( $this->
msg(
'mergehistory-empty' )->escaped() );
336 $form->prepareForm()->displayForm(
false );
338 # Show relevant lines from the merge log:
339 $mergeLogPage =
new LogPage(
'merge' );
340 $out->addHTML(
'<h2>' . $mergeLogPage->getName()->escaped() .
"</h2>\n" );
341 LogEventsList::showLogExtract( $out,
'merge', $this->mTargetObj );
356 private function merge() {
357 # Get the titles directly from the IDs, in case the target page params
358 # were spoofed. The queries are done based on the IDs, so it's best to
359 # keep it consistent...
360 $targetTitle = Title::newFromID( $this->mTargetID );
361 $destTitle = Title::newFromID( $this->mDestID );
362 if ( $targetTitle ===
null || $destTitle ===
null ) {
365 if ( $targetTitle->getArticleID() == $destTitle->getArticleID() ) {
370 $mh = $this->mergeHistoryFactory->newMergeHistory(
378 $mergeStatus = $mh->merge( $this->
getAuthority(), $this->mComment );
379 if ( !$mergeStatus->isOK() ) {
381 $this->
getOutput()->addWikiMsg( $mergeStatus->getMessage() );
387 $targetLink = $linkRenderer->makeLink(
391 [
'redirect' =>
'no' ]
395 $append = ( $mergeStatus->getValue() ===
'source-deleted' )
396 ? $this->
msg(
'mergehistory-source-deleted', $targetTitle->getPrefixedText() ) :
'';
398 $this->
getOutput()->addWikiMsg( $this->
msg(
'mergehistory-done' )
399 ->rawParams( $targetLink )
400 ->params( $destTitle->getPrefixedText(), $append )
401 ->numParams( $mh->getMergedRevisionCount() )