Switch some HTMLForms in special pages to OOUI
[lhc/web/wiklou.git] / includes / EditPage.php
index e113426..3600fb2 100644 (file)
@@ -156,11 +156,23 @@ class EditPage {
         */
        const AS_SELF_REDIRECT = 236;
 
+       /**
+        * Status: an error relating to change tagging. Look at the message key for
+        * more details
+        */
+       const AS_CHANGE_TAG_ERROR = 237;
+
        /**
         * Status: can't parse content
         */
        const AS_PARSE_ERROR = 240;
 
+       /**
+        * Status: when changing the content model is disallowed due to
+        * $wgContentHandlerUseDB being false
+        */
+       const AS_CANNOT_USE_CUSTOM_MODEL = 241;
+
        /**
         * HTML id and name for the beginning of the edit form.
         */
@@ -351,6 +363,9 @@ class EditPage {
        /** @var null|string */
        public $contentFormat = null;
 
+       /** @var null|array */
+       public $changeTags = null;
+
        # Placeholders for text injection by hooks (must be HTML)
        # extensions should take care to _append_ to the present value
 
@@ -371,12 +386,14 @@ class EditPage {
 
        public $suppressIntro = false;
 
-       /** @var bool Set to true to allow editing of non-text content types. */
-       public $allowNonTextContent = false;
-
        /** @var bool */
        protected $edit;
 
+       /**
+        * @var bool Set in ApiEditPage, based on ContentHandler::allowsDirectApiEditing
+        */
+       private $enableApiEditOverride = false;
+
        /**
         * @param Article $article
         */
@@ -438,8 +455,18 @@ class EditPage {
         * @throws MWException If $modelId has no known handler
         */
        public function isSupportedContentModel( $modelId ) {
-               return $this->allowNonTextContent ||
-                       ContentHandler::getForModelID( $modelId ) instanceof TextContentHandler;
+               return $this->enableApiEditOverride === true ||
+                       ContentHandler::getForModelID( $modelId )->supportsDirectEditing();
+       }
+
+       /**
+        * Allow editing of content that supports API direct editing, but not general
+        * direct editing. Set to false by default.
+        *
+        * @param bool $enableOverride
+        */
+       public function setApiEditOverride( $enableOverride ) {
+               $this->enableApiEditOverride = $enableOverride;
        }
 
        function submit() {
@@ -844,6 +871,14 @@ class EditPage {
 
                        $this->allowBlankArticle = $request->getBool( 'wpIgnoreBlankArticle' );
                        $this->allowSelfRedirect = $request->getBool( 'wpIgnoreSelfRedirect' );
+
+                       $changeTags = $request->getVal( 'wpChangeTags' );
+                       if ( is_null( $changeTags ) || $changeTags === '' ) {
+                               $this->changeTags = array();
+                       } else {
+                               $this->changeTags = array_filter( array_map( 'trim', explode( ',',
+                                       $changeTags ) ) );
+                       }
                } else {
                        # Not a posted form? Start with nothing.
                        wfDebug( __METHOD__ . ": Not a posted form.\n" );
@@ -1008,7 +1043,6 @@ class EditPage {
                                $undo = $wgRequest->getInt( 'undo' );
 
                                if ( $undo > 0 && $undoafter > 0 ) {
-
                                        $undorev = Revision::newFromId( $undo );
                                        $oldrev = Revision::newFromId( $undoafter );
 
@@ -1017,8 +1051,8 @@ class EditPage {
                                        # Otherwise, $content will be left as-is.
                                        if ( !is_null( $undorev ) && !is_null( $oldrev ) &&
                                                !$undorev->isDeleted( Revision::DELETED_TEXT ) &&
-                                               !$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
-
+                                               !$oldrev->isDeleted( Revision::DELETED_TEXT )
+                                       ) {
                                                $content = $this->mArticle->getUndoContent( $undorev, $oldrev );
 
                                                if ( $content === false ) {
@@ -1213,9 +1247,9 @@ class EditPage {
 
                        if ( !$converted ) {
                                //TODO: somehow show a warning to the user!
-                               wfDebug( "Attempt to preload incompatible content: "
-                                               . "can't convert " . $content->getModel()
-                                               . " to " . $handler->getModelID() );
+                               wfDebug( "Attempt to preload incompatible content: " .
+                                       "can't convert " . $content->getModel() .
+                                       " to " . $handler->getModelID() );
 
                                return $handler->makeEmptyContent();
                        }
@@ -1333,6 +1367,7 @@ class EditPage {
                        case self::AS_HOOK_ERROR:
                                return false;
 
+                       case self::AS_CANNOT_USE_CUSTOM_MODEL:
                        case self::AS_PARSE_ERROR:
                                $wgOut->addWikiText( '<div class="error">' . $status->getWikiText() . '</div>' );
                                return true;
@@ -1515,6 +1550,7 @@ class EditPage {
         */
        function internalAttemptSave( &$result, $bot = false ) {
                global $wgUser, $wgRequest, $wgParser, $wgMaxArticleSize;
+               global $wgContentHandlerUseDB;
 
                $status = Status::newGood();
 
@@ -1635,11 +1671,24 @@ class EditPage {
                        }
                }
 
-               if ( $this->contentModel !== $this->mTitle->getContentModel()
-                       && !$wgUser->isAllowed( 'editcontentmodel' )
-               ) {
-                       $status->setResult( false, self::AS_NO_CHANGE_CONTENT_MODEL );
-                       return $status;
+               if ( $this->contentModel !== $this->mTitle->getContentModel() ) {
+                       if ( !$wgContentHandlerUseDB ) {
+                               $status->fatal( 'editpage-cannot-use-custom-model' );
+                               $status->value = self::AS_CANNOT_USE_CUSTOM_MODEL;
+                               return $status;
+                       } elseif ( !$wgUser->isAllowed( 'editcontentmodel' ) ) {
+                               $status->setResult( false, self::AS_NO_CHANGE_CONTENT_MODEL );
+                               return $status;
+                       }
+               }
+
+               if ( $this->changeTags ) {
+                       $changeTagsStatus = ChangeTags::canAddTagsAccompanyingChange(
+                               $this->changeTags, $wgUser );
+                       if ( !$changeTagsStatus->isOK() ) {
+                               $changeTagsStatus->value = self::AS_CHANGE_TAG_ERROR;
+                               return $changeTagsStatus;
+                       }
                }
 
                if ( wfReadOnly() ) {
@@ -1915,7 +1964,20 @@ class EditPage {
                        $wgUser->pingLimiter( 'linkpurge' );
                }
                $result['redirect'] = $content->isRedirect();
+
                $this->updateWatchlist();
+
+               if ( $this->changeTags && isset( $doEditStatus->value['revision'] ) ) {
+                       // If a revision was created, apply any change tags that were requested
+                       $addTags = $this->changeTags;
+                       $revId = $doEditStatus->value['revision']->getId();
+                       // Defer this both for performance and so that addTags() sees the rc_id
+                       // since the recentchange entry addition is deferred first (bug T100248)
+                       DeferredUpdates::addCallableUpdate( function() use ( $addTags, $revId ) {
+                               ChangeTags::addTags( $addTags, null, $revId );
+                       } );
+               }
+
                return $status;
        }
 
@@ -3413,6 +3475,8 @@ HTML
                global $wgOut, $wgUser, $wgRawHtml, $wgLang;
                global $wgAllowUserCss, $wgAllowUserJs;
 
+               $stats = $wgOut->getContext()->getStats();
+
                if ( $wgRawHtml && !$this->mTokenOk ) {
                        // Could be an offsite preview attempt. This is very unsafe if
                        // HTML is enabled, as it could be an attack.
@@ -3424,6 +3488,7 @@ HTML
                                $parsedNote = $wgOut->parse( "<div class='previewnote'>" .
                                        wfMessage( 'session_fail_preview_html' )->text() . "</div>", true, /* interface */true );
                        }
+                       $stats->increment( 'edit.failures.session_loss' );
                        return $parsedNote;
                }
 
@@ -3447,11 +3512,16 @@ HTML
                        if ( $this->mTriedSave && !$this->mTokenOk ) {
                                if ( $this->mTokenOkExceptSuffix ) {
                                        $note = wfMessage( 'token_suffix_mismatch' )->plain();
+                                       $stats->increment( 'edit.failures.bad_token' );
                                } else {
                                        $note = wfMessage( 'session_fail_preview' )->plain();
+                                       $stats->increment( 'edit.failures.session_loss' );
                                }
                        } elseif ( $this->incompleteForm ) {
                                $note = wfMessage( 'edit_form_incomplete' )->plain();
+                               if ( $this->mTriedSave ) {
+                                       $stats->increment( 'edit.failures.incomplete_form' );
+                               }
                        } else {
                                $note = wfMessage( 'previewnote' )->plain() . ' ' . $continueEditing;
                        }
@@ -3700,7 +3770,7 @@ HTML
                }
 
                $script .= '});';
-               $wgOut->addScript( Html::inlineScript( ResourceLoader::makeLoaderConditionalScript( $script ) ) );
+               $wgOut->addScript( ResourceLoader::makeInlineScript( $script ) );
 
                $toolbar = '<div id="toolbar"></div>';