public function execute($par)
 {
     $request = $this->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('reason');
     // 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();
     }
 }
	function run() {
		global $wgUser;

		// Initialization
		$title = $this->title;
		// Other stuff
		$user    = $this->getUser();
		$summary = $this->getSummary();
		$base    = $this->getBase();

		PageTranslationHooks::$allowTargetEdit = true;
		$oldUser = $wgUser;
		$wgUser = $user;

		$error = '';
		$article = new Article( $title, 0 );
		$ok = $article->doDeleteArticle( $summary, false, 0, true, $error );
		if ( !$ok ) {
			$logger = new LogPage( 'pagetranslation' );
			$params = array(
				'user' => $this->getPerformer(),
				'target' => $base,
				'error' => base64_encode( serialize( $ok ) ), // This is getting ridiculous
			);
			$doer = User::newFromName( $this->getPerformer() );
			$msg = $this->getFull() ? 'deletefnok' : 'deletelnok';
			$logger->addEntry( $msg, $title, null, array( serialize( $params ) ), $doer );
		}

		PageTranslationHooks::$allowTargetEdit = false;

		$cache = wfGetCache( CACHE_DB );
		$pages = (array) $cache->get( wfMemcKey( 'pt-base', $base ) );
		$lastitem = array_pop( $pages );
		if ( $title->getPrefixedText() === $lastitem ) {
			$cache->delete( wfMemcKey( 'pt-base', $base ) );
			$logger = new LogPage( 'pagetranslation' );
			$params = array( 'user' => $this->getPerformer() );
			$doer = User::newFromName( $this->getPerformer() );
			$msg = $this->getFull() ? 'deletefok' : 'deletelok';
			$logger->addEntry( $msg, Title::newFromText( $base ), null, array( serialize( $params ) ), $doer );

			$tpage = TranslatablePage::newFromTitle( $title );
			$tpage->getTranslationPercentages( true );
			foreach ( $tpage->getTranslationPages() as $page ) {
				$page->invalidateCache();
			}
			$title->invalidateCache();
		}

		$wgUser = $oldUser;

		return true;
	}
 public function execute()
 {
     $groups = MessageGroups::singleton()->getGroups();
     /** @var MessageGroup $group */
     foreach ($groups as $group) {
         if (!$group instanceof WikiPageMessageGroup) {
             continue;
         }
         // Get all translation subpages and refresh each one of them
         $page = TranslatablePage::newFromTitle($group->getTitle());
         $translationPages = $page->getTranslationPages();
         foreach ($translationPages as $subpage) {
             $job = TranslateRenderJob::newJob($subpage);
             $job->run();
         }
     }
 }
 function run()
 {
     // Initialization
     $title = $this->title;
     // Other stuff
     $user = $this->getUser();
     $summary = $this->getSummary();
     $base = $this->getBase();
     $doer = User::newFromName($this->getPerformer());
     PageTranslationHooks::$allowTargetEdit = true;
     $error = '';
     $wikipage = new WikiPage($title);
     $ok = $wikipage->doDeleteArticle($summary, false, 0, true, $error, $user);
     if (!$ok) {
         $params = array('target' => $base, 'error' => $ok);
         $type = $this->getFull() ? 'deletefnok' : 'deletelnok';
         $entry = new ManualLogEntry('pagetranslation', $type);
         $entry->setPerformer($doer);
         $entry->setTarget($title);
         $entry->setParameters($params);
         $logid = $entry->insert();
         $entry->publish($logid);
     }
     PageTranslationHooks::$allowTargetEdit = false;
     $cache = wfGetCache(CACHE_DB);
     $pages = (array) $cache->get(wfMemcKey('pt-base', $base));
     $lastitem = array_pop($pages);
     if ($title->getPrefixedText() === $lastitem) {
         $cache->delete(wfMemcKey('pt-base', $base));
         $type = $this->getFull() ? 'deletefok' : 'deletelok';
         $entry = new ManualLogEntry('pagetranslation', $type);
         $entry->setPerformer($doer);
         $entry->setTarget(Title::newFromText($base));
         $logid = $entry->insert();
         $entry->publish($logid);
         $tpage = TranslatablePage::newFromTitle($title);
         $tpage->getTranslationPercentages(true);
         foreach ($tpage->getTranslationPages() as $page) {
             $page->invalidateCache();
         }
         $title->invalidateCache();
     }
     return true;
 }
 public function testTranslatablePageWithMarked()
 {
     $title = Title::newFromText('Fréttinga');
     $this->assertNotNull($title, 'Title is valid');
     $page = WikiPage::factory($title);
     $this->assertNotNull($page, 'WikiPage is valid');
     $translatablePage = TranslatablePage::newFromTitle($title);
     $content = ContentHandler::makeContent('<translate>koira</translate>', $title);
     $status = $page->doEditContent($content, 'Test case');
     $latest = $status->value['revision']->getId();
     $translatablePage->addMarkedTag($latest, array('foo'));
     $this->assertSame($latest, $translatablePage->getReadyTag(), 'Ready tag was added');
     $this->assertSame($latest, $translatablePage->getMarkedTag(), 'Marked tag was added');
     global $wgUser;
     $cascade = false;
     $page->doUpdateRestrictions(array('edit' => 'sysop'), array(), $cascade, 'Test case', $wgUser);
     $newLatest = $latest + 1;
     $this->assertSame($newLatest, $translatablePage->getReadyTag(), 'Ready tag was updated after protection');
     $this->assertSame($latest, $translatablePage->getMarkedTag(), 'Marked tag was not updated after protection');
 }
 protected function getTranslationPageDiff()
 {
     global $wgEnablePageTranslation;
     if (!$wgEnablePageTranslation) {
         return null;
     }
     $this->mustBeKnownMessage();
     if (!$this->group instanceof WikiPageMessageGroup) {
         return null;
     }
     // Shortcuts
     $code = $this->handle->getCode();
     $key = $this->handle->getKey();
     // TODO: encapsulate somewhere
     $page = TranslatablePage::newFromTitle($this->group->getTitle());
     $rev = $page->getTransRev("{$key}/{$code}");
     $latest = $page->getMarkedTag();
     if ($rev === $latest) {
         return null;
     }
     $oldpage = TranslatablePage::newFromRevision($this->group->getTitle(), $rev);
     $oldtext = $newtext = null;
     foreach ($oldpage->getParse()->getSectionsForSave() as $section) {
         if ($this->group->getTitle()->getPrefixedDBKey() . '/' . $section->id === $key) {
             $oldtext = $section->getTextForTrans();
         }
     }
     foreach ($page->getParse()->getSectionsForSave() as $section) {
         if ($this->group->getTitle()->getPrefixedDBKey() . '/' . $section->id === $key) {
             $newtext = $section->getTextForTrans();
         }
     }
     if ($oldtext === $newtext) {
         return null;
     }
     $diff = new DifferenceEngine();
     if (method_exists('DifferenceEngine', 'setTextLanguage')) {
         $diff->setTextLanguage($this->group->getSourceLanguage());
     }
     $diff->setText($oldtext, $newtext);
     $diff->setReducedLineNumbers();
     $diff->showDiffStyle();
     return $diff->getDiff(wfMsgHtml('tpt-diff-old'), wfMsgHtml('tpt-diff-new'));
 }
	protected function performAction() {
		$jobs = array();

		$target = $this->newTitle;
		$base = $this->oldTitle->getPrefixedText();
		$oldLatest = $this->oldTitle->getLatestRevId();

		$params = array(
			'base-source' => $this->oldTitle->getPrefixedText(),
			'base-target' => $this->newTitle->getPrefixedText(),
		);

		$translationPages = $this->getTranslationPages();
		foreach ( $translationPages as $old ) {
			$to = $this->newPageTitle( $base, $old, $target );
			$jobs[$old->getPrefixedText()] = MoveJob::newJob( $old, $to, $params, $this->user );
		}

		$sectionPages = $this->getSectionPages();
		foreach ( $sectionPages as $old ) {
			$to = $this->newPageTitle( $base, $old, $target );
			$jobs[$old->getPrefixedText()] = MoveJob::newJob( $old, $to, $params, $this->user );
		}

		if ( $this->moveSubpages ) {
			$subpages = $this->getSubpages();
			foreach ( $subpages as $old ) {
				if ( TranslatablePage::isTranslationPage( $old ) ) {
					continue;
				}

				$to = $this->newPageTitle( $base, $old, $target );
				$jobs[$old->getPrefixedText()] = MoveJob::newJob( $old, $to, $params, $this->user );
			}
		}

		// This is used by MoveJob
		wfGetCache( CACHE_ANYTHING )->set( wfMemcKey( 'translate-pt-move', $base ), count( $jobs ) );
		Job::batchInsert( $jobs );

		MoveJob::forceRedirects( false );

		$errors = $this->oldTitle->moveTo( $this->newTitle, true, $this->reason, false );
		if ( is_array( $errors ) ) {
			$this->showErrors( $errors );
		}

		MoveJob::forceRedirects( true );

		$newTpage = TranslatablePage::newFromTitle( $this->newTitle );
		$newTpage->addReadyTag( $this->newTitle->getLatestRevId( GAID_FOR_UPDATE ) );

		if ( $newTpage->getMarkedTag() === $oldLatest ) {
			$newTpage->addMarkedTag( $this->newTitle->getLatestRevId( GAID_FOR_UPDATE ) );
		}

		MessageGroups::clearCache();
		MessageIndexRebuildJob::newJob()->insert();

		global $wgOut;
		$wgOut->addWikiMsg( 'pt-movepage-started' );
	}
 /**
  * Hook to update source and destination translation pages on moving translation units
  * Hook: TitleMoveComplete
  * @since 2014.08
  */
 public static function onMoveTranslationUnits(Title &$ot, Title &$nt, User &$user, $oldid, $newid, $reason)
 {
     // Do the update only once. In case running by job queue, the update is not done here
     if (self::$jobQueueRunning) {
         return;
     }
     $groupLast = null;
     foreach (array($ot, $nt) as $title) {
         $handle = new MessageHandle($title);
         if (!$handle->isValid()) {
             continue;
         }
         // Documentation pages are never translation pages
         if ($handle->isDoc()) {
             continue;
         }
         $group = $handle->getGroup();
         if (!$group instanceof WikiPageMessageGroup) {
             continue;
         }
         $language = $handle->getCode();
         // Ignore pages such as Translations:Page/unit without language code
         if (strval($code) === '') {
             continue;
         }
         // Update the page only once if source and destination units
         // belong to the same page
         if ($group !== $groupLast) {
             $groupLast = $group;
             $page = TranslatablePage::newFromTitle($group->getTitle());
             self::updateTranslationPage($page, $language, $user, 0, $reason);
         }
     }
 }
 /**
  * @param Title $title
  * @return bool|TranslatablePage
  */
 public static function isTranslationPage(Title $title)
 {
     $handle = new MessageHandle($title);
     $key = $handle->getKey();
     $code = $handle->getCode();
     if ($key === '' || $code === '') {
         return false;
     }
     $codes = Language::fetchLanguageNames();
     global $wgTranslateDocumentationLanguageCode;
     unset($codes[$wgTranslateDocumentationLanguageCode]);
     if (!isset($codes[$code])) {
         return false;
     }
     $newtitle = self::changeTitleText($title, $key);
     if (!$newtitle) {
         return false;
     }
     $page = TranslatablePage::newFromTitle($newtitle);
     if ($page->getMarkedTag() === false) {
         return false;
     }
     return $page;
 }
Beispiel #10
0
 /**
  * @param $title Title
  * @return bool|TranslatablePage
  */
 public static function isTranslationPage(Title $title)
 {
     list($key, $code) = TranslateUtils::figureMessage($title->getText());
     if ($key === '' || $code === '') {
         return false;
     }
     $codes = Language::getLanguageNames(false);
     global $wgTranslateDocumentationLanguageCode;
     unset($codes[$wgTranslateDocumentationLanguageCode]);
     if (!isset($codes[$code])) {
         return false;
     }
     $newtitle = self::changeTitleText($title, $key);
     if (!$newtitle) {
         return false;
     }
     $page = TranslatablePage::newFromTitle($newtitle);
     if ($page->getMarkedTag() === false) {
         return false;
     }
     return $page;
 }
 protected static function sourcePageHeader(Title $title)
 {
     global $wgUser, $wgLang;
     $page = TranslatablePage::newFromTitle($title);
     $marked = $page->getMarkedTag();
     $ready = $page->getReadyTag();
     $title = $page->getTitle();
     $linker = class_exists('DummyLinker') ? new DummyLinker() : new Linker();
     $latest = $title->getLatestRevId();
     $canmark = $ready === $latest && $marked !== $latest;
     $actions = array();
     if ($marked && $wgUser->isAllowed('translate')) {
         $par = array('group' => $page->getMessageGroupId(), 'language' => $wgLang->getCode(), 'task' => 'view');
         $translate = SpecialPage::getTitleFor('Translate');
         $linkDesc = wfMsgHtml('translate-tag-translate-link-desc');
         $actions[] = $linker->link($translate, $linkDesc, array(), $par);
     }
     if ($canmark) {
         $diffUrl = $title->getFullUrl(array('oldid' => $marked, 'diff' => $latest));
         $par = array('target' => $title->getPrefixedText());
         $translate = SpecialPage::getTitleFor('PageTranslation');
         if ($wgUser->isAllowed('pagetranslation')) {
             // This page has never been marked
             if ($marked === false) {
                 $linkDesc = wfMsgHtml('translate-tag-markthis');
                 $actions[] = $linker->link($translate, $linkDesc, array(), $par);
             } else {
                 $markUrl = $translate->getFullUrl($par);
                 $actions[] = wfMsgExt('translate-tag-markthisagain', 'parseinline', $diffUrl, $markUrl);
             }
         } else {
             $actions[] = wfMsgExt('translate-tag-hasnew', 'parseinline', $diffUrl);
         }
     }
     if (!count($actions)) {
         return;
     }
     $legend = Html::rawElement('div', array('class' => 'mw-pt-translate-header'), $wgLang->semicolonList($actions)) . Html::element('hr');
     global $wgOut;
     $wgOut->addHTML($legend);
 }
 public function execute($parameters)
 {
     $this->setHeaders();
     $user = $this->getUser();
     $request = $this->getRequest();
     $target = $request->getText('target', $parameters);
     $revision = $request->getInt('revision', 0);
     $action = $request->getVal('do');
     $out = $this->getOutput();
     TranslateUtils::addSpecialHelpLink($out, 'Help:Extension:Translate/Page_translation_example');
     // No specific page or invalid input
     $title = Title::newFromText($target);
     if (!$title) {
         if ($target !== '') {
             $out->addWikiMsg('tpt-badtitle');
         } else {
             $this->listPages();
         }
         return;
     }
     // Check permissions
     if (!$user->isAllowed('pagetranslation')) {
         throw new PermissionsError('pagetranslation');
     }
     // Check permissions
     if ($request->wasPosted() && !$user->matchEditToken($request->getText('token'))) {
         throw new PermissionsError('pagetranslation');
     }
     // We are processing some specific page
     if (!$title->exists()) {
         $out->addWikiMsg('tpt-nosuchpage', $title->getPrefixedText());
         return;
     }
     if ($action === 'discourage' || $action === 'encourage') {
         $id = TranslatablePage::getMessageGroupIdFromTitle($title);
         $current = MessageGroups::getPriority($id);
         if ($action === 'encourage') {
             $new = '';
         } else {
             $new = 'discouraged';
         }
         if ($new !== $current) {
             MessageGroups::setPriority($id, $new);
             $entry = new ManualLogEntry('pagetranslation', $action);
             $entry->setPerformer($user);
             $entry->setTarget($title);
             $logid = $entry->insert();
             $entry->publish($logid);
         }
         $this->listPages();
         $group = MessageGroups::getGroup($id);
         $parents = MessageGroups::getSharedGroups($group);
         MessageGroupStats::clearGroup($parents);
         return;
     }
     if ($action === 'unlink') {
         if (!$request->wasPosted()) {
             $this->showUnlinkConfirmation($title);
             return;
         } else {
             $page = TranslatablePage::newFromTitle($title);
             $content = ContentHandler::makeContent(self::getStrippedSourcePageText($page->getParse()), $title);
             $status = WikiPage::factory($title)->doEditContent($content, $this->msg('tpt-unlink-summary')->inContentLanguage()->text(), EDIT_FORCE_BOT | EDIT_UPDATE);
             if (!$status->isOK()) {
                 $out->wrapWikiMsg('<div class="errorbox">$1</div>', array('tpt-edit-failed', $status->getWikiText()));
                 return;
             }
             $page = TranslatablePage::newFromTitle($title);
             $this->unmarkPage($page, $user);
             $out->wrapWikiMsg('<div class="successbox">$1</div>', array('tpt-unmarked', $title->getPrefixedText()));
             $this->listPages();
             return;
         }
     }
     if ($action === 'unmark') {
         $page = TranslatablePage::newFromTitle($title);
         $this->unmarkPage($page, $user);
         $out->wrapWikiMsg('<div class="successbox">$1</div>', array('tpt-unmarked', $title->getPrefixedText()));
         $this->listPages();
         return;
     }
     if ($revision === 0) {
         // Get the latest revision
         $revision = intval($title->getLatestRevID());
     }
     $page = TranslatablePage::newFromRevision($title, $revision);
     if (!$page instanceof TranslatablePage) {
         $out->wrapWikiMsg('<div class="errorbox">$1</div>', array('tpt-notsuitable', $title->getPrefixedText(), $revision));
         return;
     }
     if ($revision !== intval($title->getLatestRevID())) {
         // We do want to notify the reviewer if the underlying page changes during review
         $target = $title->getFullUrl(array('oldid' => $revision));
         $link = "<span class='plainlinks'>[{$target} {$revision}]</span>";
         $out->wrapWikiMsg('<div class="warningbox">$1</div>', array('tpt-oldrevision', $title->getPrefixedText(), $link));
         $this->listPages();
         return;
     }
     $lastrev = $page->getMarkedTag();
     if ($lastrev !== false && $lastrev === $revision) {
         $out->wrapWikiMsg('<div class="warningbox">$1</div>', array('tpt-already-marked'));
         $this->listPages();
         return;
     }
     // This will modify the sections to include name property
     $error = false;
     $sections = $this->checkInput($page, $error);
     // Non-fatal error which prevents saving
     if ($error === false && $request->wasPosted()) {
         // Check if user wants to translate title
         // If not, remove it from the list of sections
         if (!$request->getCheck('translatetitle')) {
             $sections = array_filter($sections, function ($s) {
                 return $s->id !== 'Page display title';
             });
         }
         $err = $this->markForTranslation($page, $sections);
         if ($err) {
             call_user_func_array(array($out, 'addWikiMsg'), $err);
         } else {
             $this->showSuccess($page);
             $this->listPages();
         }
         return;
     }
     $this->showPage($page, $sections);
 }
 protected function performAction()
 {
     $jobs = array();
     $user = $this->getUser();
     $target = $this->newTitle;
     $base = $this->oldTitle->getPrefixedText();
     $oldLatest = $this->oldTitle->getLatestRevId();
     $params = array('base-source' => $this->oldTitle->getPrefixedText(), 'base-target' => $this->newTitle->getPrefixedText());
     $translationPages = $this->getTranslationPages();
     foreach ($translationPages as $old) {
         $to = $this->newPageTitle($base, $old, $target);
         $jobs[$old->getPrefixedText()] = TranslateMoveJob::newJob($old, $to, $params, $user);
     }
     $sectionPages = $this->getSectionPages();
     foreach ($sectionPages as $old) {
         $to = $this->newPageTitle($base, $old, $target);
         $jobs[$old->getPrefixedText()] = TranslateMoveJob::newJob($old, $to, $params, $user);
     }
     if ($this->moveSubpages) {
         $subpages = $this->getSubpages();
         foreach ($subpages as $old) {
             if (TranslatablePage::isTranslationPage($old)) {
                 continue;
             }
             $to = $this->newPageTitle($base, $old, $target);
             $jobs[$old->getPrefixedText()] = TranslateMoveJob::newJob($old, $to, $params, $user);
         }
     }
     // This is used by TranslateMoveJob
     wfGetCache(CACHE_ANYTHING)->set(wfMemcKey('translate-pt-move', $base), count($jobs));
     JobQueueGroup::singleton()->push($jobs);
     TranslateMoveJob::forceRedirects(false);
     $errors = $this->oldTitle->moveTo($this->newTitle, true, $this->reason, false);
     if (is_array($errors)) {
         $this->showErrors($errors);
     }
     TranslateMoveJob::forceRedirects(true);
     $newTpage = TranslatablePage::newFromTitle($this->newTitle);
     $newTpage->addReadyTag($this->newTitle->getLatestRevId(Title::GAID_FOR_UPDATE));
     if ($newTpage->getMarkedTag() === $oldLatest) {
         $newTpage->addMarkedTag($this->newTitle->getLatestRevId(Title::GAID_FOR_UPDATE));
     }
     // remove the entries from metadata table.
     $oldGroupId = $this->page->getMessageGroupId();
     $newGroupId = $newTpage->getMessageGroupId();
     $this->moveMetadata($oldGroupId, $newGroupId);
     MessageGroups::singleton()->recache();
     MessageIndexRebuildJob::newJob()->insert();
     $this->getOutput()->addWikiMsg('pt-movepage-started');
 }
	protected function checkTransrevRevision( $revId ) {
		static $cache = array();

		if ( isset( $cache[$revId] ) ) {
			return $cache[$revId];
		}

		$revision = Revision::newFromId( $revId );
		if ( !$revision ) {
			$cache[$revId] = 'no such revision';
		} else {
			$title = $revision->getTitle();
			if ( !$title ) {
				$cache[$revId] = 'no title for the revision';
			} else {
				$page = TranslatablePage::newFromTitle( $title );
				if ( $page->getMarkedTag() === false ) {
					$cache[$revId] = 'revision belongs to a page that is not marked for translation';
				} else {
					$cache[$revId] = true;
				}
			}
		}

		return $cache[$revId];
	}
	public function execute( $parameters ) {
		$this->setHeaders();

		global $wgRequest, $wgOut, $wgUser;
		$this->user = $wgUser;
		$request = $wgRequest;

		$target = $wgRequest->getText( 'target', $parameters );
		$revision = $wgRequest->getInt( 'revision', 0 );
		$action = $request->getVal( 'do' );

		// No specific page or invalid input
		$title = Title::newFromText( $target );
		if ( !$title ) {
			if ( $target !== '' ) {
				$wgOut->addWikiMsg( 'tpt-badtitle' );
			} else {
				$this->listPages();
			}

			return;
		}

		// Check permissions
		if ( !$this->user->isAllowed( 'pagetranslation' ) ) {
			$wgOut->permissionRequired( 'pagetranslation' );
			return;
		}

		// Check permissions
		if ( $wgRequest->wasPosted() && !$this->user->matchEditToken( $wgRequest->getText( 'token' ) ) ) {
			self::superDebug( __METHOD__, "token failure", $this->user );
			$wgOut->permissionRequired( 'pagetranslation' );
			return;
		}

		// We are processing some specific page
		if ( !$title->exists() ) {
			$wgOut->addWikiMsg( 'tpt-nosuchpage', $title->getPrefixedText() );
			return;
		}

		if ( $action === 'discourage' || $action === 'encourage' ) {
			$id = TranslatablePage::getMessageGroupIdFromTitle( $title );
			$dbw = wfGetDB( DB_MASTER );
			$table = 'translate_groupreviews';
			$row = array(
				'tgr_group' => $id,
				'tgr_lang' => '*priority',
				'tgr_state' => 'discouraged',
			);
			if ( $action === 'encourage' ) {
				$dbw->delete( $table, $row, __METHOD__ );
			} else {
				$index = array( 'tgr_group', 'tgr_lang' );
				$dbw->replace( $table, array( $index ), $row, __METHOD__ );
			}
			$this->listPages();

			$group = MessageGroups::getGroup( $id );
			$parents = MessageGroups::getParentGroups( $group );
			MessageGroupStats::clearGroup( $parents );

			return;
		}

		if ( $action === 'unmark' ) {
			$page = TranslatablePage::newFromTitle( $title );
			$page->removeTags();
			$page->getTitle()->invalidateCache();

			$logger = new LogPage( 'pagetranslation' );
			$params = array( 'user' => $wgUser->getName() );
			$logger->addEntry( 'unmark', $page->getTitle(), null, array( serialize( $params ) ) );
			$wgOut->addWikiMsg( 'tpt-unmarked', $title->getPrefixedText() );
			self::superDebug( __METHOD__, "unmarked page", $this->user, $title );
			return;
		}

		if ( $revision === 0 ) {
			// Get the latest revision
			$revision = intval( $title->getLatestRevID() );
		}

		$page = TranslatablePage::newFromRevision( $title, $revision );
		if ( !$page instanceof TranslatablePage ) {
			$wgOut->addWikiMsg( 'tpt-notsuitable', $title->getPrefixedText(), $revision );

			return;
		}

		if ( $revision !== intval( $title->getLatestRevID() ) ) {
			// We do want to notify the reviewer if the underlying page changes during review
			$target = $title->getFullUrl( array( 'oldid' => $revision ) );
			$link = "<span class='plainlinks'>[$target $revision]</span>";
			$wgOut->addWikiMsg( 'tpt-oldrevision', $title->getPrefixedText(), $link );
			self::superDebug( __METHOD__, "revision mismatch while marking", $this->user, $title, $revision, intval( $title->getLatestRevID() ) );
			return;
		}

		$lastrev = $page->getMarkedTag();
		if ( $lastrev !== false && $lastrev === $revision ) {
			$wgOut->addWikiMsg( 'tpt-already-marked' );
			$this->listPages();

			return;
		}

		// This will modify the sections to include name property
		$error = false;
		$sections = $this->checkInput( $page, $error );

		// Non-fatal error which prevents saving
		if ( $error === false && $wgRequest->wasPosted() ) {
			$err = $this->markForTranslation( $page, $sections );
			if ( $err ) {
				call_user_func_array( array( $wgOut, 'addWikiMsg' ), $err );
			} else {
				$this->showSuccess( $page );
				$this->listPages();
			}

			return;
		}

		self::superDebug( __METHOD__, "marking page", $this->user, $title, $revision );
		$this->showPage( $page, $sections );
	}