/** @var Content $pstContent */
private $pstContent = null;
+ private function checkReadPermissions( Title $title ) {
+ if ( !$title->userCan( 'read', $this->getUser() ) ) {
+ $this->dieUsage( "You don't have permission to view this page", 'permissiondenied' );
+ }
+ }
+
public function execute() {
// The data is hot but user-dependent, like page views, so we set vary cookies
$this->getMain()->setCacheMode( 'anon-public-user-private' );
$this->section = $params['section'];
if ( !preg_match( '/^((T-)?\d+|new)$/', $this->section ) ) {
$this->dieUsage(
- "The section parameter must be a valid section id or 'new'", "invalidsection"
+ 'The section parameter must be a valid section id or "new"', 'invalidsection'
);
}
} else {
if ( !$rev ) {
$this->dieUsage( "There is no revision ID $oldid", 'missingrev' );
}
+
+ $this->checkReadPermissions( $rev->getTitle() );
if ( !$rev->userCan( Revision::DELETED_TEXT, $this->getUser() ) ) {
$this->dieUsage( "You don't have permission to view deleted revisions", 'permissiondenied' );
}
$titleObj = $rev->getTitle();
$wgTitle = $titleObj;
$pageObj = WikiPage::factory( $titleObj );
- $popts = $this->makeParserOptions( $pageObj, $params );
+ list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
// If for some reason the "oldid" is actually the current revision, it may be cached
// Deliberately comparing $pageObj->getLatest() with $rev->getId(), rather than
// checking $rev->isCurrent(), because $pageObj is what actually ends up being used,
// and if its ->getLatest() is outdated, $rev->isCurrent() won't tell us that.
- if ( $rev->getId() == $pageObj->getLatest() ) {
+ if ( !$suppressCache && $rev->getId() == $pageObj->getLatest() ) {
// May get from/save to parser cache
$p_result = $this->getParsedContent( $pageObj, $popts,
$pageid, isset( $prop['wikitext'] ) );
if ( !$titleObj || !$titleObj->exists() ) {
$this->dieUsage( "The page you specified doesn't exist", 'missingtitle' );
}
+
+ $this->checkReadPermissions( $titleObj );
$wgTitle = $titleObj;
if ( isset( $prop['revid'] ) ) {
$oldid = $pageObj->getLatest();
}
- $popts = $this->makeParserOptions( $pageObj, $params );
+ list( $popts, $reset, $suppressCache ) = $this->makeParserOptions( $pageObj, $params );
// Don't pollute the parser cache when setting options that aren't
// in ParserOptions::optionsHash()
/// @todo: This should be handled closer to the actual cache instead of here, see T110269
- $suppressCache =
+ $suppressCache = $suppressCache ||
$params['disablepp'] ||
$params['disablelimitreport'] ||
$params['preview'] ||
$pageObj = $article->getPage();
}
- $popts = $this->makeParserOptions( $pageObj, $params );
+ list( $popts, $reset ) = $this->makeParserOptions( $pageObj, $params );
$textProvided = !is_null( $text );
if ( !$textProvided ) {
$titleObj->getPrefixedText();
}
- if ( isset( $prop['headitems'] ) || isset( $prop['headhtml'] ) ) {
- $context = $this->getContext();
- $context->setTitle( $titleObj );
- $context->getOutput()->addParserOutputMetadata( $p_result );
-
- if ( isset( $prop['headitems'] ) ) {
- $headItems = $this->formatHeadItems( $p_result->getHeadItems() );
-
- $css = $this->formatCss( $context->getOutput()->buildCssLinksArray() );
+ if ( isset( $prop['headitems'] ) ) {
+ $result_array['headitems'] = $this->formatHeadItems( $p_result->getHeadItems() );
+ $this->logFeatureUsage( 'action=parse&prop=headitems' );
+ $this->setWarning( 'headitems is deprecated since MediaWiki 1.28. '
+ . 'Use prop=headhtml when creating new HTML documents, or '
+ . 'prop=modules|jsconfigvars when updating a document client-side.' );
+ }
- $scripts = [ $context->getOutput()->getHeadScripts() ];
+ if ( isset( $prop['headhtml'] ) ) {
+ $context = new DerivativeContext( $this->getContext() );
+ $context->setTitle( $titleObj );
+ $context->setWikiPage( $pageObj );
- $result_array['headitems'] = array_merge( $headItems, $css, $scripts );
- }
+ // We need an OutputPage tied to $context, not to the
+ // RequestContext at the root of the stack.
+ $output = new OutputPage( $context );
+ $output->addParserOutputMetadata( $p_result );
- if ( isset( $prop['headhtml'] ) ) {
- $result_array['headhtml'] = $context->getOutput()->headElement( $context->getSkin() );
- $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml';
- }
+ $result_array['headhtml'] = $output->headElement( $context->getSkin() );
+ $result_array[ApiResult::META_BC_SUBELEMENTS][] = 'headhtml';
}
if ( isset( $prop['modules'] ) ) {
$result_array['modules'] = array_values( array_unique( $p_result->getModules() ) );
$result_array['modulescripts'] = array_values( array_unique( $p_result->getModuleScripts() ) );
$result_array['modulestyles'] = array_values( array_unique( $p_result->getModuleStyles() ) );
- // To be removed in 1.27
- $result_array['modulemessages'] = [];
- $this->setWarning( 'modulemessages is deprecated since MediaWiki 1.26' );
}
if ( isset( $prop['jsconfigvars'] ) ) {
if ( isset( $prop['modules'] ) &&
!isset( $prop['jsconfigvars'] ) && !isset( $prop['encodedjsconfigvars'] ) ) {
- $this->setWarning( "Property 'modules' was set but not 'jsconfigvars' " .
- "or 'encodedjsconfigvars'. Configuration variables are necessary " .
- "for proper module usage." );
+ $this->setWarning( 'Property "modules" was set but not "jsconfigvars" ' .
+ 'or "encodedjsconfigvars". Configuration variables are necessary ' .
+ 'for proper module usage.' );
}
if ( isset( $prop['indicators'] ) ) {
if ( isset( $prop['parsetree'] ) || $params['generatexml'] ) {
if ( $this->content->getModel() != CONTENT_MODEL_WIKITEXT ) {
- $this->dieUsage( "parsetree is only supported for wikitext content", "notwikitext" );
+ $this->dieUsage( 'parsetree is only supported for wikitext content', 'notwikitext' );
}
$wgParser->startExternalParse( $titleObj, $popts, Parser::OT_PREPROCESS );
'indicators' => 'ind',
'modulescripts' => 'm',
'modulestyles' => 'm',
- 'modulemessages' => 'm',
'properties' => 'pp',
'limitreportdata' => 'lr',
];
* @param WikiPage $pageObj
* @param array $params
*
- * @return ParserOptions
+ * @return array [ ParserOptions, ScopedCallback, bool $suppressCache ]
*/
protected function makeParserOptions( WikiPage $pageObj, array $params ) {
-
$popts = $pageObj->makeParserOptions( $this->getContext() );
$popts->enableLimitReport( !$params['disablepp'] && !$params['disablelimitreport'] );
$popts->setIsPreview( $params['preview'] || $params['sectionpreview'] );
$popts->setTidy( false );
}
- return $popts;
+ $reset = null;
+ $suppressCache = false;
+ Hooks::run( 'ApiMakeParserOptions',
+ [ $popts, $pageObj->getTitle(), $params, $this, &$reset, &$suppressCache ] );
+
+ return [ $popts, $reset, $suppressCache ];
}
/**
// Not cached (save or load)
$section = $content->getSection( $this->section );
if ( $section === false ) {
- $this->dieUsage( "There is no section {$this->section} in " . $what, 'nosuchsection' );
+ $this->dieUsage( "There is no section {$this->section} in $what", 'nosuchsection' );
}
if ( $section === null ) {
- $this->dieUsage( "Sections are not supported by " . $what, 'nosuchsection' );
+ $this->dieUsage( "Sections are not supported by $what", 'nosuchsection' );
$section = false;
}
$hiddencats[$row->page_title] = isset( $row->pp_propname );
}
+ $linkCache = LinkCache::singleton();
+
foreach ( $links as $link => $sortkey ) {
$entry = [];
$entry['sortkey'] = $sortkey;
ApiResult::setContentValue( $entry, 'category', (string)$link );
if ( !isset( $hiddencats[$link] ) ) {
$entry['missing'] = true;
+
+ // We already know the link doesn't exist in the database, so
+ // tell LinkCache that before calling $title->isKnown().
+ $title = Title::makeTitle( NS_CATEGORY, $link );
+ $linkCache->addBadLinkObj( $title );
+ if ( $title->isKnown() ) {
+ $entry['known'] = true;
+ }
} elseif ( $hiddencats[$link] ) {
$entry['hidden'] = true;
}
return $result;
}
- private function formatCss( $css ) {
- $result = [];
- foreach ( $css as $file => $link ) {
- $entry = [];
- $entry['file'] = $file;
- ApiResult::setContentValue( $entry, 'link', $link );
- $result[] = $entry;
- }
-
- return $result;
- }
-
private function formatLimitReportData( $limitReportData ) {
$result = [];