From: daniel Date: Mon, 23 Jul 2012 20:07:18 +0000 (+0200) Subject: merged master X-Git-Tag: 1.31.0-rc.0~22097^2^2~72 X-Git-Url: https://git.cyclocoop.org/%28%28?a=commitdiff_plain;h=d87135d706004373b2cfdc4c588ce6d80358631f;p=lhc%2Fweb%2Fwiklou.git merged master Change-Id: Iad12ee382d6aeb1fab6fefb611d290b74865ea4b --- d87135d706004373b2cfdc4c588ce6d80358631f diff --cc RELEASE-NOTES-1.20 index 46d85046c8,2f463a763a..fda37c3d12 --- a/RELEASE-NOTES-1.20 +++ b/RELEASE-NOTES-1.20 @@@ -74,8 -82,23 +82,25 @@@ upgrade PHP if you have not done so pri * Added new function getDomain to AuthPlugin for getting a user's domain * (bug 23427) New magic word {{PAGEID}} which gives the current page ID. Will be null on previewing a page being created. +* Added new hook AfterFinalPageOutput to allow modifications to buffered page output before sent + to the client. + * (bug 37627) UserNotLoggedIn() exception to show a generic error page whenever + a user is not logged in. + * Watched status in changes lists are no longer indicated by + tags with class "mw-watched". Instead, each line now has a class + "mw-changeslist-line-watched" or "mw-changeslist-line-not-watched", and the + title itself is surrounded by tags with class "mw-title". + * Added ContribsPager::reallyDoQuery hook allowing extensions to data to MyContribs + * Added new hook ParserAfterParse to allow extensions to affect parsed output + after the parse is complete but before block level processing, link holder + replacement, and so on. + * (bug 34678) Added InternalParseBeforeSanitize hook which gets called during Parser's + internalParse method just before the parser removes unwanted/dangerous HTML tags. + * (bug 36783) Implement jQuery Promise interface in mediawiki.api module. + * Make dates in sortable tables sort according to the page content language + instead of the site content language + * (bug 37926) Deleterevision will no longer allow users to delete log entries, + the new deletelogentry permission is required for this. === Bug fixes in 1.20 === * (bug 30245) Use the correct way to construct a log page title. diff --cc includes/DefaultSettings.php index 7ed1173198,3311fb1e74..3dcecaed2e --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@@ -655,30 -710,20 +710,30 @@@ $wgTrustedMediaFormats = array * Each entry in the array maps a MIME type to a class name */ $wgMediaHandlers = array( - 'image/jpeg' => 'JpegHandler', - 'image/png' => 'PNGHandler', - 'image/gif' => 'GIFHandler', - 'image/tiff' => 'TiffHandler', + 'image/jpeg' => 'JpegHandler', + 'image/png' => 'PNGHandler', + 'image/gif' => 'GIFHandler', + 'image/tiff' => 'TiffHandler', 'image/x-ms-bmp' => 'BmpHandler', - 'image/x-bmp' => 'BmpHandler', - 'image/x-xcf' => 'XCFHandler', - 'image/svg+xml' => 'SvgHandler', // official - 'image/svg' => 'SvgHandler', // compat + 'image/x-bmp' => 'BmpHandler', + 'image/x-xcf' => 'XCFHandler', + 'image/svg+xml' => 'SvgHandler', // official + 'image/svg' => 'SvgHandler', // compat 'image/vnd.djvu' => 'DjVuHandler', // official - 'image/x.djvu' => 'DjVuHandler', // compat - 'image/x-djvu' => 'DjVuHandler', // compat + 'image/x.djvu' => 'DjVuHandler', // compat + 'image/x-djvu' => 'DjVuHandler', // compat ); +/** + * Plugins for page content model handling. + * Each entry in the array maps a model id to a class name + */ +$wgContentHandlers = array( + CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler', // the usual case + CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler', // dumb version, no syntax highlighting + CONTENT_MODEL_CSS => 'CssContentHandler', // dumb version, no syntax highlighting +); + /** * Resizing can be done using PHP's internal image libraries or using * ImageMagick or another third-party converter, e.g. GraphicMagick. diff --cc includes/EditPage.php index 8225d5a6a7,f8be535e60..dfc13d5907 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@@ -1306,146 -1201,175 +1306,146 @@@ class EditPage wfProfileOut( __METHOD__ . '-checks' ); - // Use SELECT FOR UPDATE here to avoid transaction collision in - // WikiPage::updateRevisionOn() and ending in the self::AS_END case. - $this->mArticle->loadPageData( 'forupdate' ); + # Load the page data from the master. If anything changes in the meantime, + # we detect it by using page_latest like a token in a 1 try compare-and-swap. + $this->mArticle->loadPageData( 'fromdbmaster' ); $new = !$this->mArticle->exists(); - if ( $new ) { - // Late check for create permission, just in case *PARANOIA* - if ( !$this->mTitle->userCan( 'create' ) ) { - $status->fatal( 'nocreatetext' ); - $status->value = self::AS_NO_CREATE_PERMISSION; - wfDebug( __METHOD__ . ": no create permission\n" ); - wfProfileOut( __METHOD__ ); - return $status; - } + try { + if ( $new ) { + // Late check for create permission, just in case *PARANOIA* + if ( !$this->mTitle->userCan( 'create' ) ) { + $status->fatal( 'nocreatetext' ); + $status->value = self::AS_NO_CREATE_PERMISSION; + wfDebug( __METHOD__ . ": no create permission\n" ); + wfProfileOut( __METHOD__ ); + return $status; + } - # Don't save a new article if it's blank. - if ( $this->textbox1 == '' ) { - $status->setResult( false, self::AS_BLANK_ARTICLE ); - wfProfileOut( __METHOD__ ); - return $status; - } + # Don't save a new article if it's blank. + if ( $this->textbox1 == '' ) { + $status->setResult( false, self::AS_BLANK_ARTICLE ); + wfProfileOut( __METHOD__ ); + return $status; + } - // Run post-section-merge edit filter - if ( !wfRunHooks( 'EditFilterMerged', array( $this, $this->textbox1, &$this->hookError, $this->summary ) ) ) { - # Error messages etc. could be handled within the hook... - $status->fatal( 'hookaborted' ); - $status->value = self::AS_HOOK_ERROR; - wfProfileOut( __METHOD__ ); - return $status; - } elseif ( $this->hookError != '' ) { - # ...or the hook could be expecting us to produce an error - $status->fatal( 'hookaborted' ); - $status->value = self::AS_HOOK_ERROR_EXPECTED; - wfProfileOut( __METHOD__ ); - return $status; - } + // Run post-section-merge edit filter + if ( !wfRunHooks( 'EditFilterMerged', array( $this, $this->textbox1, &$this->hookError, $this->summary ) ) ) { + # Error messages etc. could be handled within the hook... + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR; + wfProfileOut( __METHOD__ ); + return $status; + } elseif ( $this->hookError != '' ) { + # ...or the hook could be expecting us to produce an error + $status->fatal( 'hookaborted' ); + $status->value = self::AS_HOOK_ERROR_EXPECTED; + wfProfileOut( __METHOD__ ); + return $status; + } - $text = $this->textbox1; - $result['sectionanchor'] = ''; - if ( $this->section == 'new' ) { - if ( $this->sectiontitle !== '' ) { - // Insert the section title above the content. - $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->sectiontitle ) . "\n\n" . $text; - - // Jump to the new section - $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle ); - - // If no edit summary was specified, create one automatically from the section - // title and have it link to the new section. Otherwise, respect the summary as - // passed. - if ( $this->summary === '' ) { - $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle ); - $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle ); - } - } elseif ( $this->summary !== '' ) { - // Insert the section title above the content. - $text = wfMsgForContent( 'newsectionheaderdefaultlevel', $this->summary ) . "\n\n" . $text; + $content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format ); - // Jump to the new section - $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary ); + $result['sectionanchor'] = ''; + if ( $this->section == 'new' ) { + if ( $this->sectiontitle !== '' ) { + // Insert the section title above the content. + $content = $content->addSectionHeader( $this->sectiontitle ); + + // Jump to the new section + $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->sectiontitle ); + + // If no edit summary was specified, create one automatically from the section + // title and have it link to the new section. Otherwise, respect the summary as + // passed. + if ( $this->summary === '' ) { + $cleanSectionTitle = $wgParser->stripSectionName( $this->sectiontitle ); + $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSectionTitle ); + } + } elseif ( $this->summary !== '' ) { + // Insert the section title above the content. + $content = $content->addSectionHeader( $this->sectiontitle ); - // Create a link to the new section from the edit summary. - $cleanSummary = $wgParser->stripSectionName( $this->summary ); - $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary ); + // Jump to the new section + $result['sectionanchor'] = $wgParser->guessLegacySectionNameFromWikiText( $this->summary ); + + // Create a link to the new section from the edit summary. + $cleanSummary = $wgParser->stripSectionName( $this->summary ); + $this->summary = wfMsgForContent( 'newsectionsummary', $cleanSummary ); + } } - } - $status->value = self::AS_SUCCESS_NEW_ARTICLE; + $status->value = self::AS_SUCCESS_NEW_ARTICLE; - } else { + } else { # not $new - # Article exists. Check for edit conflict. - $timestamp = $this->mArticle->getTimestamp(); - wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}\n" ); + # Article exists. Check for edit conflict. - if ( $timestamp != $this->edittime ) { - $this->isConflict = true; - if ( $this->section == 'new' ) { - if ( $this->mArticle->getUserText() == $wgUser->getName() && - $this->mArticle->getComment() == $this->summary ) { - // Probably a duplicate submission of a new comment. - // This can happen when squid resends a request after - // a timeout but the first one actually went through. - wfDebug( __METHOD__ . ": duplicate new section submission; trigger edit conflict!\n" ); - } else { - // New comment; suppress conflict. + $this->mArticle->clear(); # Force reload of dates, etc. + $timestamp = $this->mArticle->getTimestamp(); + + wfDebug( "timestamp: {$timestamp}, edittime: {$this->edittime}\n" ); + + if ( $timestamp != $this->edittime ) { + $this->isConflict = true; + if ( $this->section == 'new' ) { + if ( $this->mArticle->getUserText() == $wgUser->getName() && + $this->mArticle->getComment() == $this->summary ) { + // Probably a duplicate submission of a new comment. + // This can happen when squid resends a request after + // a timeout but the first one actually went through. + wfDebug( __METHOD__ . ": duplicate new section submission; trigger edit conflict!\n" ); + } else { + // New comment; suppress conflict. + $this->isConflict = false; + wfDebug( __METHOD__ . ": conflict suppressed; new section\n" ); + } + } elseif ( $this->section == '' && $this->userWasLastToEdit( $wgUser->getId(), $this->edittime ) ) { + # Suppress edit conflict with self, except for section edits where merging is required. + wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" ); $this->isConflict = false; - wfDebug( __METHOD__ . ": conflict suppressed; new section\n" ); } - } elseif ( $this->section == '' && $this->userWasLastToEdit( $wgUser->getId(), $this->edittime ) ) { - # Suppress edit conflict with self, except for section edits where merging is required. - wfDebug( __METHOD__ . ": Suppressing edit conflict, same user.\n" ); - $this->isConflict = false; } - } - - // If sectiontitle is set, use it, otherwise use the summary as the section title (for - // backwards compatibility with old forms/bots). - if ( $this->sectiontitle !== '' ) { - $sectionTitle = $this->sectiontitle; - } else { - $sectionTitle = $this->summary; - } - if ( $this->isConflict ) { - wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" ); - $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle, $this->edittime ); - } else { - wfDebug( __METHOD__ . ": getting section '$this->section'\n" ); - $text = $this->mArticle->replaceSection( $this->section, $this->textbox1, $sectionTitle ); - } - if ( is_null( $text ) ) { - wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" ); - $this->isConflict = true; - $text = $this->textbox1; // do not try to merge here! - } elseif ( $this->isConflict ) { - # Attempt merge - if ( $this->mergeChangesInto( $text ) ) { - // Successful merge! Maybe we should tell the user the good news? - $this->isConflict = false; - wfDebug( __METHOD__ . ": Suppressing edit conflict, successful merge.\n" ); + // If sectiontitle is set, use it, otherwise use the summary as the section title (for + // backwards compatibility with old forms/bots). + if ( $this->sectiontitle !== '' ) { + $sectionTitle = $this->sectiontitle; } else { - $this->section = ''; - $this->textbox1 = $text; - wfDebug( __METHOD__ . ": Keeping edit conflict, failed merge.\n" ); + $sectionTitle = $this->summary; } - } - if ( $this->isConflict ) { - $status->setResult( false, self::AS_CONFLICT_DETECTED ); - wfProfileOut( __METHOD__ ); - return $status; - } + $textbox_content = ContentHandler::makeContent( $this->textbox1, $this->getTitle(), $this->content_model, $this->content_format ); + $content = null; - // Run post-section-merge edit filter - if ( !wfRunHooks( 'EditFilterMerged', array( $this, $text, &$this->hookError, $this->summary ) ) ) { - # Error messages etc. could be handled within the hook... - $status->fatal( 'hookaborted' ); - $status->value = self::AS_HOOK_ERROR; - wfProfileOut( __METHOD__ ); - return $status; - } elseif ( $this->hookError != '' ) { - # ...or the hook could be expecting us to produce an error - $status->fatal( 'hookaborted' ); - $status->value = self::AS_HOOK_ERROR_EXPECTED; - wfProfileOut( __METHOD__ ); - return $status; - } + if ( $this->isConflict ) { + wfDebug( __METHOD__ . ": conflict! getting section '$this->section' for time '$this->edittime' (article time '{$timestamp}')\n" ); + $content = $this->mArticle->replaceSectionContent( $this->section, $textbox_content, $sectionTitle, $this->edittime ); + } else { + wfDebug( __METHOD__ . ": getting section '$this->section'\n" ); + $content = $this->mArticle->replaceSectionContent( $this->section, $textbox_content, $sectionTitle ); + } - # Handle the user preference to force summaries here, but not for null edits - if ( $this->section != 'new' && !$this->allowBlankSummary - && $this->getOriginalContent() != $text - && !Title::newFromRedirect( $text ) ) # check if it's not a redirect - { - if ( md5( $this->summary ) == $this->autoSumm ) { - $this->missingSummary = true; - $status->fatal( 'missingsummary' ); - $status->value = self::AS_SUMMARY_NEEDED; - wfProfileOut( __METHOD__ ); - return $status; + if ( is_null( $content ) ) { + wfDebug( __METHOD__ . ": activating conflict; section replace failed.\n" ); + $this->isConflict = true; + $content = $textbox_content; // do not try to merge here! + } elseif ( $this->isConflict ) { + # Attempt merge + if ( $this->mergeChangesIntoContent( $textbox_content ) ) { + // Successful merge! Maybe we should tell the user the good news? + $this->isConflict = false; + $content = $textbox_content; + wfDebug( __METHOD__ . ": Suppressing edit conflict, successful merge.\n" ); + } else { + $this->section = ''; + #$this->textbox1 = $text; #redundant, nothing to do here? + wfDebug( __METHOD__ . ": Keeping edit conflict, failed merge.\n" ); + } } - } - # And a similar thing for new sections - if ( $this->section == 'new' && !$this->allowBlankSummary ) { - if ( trim( $this->summary ) == '' ) { - $this->missingSummary = true; - $status->fatal( 'missingsummary' ); // or 'missingcommentheader' if $section == 'new'. Blegh - $status->value = self::AS_SUMMARY_NEEDED; + if ( $this->isConflict ) { + $status->setResult( false, self::AS_CONFLICT_DETECTED ); wfProfileOut( __METHOD__ ); return $status; } @@@ -1639,36 -1515,11 +1639,36 @@@ * @private * @todo document * - * @parma $editText string + * @param $editText string * * @return bool + * @deprecated since 1.WD, use mergeChangesIntoContent() instead + */ + function mergeChangesInto( &$editText ){ + wfDebug( __METHOD__, "1.WD" ); + + $editContent = ContentHandler::makeContent( $editText, $this->getTitle(), $this->content_model, $this->content_format ); + + $ok = $this->mergeChangesIntoContent( $editContent ); + + if ( $ok ) { + $editText = $editContent->serialize( $this->content_format ); #XXX: really serialize?! + return true; + } else { + return false; + } + } + + /** + * @private + * @todo document + * + * @parma $editText string + * + * @return bool + * @since since 1.WD */ - function mergeChangesInto( &$editText ) { + private function mergeChangesIntoContent( &$editContent ){ wfProfileIn( __METHOD__ ); $db = wfGetDB( DB_MASTER ); diff --cc includes/Export.php index fd0c7658e4,f01fb23732..f2b7e1164a --- a/includes/Export.php +++ b/includes/Export.php @@@ -58,6 -58,14 +58,14 @@@ class WikiExporter */ var $sink; + /** + * Returns the export schema version. + * @return string + */ + public static function schemaVersion() { - return "0.7"; ++ return "0.7"; #FIXME: bump this when pushing ContentHandler additions. + } + /** * If using WikiExporter::STREAM to stream a large amount of data, * provide a database connection which is not managed by diff --cc includes/ImagePage.php index 62fdcca76a,fead0f580b..9221a79a19 --- a/includes/ImagePage.php +++ b/includes/ImagePage.php @@@ -155,11 -155,9 +155,11 @@@ class ImagePage extends Article # should be in page content language $pageLang = $this->getTitle()->getPageLanguage(); $out->addHTML( Xml::openElement( 'div', array( 'id' => 'mw-imagepage-content', - 'lang' => $pageLang->getCode(), 'dir' => $pageLang->getDir(), + 'lang' => $pageLang->getHtmlCode(), 'dir' => $pageLang->getDir(), 'class' => 'mw-content-'.$pageLang->getDir() ) ) ); + parent::view(); + $out->addHTML( Xml::closeElement( 'div' ) ); } else { # Just need to set the right headers diff --cc includes/LinksUpdate.php index 3e8e362c7a,1d0bcf78d2..0bdffea745 --- a/includes/LinksUpdate.php +++ b/includes/LinksUpdate.php @@@ -821,18 -822,12 +821,16 @@@ class LinksDeletionUpdate extends SqlDa /** * Constructor * - * @param $title Title of the page we're updating - * @param $parserOutput ParserOutput: output from a full parse of this page - * @param $recursive Boolean: queue jobs for recursive updates? + * @param $page WikiPage Page we are updating */ - function __construct( WikiPage $page ) { + function __construct( Title $title ) { parent::__construct( ); - $this->mPage = $page; + $this->mTitle = $title; + + if ( !$title->getArticleID() ) { + throw new MWException( "The Title object did not provide an article ID. Perhaps the page doesn't exist?" ); + } } /** diff --cc includes/Revision.php index 7f872d7470,13eaae4ef0..aa0d8314d3 --- a/includes/Revision.php +++ b/includes/Revision.php @@@ -1200,10 -1024,8 +1227,10 @@@ class Revision implements IDBAccessObje wfProfileIn( __METHOD__ ); + $this->checkContentModel(); + $data = $this->mText; - $flags = Revision::compressRevisionText( $data ); + $flags = self::compressRevisionText( $data ); # Write to external storage if required if( $wgDefaultExternalStore ) { @@@ -1237,42 -1059,27 +1264,41 @@@ $rev_id = isset( $this->mId ) ? $this->mId : $dbw->nextSequenceValue( 'revision_rev_id_seq' ); - - $dbw->insert( 'revision', - array( - 'rev_id' => $rev_id, - 'rev_page' => $this->mPage, - 'rev_text_id' => $this->mTextId, - 'rev_comment' => $this->mComment, - 'rev_minor_edit' => $this->mMinorEdit ? 1 : 0, - 'rev_user' => $this->mUser, - 'rev_user_text' => $this->mUserText, - 'rev_timestamp' => $dbw->timestamp( $this->mTimestamp ), - 'rev_deleted' => $this->mDeleted, - 'rev_len' => $this->mSize, - 'rev_parent_id' => is_null( $this->mParentId ) - ? $this->getPreviousRevisionId( $dbw ) - : $this->mParentId, - 'rev_sha1' => is_null( $this->mSha1 ) - ? self::base36Sha1( $this->mText ) - : $this->mSha1 - ), __METHOD__ + $row = array( + 'rev_id' => $rev_id, + 'rev_page' => $this->mPage, + 'rev_text_id' => $this->mTextId, + 'rev_comment' => $this->mComment, + 'rev_minor_edit' => $this->mMinorEdit ? 1 : 0, + 'rev_user' => $this->mUser, + 'rev_user_text' => $this->mUserText, + 'rev_timestamp' => $dbw->timestamp( $this->mTimestamp ), + 'rev_deleted' => $this->mDeleted, + 'rev_len' => $this->mSize, + 'rev_parent_id' => is_null( $this->mParentId ) + ? $this->getPreviousRevisionId( $dbw ) + : $this->mParentId, + 'rev_sha1' => is_null( $this->mSha1 ) + ? Revision::base36Sha1( $this->mText ) + : $this->mSha1, ); + if ( $wgContentHandlerUseDB ) { + //NOTE: Store null for the default model and format, to save space. + //XXX: Makes the DB sensitive to changed defaults. Make this behaviour optional? Only in miser mode? + + $model = $this->getContentModel(); + $format = $this->getContentFormat(); + + $defaultModel = ContentHandler::getDefaultModelFor( $this->getTitle() ); + $defaultFormat = ContentHandler::getForModelID( $defaultModel )->getDefaultFormat(); + + $row[ 'rev_content_model' ] = ( $model === $defaultModel ) ? null : $model; + $row[ 'rev_content_format' ] = ( $format === $defaultFormat ) ? null : $format; + } + + $dbw->insert( 'revision', $row, __METHOD__ ); + $this->mId = !is_null( $rev_id ) ? $rev_id : $dbw->insertId(); wfRunHooks( 'RevisionInsertComplete', array( &$this, $data, $flags ) ); diff --cc includes/WikiPage.php index f381da63f0,2de1626b51..657fcf3d06 --- a/includes/WikiPage.php +++ b/includes/WikiPage.php @@@ -1724,6 -1494,10 +1707,10 @@@ class WikiPage extends Page wfProfileOut( __METHOD__ ); return $status; - } elseif ( $oldtext === false ) { ++ } elseif ( !$old_content ) { + # Sanity check for bug 37225 + wfProfileOut( __METHOD__ ); + throw new MWException( "Could not find text for current revision {$oldid}." ); } $revision = new Revision( array( @@@ -1735,30 -1508,16 +1722,34 @@@ 'parent_id' => $oldid, 'user' => $user->getId(), 'user_text' => $user->getName(), - 'timestamp' => $now - ) ); + 'timestamp' => $now, + 'content_model' => $content->getModel(), + 'content_format' => $serialisation_format, + ) ); #XXX: pass content object?! + + # Bug 37225: use accessor to get the text as Revision may trim it. + # After trimming, the text may be a duplicate of the current text. - $text = $revision->getText(); // sanity; EditPage should trim already ++ $content = $revision->getContent(); // sanity; EditPage should trim already + - $changed = ( strcmp( $text, $oldtext ) != 0 ); + $changed = !$content->equals( $old_content ); if ( $changed ) { + if ( !$content->isValid() ) { + throw new MWException( "New content failed validity check!" ); + } + $dbw->begin( __METHOD__ ); + + $prepStatus = $content->prepareSave( $this, $flags, $baseRevId, $user ); + $status->merge( $prepStatus ); + + if ( !$status->isOK() ) { + $dbw->rollback(); + + wfProfileOut( __METHOD__ ); + return $status; + } + $revisionId = $revision->insertOn( $dbw ); # Update page @@@ -2551,10 -2227,11 +2558,11 @@@ if ( !$ok ) { $dbw->rollback( __METHOD__ ); - return WikiPage::DELETE_NO_REVISIONS; + $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) ); + return $status; } - $this->doDeleteUpdates( $id ); + $this->doDeleteUpdates( $id, $content ); # Log the deletion, if the page was suppressed, log it at Oversight instead $logtype = $suppress ? 'suppress' : 'delete'; diff --cc includes/filerepo/file/LocalFile.php index 22131c61e5,4db1f5fdad..916b25f23d --- a/includes/filerepo/file/LocalFile.php +++ b/includes/filerepo/file/LocalFile.php @@@ -1456,11 -1456,11 +1456,11 @@@ class LocalFile extends File */ function getDescriptionText() { global $wgParser; - $revision = Revision::newFromTitle( $this->title ); + $revision = Revision::newFromTitle( $this->title, false, Revision::AVOID_MASTER ); if ( !$revision ) return false; - $text = $revision->getText(); - if ( !$text ) return false; - $pout = $wgParser->parse( $text, $this->title, new ParserOptions() ); + $content = $revision->getContent(); + if ( !$content ) return false; + $pout = $content->getParserOutput( $this->title, null, new ParserOptions() ); return $pout->getText(); } diff --cc includes/specials/SpecialBooksources.php index 6182f7d146,87ba0cb1a6..71b846a431 --- a/includes/specials/SpecialBooksources.php +++ b/includes/specials/SpecialBooksources.php @@@ -143,8 -143,8 +143,8 @@@ class SpecialBookSources extends Specia $page = $this->msg( 'booksources' )->inContentLanguage()->text(); $title = Title::makeTitleSafe( NS_PROJECT, $page ); # Show list in content language if( is_object( $title ) && $title->exists() ) { - $rev = Revision::newFromTitle( $title ); + $rev = Revision::newFromTitle( $title, false, Revision::AVOID_MASTER ); - $this->getOutput()->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $rev->getText() ) ); + $this->getOutput()->addWikiText( str_replace( 'MAGICNUMBER', $this->isbn, $rev->getText() ) ); #FIXME: need a way to do this via ContentHandler (or enforce flat text-based content) return true; } diff --cc includes/specials/SpecialUndelete.php index 542ecff5df,611b3b9212..f242b425e8 --- a/includes/specials/SpecialUndelete.php +++ b/includes/specials/SpecialUndelete.php @@@ -940,8 -920,9 +951,9 @@@ class SpecialUndelete extends SpecialPa $this->diffHeader( $currentRev, 'n' ) . "\n" . "" . - $diffEngine->generateDiffBody( - $previousRev->getText( Revision::FOR_THIS_USER, $this->getUser() ), - $currentRev->getText( Revision::FOR_THIS_USER, $this->getUser() ) ) . + $diffEngine->generateContentDiffBody( - $previousRev->getContent(), $currentRev->getContent() ) . ++ $previousRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ), ++ $currentRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ) ) . "" . "\n" ); diff --cc tests/phpunit/includes/WikiPageTest.php index f2db24fc90,2949a3af8f..1e44371b14 --- a/tests/phpunit/includes/WikiPageTest.php +++ b/tests/phpunit/includes/WikiPageTest.php @@@ -614,19 -478,7 +614,19 @@@ more stuf $this->assertEquals( $expected, $text ); } + /** + * @dataProvider dataReplaceSection + */ + public function testReplaceSectionContent( $title, $text, $section, $with, $sectionTitle, $expected ) { + $page = $this->createPage( $title, $text ); + + $content = ContentHandler::makeContent( $with, $page->getTitle(), $page->getContentModel() ); + $c = $page->replaceSectionContent( $section, $content, $sectionTitle ); + + $this->assertEquals( $expected, is_null( $c ) ? null : trim( $c->getNativeData() ) ); + } + - /* @FIXME: fix this! + /* @todo FIXME: fix this! public function testGetUndoText() { global $wgDiff3;