getRequest(); $par = (string)$par; // Yes, the use of getVal() and getText() is wanted, see bug T22365 $this->text = $request->getVal( 'wpTitle', $par ); $this->title = Title::newFromText( $this->text ); $this->reason = $request->getText( 'wpReason' ); // Checkboxes that default being checked are tricky $this->doSubpages = $request->getBool( 'subpages', !$request->wasPosted() ); $user = $this->getUser(); if ( $this->doBasicChecks() !== true ) { return; } $out = $this->getOutput(); // Real stuff starts here if ( TranslatablePage::isSourcePage( $this->title ) ) { $title = $this->msg( 'pt-deletepage-full-title', $this->title->getPrefixedText() ); $out->setPageTitle( $title ); $this->code = ''; $this->page = TranslatablePage::newFromTitle( $this->title ); } else { $page = TranslatablePage::isTranslationPage( $this->title ); if ( $page ) { $title = $this->msg( 'pt-deletepage-lang-title', $this->title->getPrefixedText() ); $out->setPageTitle( $title ); list( , $this->code ) = TranslateUtils::figureMessage( $this->title->getText() ); $this->page = $page; } else { throw new ErrorPageError( 'pt-deletepage-invalid-title', 'pt-deletepage-invalid-text' ); } } if ( !$user->isAllowed( 'pagetranslation' ) ) { throw new PermissionsError( 'pagetranslation' ); } // Is there really no better way to do this? $subactionText = $request->getText( 'subaction' ); switch ( $subactionText ) { case $this->msg( 'pt-deletepage-action-check' )->text(): $subaction = 'check'; break; case $this->msg( 'pt-deletepage-action-perform' )->text(): $subaction = 'perform'; break; case $this->msg( 'pt-deletepage-action-other' )->text(): $subaction = ''; break; default: $subaction = ''; } if ( $subaction === 'check' && $this->checkToken() && $request->wasPosted() ) { $this->showConfirmation(); } elseif ( $subaction === 'perform' && $this->checkToken() && $request->wasPosted() ) { $this->performAction(); } else { $this->showForm(); } } /** * Do the basic checks whether moving is possible and whether * the input looks anywhere near sane. * @throws PermissionsError|ErrorPageError|ReadOnlyError * @return bool */ protected function doBasicChecks() { # Check rights if ( !$this->userCanExecute( $this->getUser() ) ) { $this->displayRestrictionError(); } if ( $this->title === null ) { throw new ErrorPageError( 'notargettitle', 'notargettext' ); } if ( !$this->title->exists() ) { throw new ErrorPageError( 'nopagetitle', 'nopagetext' ); } $permissionErrors = $this->title->getUserPermissionsErrors( 'delete', $this->getUser() ); if ( count( $permissionErrors ) ) { throw new PermissionsError( 'delete', $permissionErrors ); } # Check for database lock if ( wfReadOnly() ) { throw new ReadOnlyError; } // Let the caller know it's safe to continue return true; } /** * Checks token. Use before real actions happen. Have to use wpEditToken * for compatibility for SpecialMovepage.php. * @return bool */ protected function checkToken() { return $this->getUser()->matchEditToken( $this->getRequest()->getVal( 'wpEditToken' ) ); } /** * The query form. */ protected function showForm() { $this->getOutput()->addWikiMsg( 'pt-deletepage-intro' ); $formDescriptor = [ 'wpTitle' => [ 'type' => 'text', 'name' => 'wpTitle', 'label' => $this->msg( 'pt-deletepage-current' )->text(), 'size' => 30, 'default' => $this->text, ], 'wpReason' => [ 'type' => 'text', 'name' => 'wpReason', 'label' => $this->msg( 'pt-deletepage-reason' )->text(), 'size' => 60, 'default' => $this->reason, ] ]; $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ); $htmlForm ->addHiddenField( 'wpEditToken', $this->getUser()->getEditToken() ) ->setMethod( 'post' ) ->setAction( $this->getPageTitle( $this->text )->getLocalURL() ) ->setSubmitName( 'subaction' ) ->setSubmitTextMsg( 'pt-deletepage-action-check' ) ->setWrapperLegendMsg( 'pt-deletepage-any-legend' ) ->prepareForm() ->displayForm( false ); } /** * The second form, which still allows changing some things. * Lists all the action which would take place. */ protected function showConfirmation() { $out = $this->getOutput(); $count = 0; $out->addWikiMsg( 'pt-deletepage-intro' ); $out->wrapWikiMsg( '== $1 ==', 'pt-deletepage-list-pages' ); if ( !$this->singleLanguage() ) { $count++; TranslateUtils::addWikiTextAsInterface( $out, $this->getChangeLine( $this->title ) ); } $out->wrapWikiMsg( '=== $1 ===', 'pt-deletepage-list-translation' ); $translationPages = $this->getTranslationPages(); $lines = []; foreach ( $translationPages as $old ) { $count++; $lines[] = $this->getChangeLine( $old ); } TranslateUtils::addWikiTextAsInterface( $out, implode( "\n", $lines ) ); $out->wrapWikiMsg( '=== $1 ===', 'pt-deletepage-list-section' ); $sectionPages = $this->getSectionPages(); $lines = []; foreach ( $sectionPages as $old ) { $count++; $lines[] = $this->getChangeLine( $old ); } TranslateUtils::addWikiTextAsInterface( $out, implode( "\n", $lines ) ); $out->wrapWikiMsg( '=== $1 ===', 'pt-deletepage-list-other' ); $subpages = $this->getSubpages(); $lines = []; foreach ( $subpages as $old ) { if ( TranslatablePage::isTranslationPage( $old ) ) { continue; } if ( $this->doSubpages ) { $count++; } $lines[] = $this->getChangeLine( $old, $this->doSubpages ); } TranslateUtils::addWikiTextAsInterface( $out, implode( "\n", $lines ) ); TranslateUtils::addWikiTextAsInterface( $out, "----\n" ); $out->addWikiMsg( 'pt-deletepage-list-count', $this->getLanguage()->formatNum( $count ) ); $formDescriptor = [ 'wpTitle' => [ 'type' => 'text', 'name' => 'wpTitle', 'label' => $this->msg( 'pt-deletepage-current' )->text(), 'size' => 30, 'default' => $this->text, 'readonly' => true, ], 'wpReason' => [ 'type' => 'text', 'name' => 'wpReason', 'label' => $this->msg( 'pt-deletepage-reason' )->text(), 'size' => 60, 'default' => $this->reason, ], 'subpages' => [ 'type' => 'check', 'name' => 'subpages', 'id' => 'mw-subpages', 'label' => $this->msg( 'pt-deletepage-subpages' )->text(), 'default' => $this->doSubpages, ] ]; $htmlForm = HTMLForm::factory( 'ooui', $formDescriptor, $this->getContext() ); if ( $this->singleLanguage() ) { $htmlForm->setWrapperLegendMsg( 'pt-deletepage-lang-legend' ); } else { $htmlForm->setWrapperLegendMsg( 'pt-deletepage-full-legend' ); } $htmlForm ->addHiddenField( 'wpEditToken', $this->getUser()->getEditToken() ) ->setMethod( 'post' ) ->setAction( $this->getPageTitle( $this->text )->getLocalURL() ) ->setSubmitTextMsg( 'pt-deletepage-action-perform' ) ->setSubmitName( 'subaction' ) ->addButton( [ 'name' => 'subaction', 'value' => $this->msg( 'pt-deletepage-action-other' )->text(), ] ) ->prepareForm() ->displayForm( false ); } /** * @param Title $title * @param bool $enabled * @return string One line of wikitext, without trailing newline. */ protected function getChangeLine( $title, $enabled = true ) { if ( $enabled ) { return '* ' . $title->getPrefixedText(); } else { return '* ' . $title->getPrefixedText() . ''; } } protected function performAction() { $jobs = []; $target = $this->title; $base = $this->title->getPrefixedText(); $translationPages = $this->getTranslationPages(); $user = $this->getUser(); foreach ( $translationPages as $old ) { $jobs[$old->getPrefixedText()] = TranslateDeleteJob::newJob( $old, $base, !$this->singleLanguage(), $user, $this->reason ); } $sectionPages = $this->getSectionPages(); foreach ( $sectionPages as $old ) { $jobs[$old->getPrefixedText()] = TranslateDeleteJob::newJob( $old, $base, !$this->singleLanguage(), $user, $this->reason ); } if ( !$this->doSubpages ) { $subpages = $this->getSubpages(); foreach ( $subpages as $old ) { if ( TranslatablePage::isTranslationPage( $old ) ) { continue; } $jobs[$old->getPrefixedText()] = TranslateDeleteJob::newJob( $old, $base, !$this->singleLanguage(), $user, $this->reason ); } } JobQueueGroup::singleton()->push( $jobs ); $cache = wfGetCache( CACHE_DB ); $cache->set( wfMemcKey( 'pt-base', $target->getPrefixedText() ), array_keys( $jobs ), 60 * 60 * 6 ); if ( !$this->singleLanguage() ) { $this->page->unmarkTranslatablePage(); } $this->clearMetadata(); MessageGroups::singleton()->recache(); MessageIndexRebuildJob::newJob()->insertIntoJobQueue(); $this->getOutput()->addWikiMsg( 'pt-deletepage-started' ); } protected function clearMetadata() { // remove the entries from metadata table. $groupId = $this->page->getMessageGroupId(); TranslateMetadata::set( $groupId, 'prioritylangs', false ); TranslateMetadata::set( $groupId, 'priorityforce', false ); TranslateMetadata::set( $groupId, 'priorityreason', false ); // remove the page from aggregate groups, if present in any of them. $aggregateGroups = MessageGroups::getGroupsByType( AggregateMessageGroup::class ); TranslateMetadata::preloadGroups( array_keys( $aggregateGroups ) ); foreach ( $aggregateGroups as $group ) { $subgroups = TranslateMetadata::get( $group->getId(), 'subgroups' ); if ( $subgroups !== false ) { $subgroups = explode( ',', $subgroups ); $subgroups = array_flip( $subgroups ); if ( isset( $subgroups[$groupId] ) ) { unset( $subgroups[$groupId] ); $subgroups = array_flip( $subgroups ); TranslateMetadata::set( $group->getId(), 'subgroups', implode( ',', $subgroups ) ); } } } } /** * Returns all section pages, including those which are currently not active. * @return Array of titles. */ protected function getSectionPages() { $code = $this->singleLanguage() ? $this->code : false; return $this->page->getTranslationUnitPages( 'all', $code ); } /** * Returns only translation subpages. * @return Array of titles. */ protected function getTranslationPages() { if ( $this->singleLanguage() ) { return [ $this->title ]; } if ( !isset( $this->translationPages ) ) { $this->translationPages = $this->page->getTranslationPages(); } return $this->translationPages; } /** * Returns all subpages, if the namespace has them enabled. * @return array|TitleArray Empty array or TitleArray. */ protected function getSubpages() { return $this->title->getSubpages(); } /** * @return bool */ protected function singleLanguage() { return $this->code !== ''; } }