will still be blocked.
* The resetpassword right and associated password reset capture feature has
been removed.
+ * The $error parameter to the EmailUser hook should be set to a Status object
+ or boolean false. This should be compatible with at least MediaWiki 1.23 if
+ not earlier. Returning a raw HTML string is now deprecated.
+ * The $message parameter to the ApiCheckCanExecute hook should be set to an
+ ApiMessage. This is compatible with MediaWiki 1.27 and later. Returning a
+ code for ApiBase::parseMsg() will no longer work.
+ * ApiBase::$messageMap is no longer public. Code attempting to access it will
+ result in a PHP fatal error.
=== New features in 1.29 ===
* (T5233) A cookie can now be set when a user is autoblocked, to track that user if
body instead.
* The capture option for action=resetpassword has been removed
* action=clearhasmsg now requires a POST.
+ * (T47843) API errors and warnings may be requested in non-English languages
+ using the new 'errorformat', 'errorlang', and 'errorsuselocal' parameters.
+ * API error codes may have changed. Most notably, errors from modules using
+ parameter prefixes (e.g. all query submodules) will no longer be prefixed.
+ * action=emailuser may return a "Warnings" status, and now returns 'warnings' and
+ 'errors' subelements (as applicable) instead of 'message'.
+ * action=imagerotate returns an 'errors' subelement rather than 'errormessage'.
+ * action=move now reports errors when moving the talk page as an array under
+ key 'talkmove-errors', rather than using 'talkmove-error-code' and
+ 'talkmove-error-info'. The format for subpage move errors has also changed.
+ * action=rollback no longer returns a "messageHtml" property on errors. Use
+ errorformat=html if you're wanting HTML formatting of messages.
+ * action=upload now reports optional stash failures as an array under key
+ 'stasherrors' rather than a 'stashfailed' text string.
+ * action=watch reports 'errors' and 'warnings' instead of a single 'error'.
=== Action API internal changes in 1.29 ===
+ * New methods were added to ApiBase to handle errors and warnings using i18n
+ keys. Methods for using hard-coded English messages were deprecated:
+ * ApiBase::dieUsage() was deprecated
+ * ApiBase::dieUsageMsg() was deprecated
+ * ApiBase::dieUsageMsgOrDebug() was deprecated
+ * ApiBase::getErrorFromStatus() was deprecated
+ * ApiBase::parseMsg() was deprecated
+ * ApiBase::setWarning() was deprecated
+ * ApiBase::$messageMap is no longer public. Code attempting to access it will
+ result in a PHP fatal error.
+ * The $message parameter to the ApiCheckCanExecute hook should be set to an
+ ApiMessage. This is compatible with MediaWiki 1.27 and later. Returning a
+ code for ApiBase::parseMsg() will no longer work.
+ * UsageException is deprecated in favor of ApiUsageException. For the time
+ being ApiUsageException is a subclass of UsageException to allow things that
+ catch only UsageException to still function properly.
+ * If, for some strange reason, code was using an ApiErrorFormatter instead of
+ ApiErrorFormatter_BackCompat, note that the result format has changed and
+ various methods now take a module path rather than a module name.
+ * ApiMessageTrait::getApiCode() now strips 'apierror-' and 'apiwarn-' prefixes
+ from the message key, and maps some message keys for backwards compatibility.
=== Languages updated in 1.29 ===
required as all sessions are stored in Object Cache now.
* MWHttpRequest::execute() should be considered to return a StatusValue; the
Status return type is deprecated.
+* User::edits() (deprecated in 1.21) was removed.
+* Xml::escapeJsString() (deprecated in 1.21) was removed.
+* Article::getText() and Article::prepareTextForEdit() (deprecated in 1.21)
+ were removed.
+* Article::getAutosummary() and WikiPage::getAutosummary (deprecated in 1.21)
+ were removed.
+* Hooks ArticleViewCustom, EditPageGetDiffText and ShowRawCssJs (deprecated in 1.21)
+ were removed.
+* Class RevisiondeleteAction (deprecated in 1.25) was removed.
== Compatibility ==
'ApiUnblock' => __DIR__ . '/includes/api/ApiUnblock.php',
'ApiUndelete' => __DIR__ . '/includes/api/ApiUndelete.php',
'ApiUpload' => __DIR__ . '/includes/api/ApiUpload.php',
+ 'ApiUsageException' => __DIR__ . '/includes/api/ApiUsageException.php',
'ApiUserrights' => __DIR__ . '/includes/api/ApiUserrights.php',
'ApiWatch' => __DIR__ . '/includes/api/ApiWatch.php',
'ArchivedFile' => __DIR__ . '/includes/filerepo/file/ArchivedFile.php',
'ExplodeIterator' => __DIR__ . '/includes/libs/ExplodeIterator.php',
'ExportProgressFilter' => __DIR__ . '/maintenance/backup.inc',
'ExportSites' => __DIR__ . '/maintenance/exportSites.php',
+ 'ExtensionJsonValidationError' => __DIR__ . '/includes/registration/ExtensionJsonValidationError.php',
+ 'ExtensionJsonValidator' => __DIR__ . '/includes/registration/ExtensionJsonValidator.php',
'ExtensionLanguages' => __DIR__ . '/maintenance/language/languages.inc',
'ExtensionProcessor' => __DIR__ . '/includes/registration/ExtensionProcessor.php',
'ExtensionRegistry' => __DIR__ . '/includes/registration/ExtensionRegistry.php',
'ResourceLoaderSpecialCharacterDataModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderSpecialCharacterDataModule.php',
'ResourceLoaderStartUpModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderStartUpModule.php',
'ResourceLoaderUploadDialogModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUploadDialogModule.php',
- 'ResourceLoaderUserCSSPrefsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserCSSPrefsModule.php',
'ResourceLoaderUserDefaultsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserDefaultsModule.php',
'ResourceLoaderUserModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserModule.php',
'ResourceLoaderUserOptionsModule' => __DIR__ . '/includes/resourceloader/ResourceLoaderUserOptionsModule.php',
'RevisionItemBase' => __DIR__ . '/includes/RevisionList.php',
'RevisionList' => __DIR__ . '/includes/RevisionList.php',
'RevisionListBase' => __DIR__ . '/includes/RevisionList.php',
- 'RevisiondeleteAction' => __DIR__ . '/includes/actions/RevisiondeleteAction.php',
'RiffExtractor' => __DIR__ . '/includes/libs/RiffExtractor.php',
'RightsLogFormatter' => __DIR__ . '/includes/logging/RightsLogFormatter.php',
'RollbackAction' => __DIR__ . '/includes/actions/RollbackAction.php',
'UploadStashWrongOwnerException' => __DIR__ . '/includes/upload/UploadStash.php',
'UploadStashZeroLengthFileException' => __DIR__ . '/includes/upload/UploadStash.php',
'UppercaseCollation' => __DIR__ . '/includes/collation/UppercaseCollation.php',
- 'UsageException' => __DIR__ . '/includes/api/ApiMain.php',
+ 'UsageException' => __DIR__ . '/includes/api/ApiUsageException.php',
'User' => __DIR__ . '/includes/user/User.php',
'UserArray' => __DIR__ . '/includes/user/UserArray.php',
'UserArrayFromResult' => __DIR__ . '/includes/user/UserArrayFromResult.php',
false and set a message to cancel the request.
$module: Module object
$user: Current user
- &$message: API usage message to die with, as a message key or array
- as accepted by ApiBase::dieUsageMsg.
+ &$message: API message to die with. Specific values accepted depend on the
+ MediaWiki version:
+ * 1.29+: IApiMessage, Message, string message key, or key+parameters array to
+ pass to ApiBase::dieWithError().
+ * 1.27+: IApiMessage, or a key or key+parameters in ApiBase::$messageMap.
+ * Earlier: A key or key+parameters in ApiBase::$messageMap.
'APIEditBeforeSave': DEPRECATED! Use EditFilterMergedContent instead.
Before saving a page with api.php?action=edit, after
&$sectionanchor: The section anchor link (e.g. "#overview" )
&$extraq: Extra query parameters which can be added via hooked functions
-'ArticleViewCustom': DEPRECATED! Use ArticleContentViewCustom instead.
-Allows to output the text of the article in a different format than wikitext.
-Note that it is preferable to implement proper handing for a custom data type
-using the ContentHandler facility.
-$text: text of the page
-$title: title of the page
-$output: reference to $wgOut
-
'ArticleViewFooter': After showing the footer section of an ordinary page view
$article: Article object
$patrolFooterShown: boolean whether patrol footer is shown
$editPage: EditPage object
&$newtext: wikitext that will be used as "your version"
-'EditPageGetDiffText': DEPRECATED! Use EditPageGetDiffContent instead.
-Allow modifying the wikitext that will be used in "Show changes". Note that it
-is preferable to implement diff handling for different data types using the
-ContentHandler facility.
-$editPage: EditPage object
-&$newtext: wikitext that will be used as "your version"
-
'EditPageGetPreviewContent': Allow modifying the wikitext that will be
previewed. Note that it is preferable to implement previews for different data
types using the ContentHandler facility.
&$from: MailAddress object of sending user
&$subject: subject of the mail
&$text: text of the mail
- &$error: Out-param for an error
+ &$error: Out-param for an error. Should be set to a Status object or boolean false.
'EmailUserCC': Before sending the copy of the email to the author.
&$to: MailAddress object of receiving user
'PasswordPoliciesForUser': Alter the effective password policy for a user.
$user: User object whose policy you are modifying
&$effectivePolicy: Array of policy statements that apply to this user
-$purpose: string indicating purpose of the check, one of 'login', 'create',
- or 'reset'
'PerformRetroactiveAutoblock': Called before a retroactive autoblock is applied
to a user.
'ShowMissingArticle': Called when generating the output for a non-existent page.
$article: The article object corresponding to the page
-'ShowRawCssJs': DEPRECATED! Use the ContentGetParserOutput hook instead.
-Customise the output of raw CSS and JavaScript in page views.
-$text: Text being shown
-$title: Title of the custom script/stylesheet page
-$output: Current OutputPage object
-
'ShowSearchHit': Customize display of search hit.
$searchPage: The SpecialSearch instance.
$result: The SearchResult to show
}
protected function getFormFields() {
+ $linkRenderer = $this->getLinkRenderer();
return [
'From' => [
'type' => 'info',
'raw' => 1,
- 'default' => Linker::link(
+ 'default' => $linkRenderer->makeLink(
$this->getUser()->getUserPage(),
- htmlspecialchars( $this->getUser()->getName() )
+ $this->getUser()->getName()
),
'label-message' => 'emailfrom',
'id' => 'mw-emailuser-sender',
'To' => [
'type' => 'info',
'raw' => 1,
- 'default' => Linker::link(
+ 'default' => $linkRenderer->makeLink(
$this->mTargetObj->getUserPage(),
- htmlspecialchars( $this->mTargetObj->getName() )
+ $this->mTargetObj->getName()
),
'label-message' => 'emailto',
'id' => 'mw-emailuser-recipient',
* @since 1.20
* @param array $data
* @param HTMLForm $form
- * @return Status|string|bool
+ * @return Status|bool
*/
public static function uiSubmit( array $data, HTMLForm $form ) {
return self::submit( $data, $form->getContext() );
*
* @param array $data
* @param IContextSource $context
- * @return Status|string|bool Status object, or potentially a String on error
- * or maybe even true on success if anything uses the EmailUser hook.
+ * @return Status|bool
*/
public static function submit( array $data, IContextSource $context ) {
$config = $context->getConfig();
$target = self::getTarget( $data['Target'] );
if ( !$target instanceof User ) {
// Messages used here: notargettext, noemailtext, nowikiemailtext
- return $context->msg( $target . 'text' )->parseAsBlock();
+ return Status::newFatal( $target . 'text' );
}
$to = MailAddress::newFromUser( $target );
$text .= $context->msg( 'emailuserfooter',
$from->name, $to->name )->inContentLanguage()->text();
- $error = '';
+ $error = false;
if ( !Hooks::run( 'EmailUser', [ &$to, &$from, &$subject, &$text, &$error ] ) ) {
- return $error;
+ if ( $error instanceof Status ) {
+ return $error;
+ } elseif ( $error === false || $error === '' || $error === [] ) {
+ // Possibly to tell HTMLForm to pretend there was no submission?
+ return false;
+ } elseif ( $error === true ) {
+ // Hook sent the mail itself and indicates success?
+ return Status::newGood();
+ } elseif ( is_array( $error ) ) {
+ $status = Status::newGood();
+ foreach ( $error as $e ) {
+ $status->fatal( $e );
+ }
+ return $status;
+ } elseif ( $error instanceof MessageSpecifier ) {
+ return Status::newFatal( $error );
+ } else {
+ // Ugh. Either a raw HTML string, or something that's supposed
+ // to be treated like one.
+ $type = is_object( $error ) ? get_class( $error ) : gettype( $error );
+ wfDeprecated( "EmailUser hook returning a $type as \$error", '1.29' );
+ return Status::newFatal( new ApiRawMessage(
+ [ '$1', Message::rawParam( (string)$error ) ], 'hookaborted'
+ ) );
+ }
}
if ( $config->get( 'UserEmailUseReplyTo' ) ) {
$fields['Target']['type'] = 'hidden';
switch ( $type ) {
case Block::TYPE_IP:
- $fields['Name']['default'] = Linker::linkKnown(
+ $fields['Name']['default'] = $this->getLinkRenderer()->makeKnownLink(
SpecialPage::getTitleFor( 'Contributions', $target->getName() ),
$target->getName()
);
$fields['Name']['raw'] = true;
break;
case Block::TYPE_USER:
- $fields['Name']['default'] = Linker::link(
+ $fields['Name']['default'] = $this->getLinkRenderer()->makeLink(
$target->getUserPage(),
$target->getName()
);
* @param array $data
* @param IContextSource $context
* @throws ErrorPageError
- * @return array|bool Array(message key, parameters) on failure, True on success
+ * @return array|bool Array( Array( message key, parameters ) ) on failure, True on success
*/
public static function processUnblock( array $data, IContextSource $context ) {
$performer = $context->getUser();
# Delete block
if ( !$block->delete() ) {
- return [ 'ipb_cant_unblock', htmlspecialchars( $block->getTarget() ) ];
+ return [ [ 'ipb_cant_unblock', htmlspecialchars( $block->getTarget() ) ] ];
}
# Unset _deleted fields as needed
"userrights-user-editname": "Enter a username:",
"editusergroup": "Load user groups",
"editinguser": "Changing user rights of {{GENDER:$1|user}} <strong>[[User:$1|$1]]</strong> $2",
+ "viewinguserrights": "Viewing user rights of {{GENDER:$1|user}} <strong>[[User:$1|$1]]</strong> $2",
"userrights-editusergroup": "Edit user groups",
+ "userrights-viewusergroup": "View user groups",
"saveusergroups": "Save {{GENDER:$1|user}} groups",
"userrights-groupsmember": "Member of:",
"userrights-groupsmember-auto": "Implicit member of:",
"action-upload_by_url": "upload this file from a URL",
"action-writeapi": "use the write API",
"action-delete": "delete this page",
- "action-deleterevision": "delete this revision",
- "action-deletedhistory": "view this page's deleted history",
+ "action-deleterevision": "delete revisions",
+ "action-deletelogentry": "delete log entries",
+ "action-deletedhistory": "view a page's deleted history",
+ "action-deletedtext": "view deleted revision text",
"action-browsearchive": "search deleted pages",
- "action-undelete": "undelete this page",
- "action-suppressrevision": "review and restore this hidden revision",
+ "action-undelete": "undelete pages",
+ "action-suppressrevision": "review and restore hidden revisions",
"action-suppressionlog": "view this private log",
"action-block": "block this user from editing",
"action-protect": "change protection levels for this page",
"action-userrights-interwiki": "edit user rights of users on other wikis",
"action-siteadmin": "lock or unlock the database",
"action-sendemail": "send emails",
+ "action-editmyoptions": "edit your preferences",
"action-editmywatchlist": "edit your watchlist",
"action-viewmywatchlist": "view your watchlist",
"action-viewmyprivateinfo": "view your private information",
"emailccsubject": "Copy of your message to $1: $2",
"emailsent": "Email sent",
"emailsenttext": "Your email message has been sent.",
- "emailuserfooter": "This email was {{GENDER:$1|sent}} by $1 to {{GENDER:$2|$2}} by the \"{{int:emailuser}}\" function at {{SITENAME}}.",
+ "emailuserfooter": "This email was {{GENDER:$1|sent}} by $1 to {{GENDER:$2|$2}} by the \"{{int:emailuser}}\" function at {{SITENAME}}. {{GENDER:$2|Your}} email will be sent directly to the {{GENDER:$1|original sender}}, revealing {{GENDER:$2|your}} email address to {{GENDER:$1|them}}.",
"usermessage-summary": "Leaving system message.",
"usermessage-editor": "System messenger",
"usermessage-template": "MediaWiki:UserMessage",
"usercssispublic": "Please note: CSS subpages should not contain confidential data as they are viewable by other users.",
"restrictionsfield-badip": "Invalid IP address or range: $1",
"restrictionsfield-label": "Allowed IP ranges:",
- "restrictionsfield-help": "One IP address or CIDR range per line. To enable everything, use<br><code>0.0.0.0/0</code><br><code>::/0</code>"
+ "restrictionsfield-help": "One IP address or CIDR range per line. To enable everything, use<br><code>0.0.0.0/0</code><br><code>::/0</code>",
+ "revid": "r$1",
+ "pageid": "page ID $1"
}
"october-gen": "{{doc-months|10|genitive}}\n{{Identical|October}}",
"november-gen": "{{doc-months|11|genitive}}\n{{Identical|November}}",
"december-gen": "{{doc-months|12|genitive}}\n{{Identical|December}}",
- "jan": "{{doc-months|1|short}}",
- "feb": "{{doc-months|2|short}}",
- "mar": "{{doc-months|3|short}}",
- "apr": "{{doc-months|4|short}}",
- "may": "{{doc-months|5|short}}",
- "jun": "{{doc-months|6|short}}",
+ "jan": "{{doc-months|1|short}}\n{{Identical|January}}",
+ "feb": "{{doc-months|2|short}}\n{{Identical|February}}",
+ "mar": "{{doc-months|3|short}}\n{{Identical|March}}",
+ "apr": "{{doc-months|4|short}}\n{{Identical|April}}",
+ "may": "{{doc-months|5|short}}\n{{Identical|May}}",
+ "jun": "{{doc-months|6|short}}\n{{Identical|June}}",
"jul": "{{doc-months|7|short}}",
"aug": "{{doc-months|8|short}}",
"sep": "{{doc-months|9|short}}",
"userrights-lookup-user": "Label text when managing user rights ([[Special:UserRights]])",
"userrights-user-editname": "Displayed on [[Special:UserRights]].",
"editusergroup": "Button name, in page [[Special:Userrights]], in the section named {{MediaWiki:userrights-lookup-user}}. The username or gender of the user is not known when this message is displayed.",
- "editinguser": "Appears on [[Special:UserRights]]. Parameters:\n* $1 - a plaintext username\n* $2 - user tool links. e.g. \"(Talk | contribs | block | send email)\"",
- "userrights-editusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER",
+ "editinguser": "Appears on [[Special:UserRights]]. Parameters:\n* $1 - a plaintext username\n* $2 - user tool links. e.g. \"(Talk | contribs | block | send email)\"\n\nRelated messages:\n* {{msg-mw|viewinguserrights}}",
+ "viewinguserrights": "Appears on [[Special:UserRights]]. Parameters:\n* $1 - a plaintext username\n* $2 - user tool links. e.g. \"(Talk | contribs | block | send email)\"\n\nRelated messages:\n* {{msg-mw|editinguser}}",
+ "userrights-editusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER\n\nRelated messages:\n* {{msg-mw|userrights-viewusergroup}}",
+ "userrights-viewusergroup": "Parameter:\n* $1 - (Optional) a username, can be used for GENDER\n\nRelated messages:\n* {{msg-mw|userrights-editusergroup}}",
"saveusergroups": "Button text when editing user groups.\nParameters:\n* $1 - username, for GENDER support",
"userrights-groupsmember": "Used when editing user groups in [[Special:Userrights]].\n\nThe message is followed by a list of group names.\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER",
"userrights-groupsmember-auto": "Used when editing user groups in [[Special:Userrights]]. The message is followed by a list of group names.\n\n\"Implicit\" is for groups that the user was automatically added to (such as \"autoconfirmed\"); cf. {{msg-mw|userrights-groupsmember}}\n\nParameters:\n* $1 - (Optional) the number of items in the list following the message, for PLURAL\n* $2 - (Optional) the user name, for GENDER",
"action-delete": "{{Doc-action|delete}}",
"action-deleterevision": "{{Doc-action|deleterevision}}",
"action-deletedhistory": "{{Doc-action|deletedhistory}}",
+ "action-deletedtext": "{{Doc-action|deletedtext}}",
+ "action-deletelogentry": "{{Doc-action|deletelogentry}}",
"action-browsearchive": "{{Doc-action|browsearchive}}",
"action-undelete": "{{Doc-action|undelete}}",
"action-suppressrevision": "{{Doc-action|suppressrevision}}",
"action-sendemail": "{{doc-action|sendemail}}\n{{Identical|E-mail}}",
"action-editmywatchlist": "{{doc-action|editmywatchlist}}\n{{Identical|Edit your watchlist}}",
"action-viewmywatchlist": "{{doc-action|viewmywatchlist}}\n{{Identical|View your watchlist}}",
+ "action-editmyoptions": "{{Doc-action|editmyoptions}}",
"action-viewmyprivateinfo": "{{doc-action|viewmyprivateinfo}}",
"action-editmyprivateinfo": "{{doc-action|editmyprivateinfo}}",
"action-editcontentmodel": "{{doc-action|editcontentmodel}}",
"usercssispublic": "A reminder to users that CSS subpages are not preferences but normal pages, and thus can be viewed by other users and the general public. This message is shown to a user whenever they are editing a subpage in their own user-space that ends in .css. See also {{msg-mw|userjsispublic}}",
"restrictionsfield-badip": "An error message shown when one entered an invalid IP address or range in a restrictions field (such as Special:BotPassword). $1 is the IP address.",
"restrictionsfield-label": "Field label shown for restriction fields (e.g. on Special:BotPassword).",
- "restrictionsfield-help": "Placeholder text displayed in restriction fields (e.g. on Special:BotPassword)."
+ "restrictionsfield-help": "Placeholder text displayed in restriction fields (e.g. on Special:BotPassword).",
+ "revid": "Used to format a revision ID number in text. Parameters:\n* $1 - Revision ID number.",
+ "pageid": "Used to format a page ID number in text. Parameters:\n* $1 - Page ID number."
}