Merge "Provide command to adjust phpunit.xml for code coverage"
[lhc/web/wiklou.git] / includes / OutputPage.php
index 2c7292c..7f005fb 100644 (file)
@@ -44,7 +44,7 @@ use Wikimedia\WrappedStringList;
  * @todo document
  */
 class OutputPage extends ContextSource {
-       /** @var array Should be private. Used with addMeta() which adds "<meta>" */
+       /** @var string[][] Should be private. Used with addMeta() which adds "<meta>" */
        protected $mMetatags = [];
 
        /** @var array */
@@ -54,7 +54,8 @@ class OutputPage extends ContextSource {
        protected $mCanonicalUrl = false;
 
        /**
-        * @var string The contents of <h1> */
+        * @var string The contents of <h1>
+        */
        private $mPageTitle = '';
 
        /**
@@ -994,6 +995,8 @@ class OutputPage extends ContextSource {
         * @param Title $t
         */
        public function setTitle( Title $t ) {
+               // @phan-suppress-next-next-line PhanUndeclaredMethod
+               // @fixme Not all implementations of IContextSource have this method!
                $this->getContext()->setTitle( $t );
        }
 
@@ -1660,6 +1663,16 @@ class OutputPage extends ContextSource {
                return $this->mRevisionId;
        }
 
+       /**
+        * Whether the revision displayed is the latest revision of the page
+        *
+        * @since 1.34
+        * @return bool
+        */
+       public function isRevisionCurrent() {
+               return $this->mRevisionId == 0 || $this->mRevisionId == $this->getTitle()->getLatestRevID();
+       }
+
        /**
         * Set the timestamp of the revision which will be displayed. This is used
         * to avoid a extra DB call in Skin::lastModified().
@@ -1809,14 +1822,10 @@ class OutputPage extends ContextSource {
         * @param string $text Wikitext
         * @param Title $title
         * @param bool $linestart Is this the start of a line?
-        * @param bool $tidy Whether to use tidy.
-        *             Setting this to false (or omitting it) is deprecated
-        *             since 1.32; all wikitext should be tidied.
         * @param bool $interface Whether it is an interface message
         *   (for example disables conversion)
         * @param string $wrapperClass if not empty, wraps the output in
         *   a `<div class="$wrapperClass">`
-        * @private
         */
        private function addWikiTextTitleInternal(
                $text, Title $title, $linestart, $interface, $wrapperClass = null
@@ -2405,32 +2414,16 @@ class OutputPage extends ContextSource {
                                $this->mCdnMaxage != 0 &&
                                !$this->haveCacheVaryCookies()
                        ) {
-                               if ( $config->get( 'UseESI' ) ) {
-                                       wfDeprecated( '$wgUseESI = true', '1.33' );
-                                       # We'll purge the proxy cache explicitly, but require end user agents
-                                       # to revalidate against the proxy on each visit.
-                                       # Surrogate-Control controls our CDN, Cache-Control downstream caches
-                                       wfDebug( __METHOD__ .
-                                               ": proxy caching with ESI; {$this->mLastModified} **", 'private' );
-                                       # start with a shorter timeout for initial testing
-                                       # header( 'Surrogate-Control: max-age=2678400+2678400, content="ESI/1.0"');
-                                       $response->header(
-                                               "Surrogate-Control: max-age={$config->get( 'CdnMaxAge' )}" .
-                                               "+{$this->mCdnMaxage}, content=\"ESI/1.0\""
-                                       );
-                                       $response->header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' );
-                               } else {
-                                       # We'll purge the proxy cache for anons explicitly, but require end user agents
-                                       # to revalidate against the proxy on each visit.
-                                       # IMPORTANT! The CDN needs to replace the Cache-Control header with
-                                       # Cache-Control: s-maxage=0, must-revalidate, max-age=0
-                                       wfDebug( __METHOD__ .
-                                               ": local proxy caching; {$this->mLastModified} **", 'private' );
-                                       # start with a shorter timeout for initial testing
-                                       # header( "Cache-Control: s-maxage=2678400, must-revalidate, max-age=0" );
-                                       $response->header( "Cache-Control: " .
-                                               "s-maxage={$this->mCdnMaxage}, must-revalidate, max-age=0" );
-                               }
+                               # We'll purge the proxy cache for anons explicitly, but require end user agents
+                               # to revalidate against the proxy on each visit.
+                               # IMPORTANT! The CDN needs to replace the Cache-Control header with
+                               # Cache-Control: s-maxage=0, must-revalidate, max-age=0
+                               wfDebug( __METHOD__ .
+                                       ": local proxy caching; {$this->mLastModified} **", 'private' );
+                               # start with a shorter timeout for initial testing
+                               # header( "Cache-Control: s-maxage=2678400, must-revalidate, max-age=0" );
+                               $response->header( "Cache-Control: " .
+                                       "s-maxage={$this->mCdnMaxage}, must-revalidate, max-age=0" );
                        } else {
                                # We do want clients to cache if they can, but they *must* check for updates
                                # on revisiting the page.
@@ -2665,6 +2658,8 @@ class OutputPage extends ContextSource {
         * @param string|null $action Action that was denied or null if unknown
         */
        public function showPermissionsErrorPage( array $errors, $action = null ) {
+               $services = MediaWikiServices::getInstance();
+               $permissionManager = $services->getPermissionManager();
                foreach ( $errors as $key => $error ) {
                        $errors[$key] = (array)$error;
                }
@@ -2674,11 +2669,12 @@ class OutputPage extends ContextSource {
                // 1. the user is not logged in
                // 2. the only error is insufficient permissions (i.e. no block or something else)
                // 3. the error can be avoided simply by logging in
+
                if ( in_array( $action, [ 'read', 'edit', 'createpage', 'createtalk', 'upload' ] )
                        && $this->getUser()->isAnon() && count( $errors ) == 1 && isset( $errors[0][0] )
                        && ( $errors[0][0] == 'badaccess-groups' || $errors[0][0] == 'badaccess-group0' )
-                       && ( User::groupHasPermission( 'user', $action )
-                       || User::groupHasPermission( 'autoconfirmed', $action ) )
+                       && ( $permissionManager->groupHasPermission( 'user', $action )
+                               || $permissionManager->groupHasPermission( 'autoconfirmed', $action ) )
                ) {
                        $displayReturnto = null;
 
@@ -2714,8 +2710,6 @@ class OutputPage extends ContextSource {
                                }
                        }
 
-                       $services = MediaWikiServices::getInstance();
-
                        $title = SpecialPage::getTitleFor( 'Userlogin' );
                        $linkRenderer = $services->getLinkRenderer();
                        $loginUrl = $title->getLinkURL( $query, false, PROTO_RELATIVE );
@@ -2729,8 +2723,6 @@ class OutputPage extends ContextSource {
                        $this->prepareErrorPage( $this->msg( 'loginreqtitle' ) );
                        $this->addHTML( $this->msg( $msg )->rawParams( $loginLink )->params( $loginUrl )->parse() );
 
-                       $permissionManager = $services->getPermissionManager();
-
                        # Don't return to a page the user can't read otherwise
                        # we'll end up in a pointless loop
                        if ( $displayReturnto && $permissionManager->userCan(
@@ -3017,10 +3009,11 @@ class OutputPage extends ContextSource {
                $sitedir = MediaWikiServices::getInstance()->getContentLanguage()->getDir();
 
                $pieces = [];
-               $pieces[] = Html::htmlHeader( Sanitizer::mergeAttributes(
+               $htmlAttribs = Sanitizer::mergeAttributes(
                        $this->getRlClient()->getDocumentAttributes(),
                        $sk->getHtmlElementAttributes()
-               ) );
+               );
+               $pieces[] = Html::htmlHeader( $htmlAttribs );
                $pieces[] = Html::openElement( 'head' );
 
                if ( $this->getHTMLTitle() == '' ) {
@@ -3040,7 +3033,7 @@ class OutputPage extends ContextSource {
                }
 
                $pieces[] = Html::element( 'title', null, $this->getHTMLTitle() );
-               $pieces[] = $this->getRlClient()->getHeadHtml();
+               $pieces[] = $this->getRlClient()->getHeadHtml( $htmlAttribs['class'] ?? null );
                $pieces[] = $this->buildExemptModules();
                $pieces = array_merge( $pieces, array_values( $this->getHeadLinksArray() ) );
                $pieces = array_merge( $pieces, array_values( $this->mHeadItems ) );
@@ -3217,7 +3210,7 @@ class OutputPage extends ContextSource {
 
                $title = $this->getTitle();
                $ns = $title->getNamespace();
-               $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
+               $nsInfo = $services->getNamespaceInfo();
                $canonicalNamespace = $nsInfo->exists( $ns )
                        ? $nsInfo->getCanonicalName( $ns )
                        : $title->getNsText();
@@ -3301,12 +3294,10 @@ class OutputPage extends ContextSource {
                        $vars['wgUserVariant'] = $contLang->getPreferredVariant();
                }
                // Same test as SkinTemplate
-               $vars['wgIsProbablyEditable'] = $title->quickUserCan( 'edit', $user )
-                       && ( $title->exists() || $title->quickUserCan( 'create', $user ) );
+               $vars['wgIsProbablyEditable'] = $this->userCanEditOrCreate( $user, $title );
 
-               $vars['wgRelevantPageIsProbablyEditable'] = $relevantTitle
-                       && $relevantTitle->quickUserCan( 'edit', $user )
-                       && ( $relevantTitle->exists() || $relevantTitle->quickUserCan( 'create', $user ) );
+               $vars['wgRelevantPageIsProbablyEditable'] = $relevantTitle &&
+                       $this->userCanEditOrCreate( $user, $relevantTitle );
 
                foreach ( $title->getRestrictionTypes() as $type ) {
                        // Following keys are set in $vars:
@@ -3373,6 +3364,21 @@ class OutputPage extends ContextSource {
                return true;
        }
 
+       /**
+        * @param User $user
+        * @param LinkTarget $title
+        * @return bool
+        */
+       private function userCanEditOrCreate(
+               User $user,
+               LinkTarget $title
+       ) {
+               $pm = MediaWikiServices::getInstance()->getPermissionManager();
+               return $pm->quickUserCan( 'edit', $user, $title )
+               && ( $this->getTitle()->exists() ||
+                        $pm->quickUserCan( 'create', $user, $title ) );
+       }
+
        /**
         * @return array Array in format "link name or number => 'link html'".
         */
@@ -3437,11 +3443,7 @@ class OutputPage extends ContextSource {
 
                # Universal edit button
                if ( $config->get( 'UniversalEditButton' ) && $this->isArticleRelated() ) {
-                       $user = $this->getUser();
-                       if ( $this->getTitle()->quickUserCan( 'edit', $user )
-                               && ( $this->getTitle()->exists() ||
-                                       $this->getTitle()->quickUserCan( 'create', $user ) )
-                       ) {
+                       if ( $this->userCanEditOrCreate( $this->getUser(), $this->getTitle() ) ) {
                                // Original UniversalEditButton
                                $msg = $this->msg( 'edit' )->text();
                                $tags['universal-edit-button'] = Html::element( 'link', [