/** * Page moving and page protection (and possibly other things) creates null * revisions. These revisions re-use the previous text already stored in * the database. Those however do not trigger re-parsing of the page and * thus the ready tag is not updated. This watches for new revisions, * checks if they reuse existing text, checks whether the parent version * is the latest version and has a ready tag. If that is the case, * also adds a ready tag for the new revision (which is safe, because * the text hasn't changed). The interface will say that there has been * a change, but shows no change in the content. This lets the user to * update the translation pages in the case, the non-text changes affect * the rendering of translation pages. I'm not aware of any such cases * at the moment. * Hook: RevisionInsertComplete * @since 2012-05-08 */ public static function updateTranstagOnNullRevisions(Revision $rev, $text, $flags) { $title = $rev->getTitle(); $newRevId = $rev->getId(); $oldRevId = $rev->getParentId(); $newTextId = $rev->getTextId(); /* This hook doesn't provide any way to detech null revisions * without extra query */ $dbw = wfGetDB(DB_MASTER); $table = 'revision'; $field = 'rev_text_id'; $conds = array('rev_page' => $rev->getPage(), 'rev_id' => $oldRevId); // FIXME: optimize away this query. Bug T38588. $oldTextId = $dbw->selectField($table, $field, $conds, __METHOD__); if (strval($newTextId) !== strval($oldTextId)) { // Not a null revision, bail out. return true; } $page = TranslatablePage::newFromTitle($title); if ($page->getReadyTag() === $oldRevId) { $page->addReadyTag($newRevId); } return true; }
/** * Get the "are you sure you want to reject these changes?" form * @return array (html string, error string or true) */ public function getHtml() { global $wgLang, $wgContLang; $status = $this->form->checkTarget(); if ($status !== true) { return array('', $status); // not a reviewable existing page } $oldRev = $this->oldRev; // convenience $newRev = $this->newRev; // convenience # Do not mess with archived/deleted revisions if (!$oldRev || $newRev->isDeleted(Revision::DELETED_TEXT)) { return array('', 'review_bad_oldid'); } elseif (!$newRev || $newRev->isDeleted(Revision::DELETED_TEXT)) { return array('', 'review_bad_oldid'); } $form = '<div class="plainlinks">'; $dbr = wfGetDB(DB_SLAVE); $res = $dbr->select('revision', Revision::selectFields(), array('rev_page' => $oldRev->getPage(), 'rev_timestamp > ' . $dbr->addQuotes($dbr->timestamp($oldRev->getTimestamp())), 'rev_timestamp <= ' . $dbr->addQuotes($dbr->timestamp($newRev->getTimestamp()))), __METHOD__, array('ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 251)); if (!$dbr->numRows($res)) { return array('', 'review_bad_oldid'); } elseif ($dbr->numRows($res) > 250) { return array('', 'review_reject_excessive'); } $contribs = SpecialPage::getTitleFor('Contributions')->getPrefixedText(); $lastTextId = 0; $rejectIds = $rejectAuthors = array(); foreach ($res as $row) { $rev = new Revision($row); if ($rev->getTextId() != $lastTextId) { // skip null edits $rejectIds[] = $rev->getId(); $rejectAuthors[] = $rev->isDeleted(Revision::DELETED_USER) ? wfMsg('rev-deleted-user') : "[[{$contribs}/{$rev->getUserText()}|{$rev->getUserText()}]]"; } $lastTextId = $rev->getTextId(); } $rejectAuthors = array_values(array_unique($rejectAuthors)); if (!$rejectIds) { // all null edits? (this shouldn't happen) return array('', 'review_reject_nulledits'); } // List of revisions being undone... $form .= wfMsgExt('revreview-reject-text-list', 'parseinline', $wgLang->formatNum(count($rejectIds)), $oldRev->getTitle()->getPrefixedText()); $form .= '<ul>'; $list = new RevisionList(RequestContext::getMain(), $oldRev->getTitle()); $list->filterByIds($rejectIds); for ($list->reset(); $list->current(); $list->next()) { $item = $list->current(); if ($item->canView()) { $form .= $item->getHTML(); } } $form .= '</ul>'; if ($newRev->isCurrent()) { // Revision this will revert to (when reverting the top X revs)... $form .= wfMsgExt('revreview-reject-text-revto', 'parseinline', $oldRev->getTitle()->getPrefixedDBKey(), $oldRev->getId(), $wgLang->timeanddate($oldRev->getTimestamp(), true)); } $comment = $this->form->getComment(); // convenience // Determine the default edit summary... $oldRevAuthor = $oldRev->isDeleted(Revision::DELETED_USER) ? wfMsg('rev-deleted-user') : $oldRev->getUserText(); // NOTE: *-cur msg wording not safe for (unlikely) edit auto-merge $msg = $newRev->isCurrent() ? 'revreview-reject-summary-cur' : 'revreview-reject-summary-old'; $defaultSummary = wfMsgExt($msg, array('parsemag', 'content'), $wgContLang->formatNum(count($rejectIds)), $wgContLang->listToText($rejectAuthors), $oldRev->getId(), $oldRevAuthor); // If the message is too big, then fallback to the shorter one $colonSeparator = wfMsgForContent('colon-separator'); $maxLen = 255 - count($colonSeparator) - count($comment); if (strlen($defaultSummary) > $maxLen) { $msg = $newRev->isCurrent() ? 'revreview-reject-summary-cur-short' : 'revreview-reject-summary-old-short'; $defaultSummary = wfMsgExt($msg, array('parsemag', 'content'), $wgContLang->formatNum(count($rejectIds)), $oldRev->getId(), $oldRevAuthor); } // Append any review comment... if ($comment != '') { if ($defaultSummary != '') { $defaultSummary .= $colonSeparator; } $defaultSummary .= $comment; } $form .= '</div>'; $skin = $this->form->getUser()->getSkin(); $reviewTitle = SpecialPage::getTitleFor('RevisionReview'); $form .= Xml::openElement('form', array('method' => 'POST', 'action' => $reviewTitle->getFullUrl())); $form .= Html::hidden('action', 'reject'); $form .= Html::hidden('wpReject', 1); $form .= Html::hidden('wpRejectConfirm', 1); $form .= Html::hidden('oldid', $this->form->getOldId()); $form .= Html::hidden('refid', $this->form->getRefId()); $form .= Html::hidden('target', $oldRev->getTitle()->getPrefixedDBKey()); $form .= Html::hidden('wpEditToken', $this->form->getUser()->editToken()); $form .= Html::hidden('changetime', $newRev->getTimestamp()); $form .= Xml::inputLabel(wfMsg('revreview-reject-summary'), 'wpReason', 'wpReason', 120, $defaultSummary, array('maxlength' => 200)) . "<br />"; $form .= Html::input('wpSubmit', wfMsg('revreview-reject-confirm'), 'submit'); $form .= ' '; $form .= $skin->link($this->form->getPage(), wfMsg('revreview-reject-cancel'), array('onClick' => 'history.back(); return history.length <= 1;'), array('oldid' => $this->form->getRefId(), 'diff' => $this->form->getOldId())); $form .= Xml::closeElement('form'); return array($form, true); }