jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/330340 )

Change subject: Add API action to set the language of a page
......................................................................


Add API action to set the language of a page

Currently, a user who wants to set a page's language must use the
Special:PageLanguage interface. However, this is not easy for bots and
scripts to use. The addition of action=setpagelanguage to the API makes
this process easier for such users.

Bug: T74958
Change-Id: I42e74ed3bcd0bfa9ec0c344ba67668210450c975
---
M autoload.php
M includes/api/ApiMain.php
A includes/api/ApiSetPageLanguage.php
M includes/api/i18n/en.json
M includes/api/i18n/qqq.json
M includes/specials/SpecialPageLanguage.php
M languages/i18n/en.json
M languages/i18n/qqq.json
8 files changed, 238 insertions(+), 26 deletions(-)

Approvals:
  TTO: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/autoload.php b/autoload.php
index cdbdf1f..a38fca2 100644
--- a/autoload.php
+++ b/autoload.php
@@ -139,6 +139,7 @@
        'ApiRsd' => __DIR__ . '/includes/api/ApiRsd.php',
        'ApiSerializable' => __DIR__ . '/includes/api/ApiSerializable.php',
        'ApiSetNotificationTimestamp' => __DIR__ . 
'/includes/api/ApiSetNotificationTimestamp.php',
+       'ApiSetPageLanguage' => __DIR__ . 
'/includes/api/ApiSetPageLanguage.php',
        'ApiStashEdit' => __DIR__ . '/includes/api/ApiStashEdit.php',
        'ApiTag' => __DIR__ . '/includes/api/ApiTag.php',
        'ApiTokens' => __DIR__ . '/includes/api/ApiTokens.php',
diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php
index 4220fb8..52f1d95 100644
--- a/includes/api/ApiMain.php
+++ b/includes/api/ApiMain.php
@@ -106,6 +106,7 @@
                'managetags' => 'ApiManageTags',
                'tag' => 'ApiTag',
                'mergehistory' => 'ApiMergeHistory',
+               'setpagelanguage' => 'ApiSetPageLanguage',
        ];
 
        /**
diff --git a/includes/api/ApiSetPageLanguage.php 
b/includes/api/ApiSetPageLanguage.php
new file mode 100755
index 0000000..3f03c02
--- /dev/null
+++ b/includes/api/ApiSetPageLanguage.php
@@ -0,0 +1,147 @@
+<?php
+/**
+ *
+ *
+ * Created on January 1, 2017
+ *
+ * Copyright © 2017 Justin Du "<justin.d...@gmail.com>"
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * API module that facilitates changing the language of a page.
+ * The API equivalent of SpecialPageLanguage.
+ * Requires API write mode to be enabled.
+ *
+ * @ingroup API
+ */
+class ApiSetPageLanguage extends ApiBase {
+       // Check if change language feature is enabled
+       protected function getDescriptionMessage() {
+               if ( !$this->getConfig()->get( 'PageLanguageUseDB' ) ) {
+                       return 'apihelp-setpagelanguage-description-disabled';
+               }
+               return parent::getDescriptionMessage();
+       }
+
+       /**
+        * Extracts the title and language from the request parameters and 
invokes
+        * the static SpecialPageLanguage::changePageLanguage() function with 
these as arguments.
+        * If the language change succeeds, the title, old language, and new 
language
+        * of the article changed, as well as the performer of the language 
change
+        * are added to the result object.
+        */
+       public function execute() {
+               // Check if change language feature is enabled
+               if ( !$this->getConfig()->get( 'PageLanguageUseDB' ) ) {
+                       $this->dieWithError( 'apierror-pagelang-disabled' );
+               }
+
+               // Check if the user has permissions
+               $this->checkUserRightsAny( 'pagelang' );
+
+               $this->useTransactionalTimeLimit();
+
+               $params = $this->extractRequestParams();
+
+               $pageObj = $this->getTitleOrPageId( $params, 'fromdbmaster' );
+               if ( !$pageObj->exists() ) {
+                       $this->dieWithError( 'apierror-missingtitle' );
+               }
+
+               $titleObj = $pageObj->getTitle();
+               $user = $this->getUser();
+
+               // Check that the user is allowed to edit the page
+               $this->checkTitleUserPermissions( $titleObj, 'edit' );
+
+               // If change tagging was requested, check that the user is 
allowed to tag,
+               // and the tags are valid
+               if ( count( $params['tags'] ) ) {
+                       $tagStatus = ChangeTags::canAddTagsAccompanyingChange( 
$params['tags'], $user );
+                       if ( !$tagStatus->isOK() ) {
+                               $this->dieStatus( $tagStatus );
+                       }
+               }
+
+               $status = SpecialPageLanguage::changePageLanguage(
+                       $this,
+                       $titleObj,
+                       $params['lang'],
+                       $params['tags'] ?: []
+               );
+
+               if ( !$status->isOK() ) {
+                       $this->dieStatus( $status );
+               }
+
+               $r = [
+                       'title' => $titleObj->getPrefixedText(),
+                       'oldlanguage' => $status->value->oldLanguage,
+                       'newlanguage' => $status->value->newLanguage,
+                       'logid' => $status->value->logId
+               ];
+               $this->getResult()->addValue( null, $this->getModuleName(), $r 
);
+       }
+
+       public function mustBePosted() {
+               return true;
+       }
+
+       public function isWriteMode() {
+               return true;
+       }
+
+       public function getAllowedParams() {
+               return [
+                       'title' => null,
+                       'pageid' => [
+                               ApiBase::PARAM_TYPE => 'integer'
+                       ],
+                       'lang' => [
+                               ApiBase::PARAM_TYPE => array_merge(
+                                       [ 'default' ],
+                                       array_keys( 
Language::fetchLanguageNames( null, 'mwfile' ) )
+                               ),
+                               ApiBase::PARAM_REQUIRED => true,
+                       ],
+                       'tags' => [
+                               ApiBase::PARAM_TYPE => 'tags',
+                               ApiBase::PARAM_ISMULTI => true,
+                       ],
+               ];
+       }
+
+       public function needsToken() {
+               return 'csrf';
+       }
+
+       protected function getExamplesMessages() {
+               return [
+                       
'action=setpagelanguage&title=Main%20Page&lang=eu&token=123ABC'
+                               => 'apihelp-setpagelanguage-example-language',
+                       
'action=setpagelanguage&pageid=123&lang=default&token=123ABC'
+                               => 'apihelp-setpagelanguage-example-default',
+               ];
+       }
+
+       public function getHelpUrls() {
+               return 'https://www.mediawiki.org/wiki/API:SetPageLanguage';
+       }
+}
diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json
index bc9fbf6..4b6e932 100644
--- a/includes/api/i18n/en.json
+++ b/includes/api/i18n/en.json
@@ -1353,6 +1353,15 @@
        "apihelp-setnotificationtimestamp-example-pagetimestamp": "Set the 
notification timestamp for <kbd>Main page</kbd> so all edits since 1 January 
2012 are unviewed.",
        "apihelp-setnotificationtimestamp-example-allpages": "Reset the 
notification status for pages in the <kbd>{{ns:user}}</kbd> namespace.",
 
+       "apihelp-setpagelanguage-description": "Change the language of a page.",
+       "apihelp-setpagelanguage-description-disabled": "Changing the language 
of a page is not allowed on this wiki.\n\nEnable 
<var>[[mw:Manual:$wgPageLanguageUseDB|$wgPageLanguageUseDB]]</var> to use the 
API.",
+       "apihelp-setpagelanguage-param-title": "Title of the page whose 
language you wish to change. Cannot be used together with <var>$1pageid</var>.",
+       "apihelp-setpagelanguage-param-pageid": "Page ID of the page whose 
language you wish to change. Cannot be used together with <var>$1title</var>.",
+       "apihelp-setpagelanguage-param-lang": "Language code of the language to 
change the page to. Use <kbd>default</kbd> to reset the page to the wiki's 
default content language.",
+       "apihelp-setpagelanguage-param-tags": "Change tags to apply to the log 
entry resulting from this action.",
+       "apihelp-setpagelanguage-example-language": "Change the language of 
<kbd>Main Page</kbd> to Basque.",
+       "apihelp-setpagelanguage-example-default": "Change the language of the 
page with ID 123 to the wiki's default content language.",
+
        "apihelp-stashedit-description": "Prepare an edit in shared 
cache.\n\nThis is intended to be used via AJAX from the edit form to improve 
the performance of the page save.",
        "apihelp-stashedit-param-title": "Title of the page being edited.",
        "apihelp-stashedit-param-section": "Section number. <kbd>0</kbd> for 
the top section, <kbd>new</kbd> for a new section.",
@@ -1673,6 +1682,7 @@
        "apierror-opensearch-json-warnings": "Warnings cannot be represented in 
OpenSearch JSON format.",
        "apierror-pagecannotexist": "Namespace doesn't allow actual pages.",
        "apierror-pagedeleted": "The page has been deleted since you fetched 
its timestamp.",
+       "apierror-pagelang-disabled": "Changing the language of a page is not 
allowed on this wiki.",
        "apierror-paramempty": "The parameter <var>$1</var> may not be empty.",
        "apierror-parsetree-notwikitext": "<kbd>prop=parsetree</kbd> is only 
supported for wikitext content.",
        "apierror-parsetree-notwikitext-title": "<kbd>prop=parsetree</kbd> is 
only supported for wikitext content. $1 uses content model $2.",
diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json
index 9d467cc..662020b 100644
--- a/includes/api/i18n/qqq.json
+++ b/includes/api/i18n/qqq.json
@@ -1261,6 +1261,14 @@
        "apihelp-setnotificationtimestamp-example-page": 
"{{doc-apihelp-example|setnotificationtimestamp}}",
        "apihelp-setnotificationtimestamp-example-pagetimestamp": 
"{{doc-apihelp-example|setnotificationtimestamp}}",
        "apihelp-setnotificationtimestamp-example-allpages": 
"{{doc-apihelp-example|setnotificationtimestamp}}",
+       "apihelp-setpagelanguage-description": 
"{{doc-apihelp-description|setpagelanguage}}",
+       "apihelp-setpagelanguage-description-disabled": 
"{{doc-apihelp-description|setpagelanguage|info=This message is used when 
changing the language of a page is not allowed on the wiki because 
<var>[[mw:Manual:$wgPageLanguageUseDB|$wgPageLanguageUseDB]]</var> is not 
enabled.|seealso={{msg-mw|apihelp-setpagelanguage-description}}}}",
+       "apihelp-setpagelanguage-param-title": 
"{{doc-apihelp-param|setpagelanguage|title}}",
+       "apihelp-setpagelanguage-param-pageid": 
"{{doc-apihelp-param|setpagelanguage|pageid}}",
+       "apihelp-setpagelanguage-param-lang": 
"{{doc-apihelp-param|setpagelanguage|lang}}",
+       "apihelp-setpagelanguage-param-tags": 
"{{doc-apihelp-param|setpagelanguage|tags}}",
+       "apihelp-setpagelanguage-example-language": 
"{{doc-apihelp-example|setpagelanguage}}",
+       "apihelp-setpagelanguage-example-default": 
"{{doc-apihelp-example|setpagelanguage}}",
        "apihelp-stashedit-description": 
"{{doc-apihelp-description|stashedit}}",
        "apihelp-stashedit-param-title": 
"{{doc-apihelp-param|stashedit|title}}",
        "apihelp-stashedit-param-section": 
"{{doc-apihelp-param|stashedit|section}}",
@@ -1566,6 +1574,7 @@
        "apierror-opensearch-json-warnings": "{{doc-apierror}}",
        "apierror-pagecannotexist": "{{doc-apierror}}",
        "apierror-pagedeleted": "{{doc-apierror}}",
+       "apierror-pagelang-disabled": "{{doc-apierror}}",
        "apierror-paramempty": "{{doc-apierror}}\n\nParameters:\n* $1 - 
Parameter name.",
        "apierror-parsetree-notwikitext": "{{doc-apierror}}",
        "apierror-parsetree-notwikitext-title": 
"{{doc-apierror}}\n\nParameters:\n* $1 - Page title.\n* $2 - Content model.",
diff --git a/includes/specials/SpecialPageLanguage.php 
b/includes/specials/SpecialPageLanguage.php
index 61b6a8c..55ae692 100644
--- a/includes/specials/SpecialPageLanguage.php
+++ b/includes/specials/SpecialPageLanguage.php
@@ -111,68 +111,99 @@
        /**
         *
         * @param array $data
-        * @return bool
+        * @return Status
         */
        public function onSubmit( array $data ) {
-               $title = Title::newFromText( $data['pagename'] );
+               $pageName = $data['pagename'];
 
-               // Check if title is valid
-               if ( !$title ) {
-                       return false;
+               // Check if user wants to use default language
+               if ( $data['selectoptions'] == 1 ) {
+                       $newLanguage = 'default';
+               } else {
+                       $newLanguage = $data['language'];
                }
 
+               try {
+                       $title = Title::newFromTextThrow( $pageName );
+               } catch ( MalformedTitleException $ex ) {
+                       return Status::newFatal( $ex->getMessageObject() );
+               }
+
+               // Url to redirect to after the operation
+               $this->goToUrl = $title->getFullURL();
+
+               return self::changePageLanguage( $this->getContext(), $title, 
$newLanguage );
+       }
+
+       /**
+        * @param IContextSource $context
+        * @param Title $title
+        * @param string $newLanguage Language code
+        * @param array $tags Change tags to apply to the log entry
+        * @return Status
+        */
+       public static function changePageLanguage( IContextSource $context, 
Title $title,
+               $newLanguage, array $tags = [] ) {
                // Get the default language for the wiki
-               $defLang = $this->getConfig()->get( 'LanguageCode' );
+               $defLang = $context->getConfig()->get( 'LanguageCode' );
 
                $pageId = $title->getArticleID();
 
                // Check if article exists
                if ( !$pageId ) {
-                       return false;
+                       return Status::newFatal(
+                               'pagelang-nonexistent-page',
+                               wfEscapeWikiText( $title->getPrefixedText() )
+                       );
                }
 
                // Load the page language from DB
                $dbw = wfGetDB( DB_MASTER );
-               $langOld = $dbw->selectField(
+               $oldLanguage = $dbw->selectField(
                        'page',
                        'page_lang',
                        [ 'page_id' => $pageId ],
                        __METHOD__
                );
 
-               // Url to redirect to after the operation
-               $this->goToUrl = $title->getFullURL();
-
-               // Check if user wants to use default language
-               if ( $data['selectoptions'] == 1 ) {
-                       $langNew = null;
-               } else {
-                       $langNew = $data['language'];
+               // Check if user wants to use the default language
+               if ( $newLanguage === 'default' ) {
+                       $newLanguage = null;
                }
 
                // No change in language
-               if ( $langNew === $langOld ) {
-                       return false;
+               if ( $newLanguage === $oldLanguage ) {
+                       // Check if old language does not exist
+                       if ( !$oldLanguage ) {
+                               return Status::newFatal(
+                                       'pagelang-unchanged-language-default',
+                                       wfEscapeWikiText( 
$title->getPrefixedText() )
+                               );
+                       }
+                       return Status::newFatal(
+                               'pagelang-unchanged-language',
+                               wfEscapeWikiText( $title->getPrefixedText() ),
+                               $oldLanguage
+                       );
                }
 
                // Hardcoded [def] if the language is set to null
-               $logOld = $langOld ? $langOld : $defLang . '[def]';
-               $logNew = $langNew ? $langNew : $defLang . '[def]';
+               $logOld = $oldLanguage ? $oldLanguage : $defLang . '[def]';
+               $logNew = $newLanguage ? $newLanguage : $defLang . '[def]';
 
                // Writing new page language to database
-               $dbw = wfGetDB( DB_MASTER );
                $dbw->update(
                        'page',
-                       [ 'page_lang' => $langNew ],
+                       [ 'page_lang' => $newLanguage ],
                        [
                                'page_id' => $pageId,
-                               'page_lang' => $langOld
+                               'page_lang' => $oldLanguage
                        ],
                        __METHOD__
                );
 
                if ( !$dbw->affectedRows() ) {
-                       return false;
+                       return Status::newFatal( 'pagelang-db-failed' );
                }
 
                // Logging change of language
@@ -181,9 +212,10 @@
                        '5::newlanguage' => $logNew
                ];
                $entry = new ManualLogEntry( 'pagelang', 'pagelang' );
-               $entry->setPerformer( $this->getUser() );
+               $entry->setPerformer( $context->getUser() );
                $entry->setTarget( $title );
                $entry->setParameters( $logParams );
+               $entry->setTags( $tags );
 
                $logid = $entry->insert();
                $entry->publish( $logid );
@@ -191,7 +223,11 @@
                // Force re-render so that language-based content (parser 
functions etc.) gets updated
                $title->invalidateCache();
 
-               return true;
+               return Status::newGood( (object)[
+                       'oldLanguage' => $logOld,
+                       'newLanguage' => $logNew,
+                       'logId' => $logid,
+               ] );
        }
 
        public function onSuccess() {
diff --git a/languages/i18n/en.json b/languages/i18n/en.json
index f2b27fc..f31690c 100644
--- a/languages/i18n/en.json
+++ b/languages/i18n/en.json
@@ -4047,6 +4047,10 @@
        "pagelang-use-default": "Use default language",
        "pagelang-select-lang": "Select language",
        "pagelang-submit": "Submit",
+       "pagelang-nonexistent-page": "The page $1 does not exist.",
+       "pagelang-unchanged-language": "The page $1 is already set to language 
$2.",
+       "pagelang-unchanged-language-default": "The page $1 is already set to 
the wiki's default content language.",
+       "pagelang-db-failed": "The database failed to change the page 
language.",
        "right-pagelang": "Change page language",
        "action-pagelang": "change the page language",
        "log-name-pagelang": "Language change log",
diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json
index 99f7679..6eba2e2 100644
--- a/languages/i18n/qqq.json
+++ b/languages/i18n/qqq.json
@@ -4231,6 +4231,10 @@
        "pagelang-use-default": "Radio label for selector on 
Special:PageLanguage for default language",
        "pagelang-select-lang": "Radio label for selector on 
Special:PageLanguage for language selection\n{{Identical|Select language}}",
        "pagelang-submit": "Submit button label for Special:PageLanguage 
form\n{{Identical|Submit}}",
+       "pagelang-nonexistent-page": "Error message shown when the page the 
user is trying to change the language on does not exist.\n\nParameters:\n* $1 - 
the title of the nonexistent page",
+       "pagelang-unchanged-language": "Error message shown when the language 
the user is trying to change the page to and the current language the page is 
in are the same.\n\nParameters:\n* $1 - the title of the target page\n* $2 - 
the current language of the page",
+       "pagelang-unchanged-language-default": "Error message shown when the 
language the user is trying to change the page to is already the wiki's default 
content language.\n\nParameters:\n* $1 - the title of the target page",
+       "pagelang-db-failed": "Error message shown when the database fails to 
update the language of the page",
        "right-pagelang": "{{Doc-right|pagelang}}\nRight to change page 
language on Special:PageLanguage",
        "action-pagelang": "{{Doc-action|pagelang}}",
        "log-name-pagelang": "Display entry for log name for changes in page 
language in Special:Log.",

-- 
To view, visit https://gerrit.wikimedia.org/r/330340
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I42e74ed3bcd0bfa9ec0c344ba67668210450c975
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: MtDu <justin.d...@gmail.com>
Gerrit-Reviewer: Anomie <bjor...@wikimedia.org>
Gerrit-Reviewer: MtDu <justin.d...@gmail.com>
Gerrit-Reviewer: TTO <at.li...@live.com.au>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to