Localisation updates from https://translatewiki.net.
[mediawiki.git] / resources / src / mediawiki.ForeignApi / mediawiki.ForeignApi.core.js
blobf2437d7705e6d96dcfc5bbddabedfbdee0926f8e
1 module.exports = ( function () {
3         /**
4          * @classdesc Interact with the API of another MediaWiki site. mw.Foreign API creates
5          * an object like {@link mw.Api}, but automatically handle everything required to communicate
6          * with another MediaWiki wiki via cross-origin requests (CORS).
7          *
8          * The foreign wiki must be configured to accept requests from the current wiki. See
9          * <https://www.mediawiki.org/wiki/Manual:$wgCrossSiteAJAXdomains> for details.
10          * ```
11          * const api = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' );
12          * api.get( {
13          *     action: 'query',
14          *     meta: 'userinfo'
15          * } ).done( function ( data ) {
16          *     console.log( data );
17          * } );
18          * ```
19          *
20          * To ensure that the user at the foreign wiki is logged in, pass the `assert: 'user'` parameter
21          * to {@link mw.ForeignApi#get get()}/{@link mw.ForeignApi#post post()} (since MW 1.23), otherwise
22          * the API request will fail. (Note that this doesn't guarantee that it's the same user. To assert
23          * that the user at the foreign wiki has a specific username, pass the `assertuser` parameter with
24          * the desired username.)
25          *
26          * Authentication-related MediaWiki extensions may extend this class to ensure that the user
27          * authenticated on the current wiki will be automatically authenticated on the foreign one. These
28          * extension modules should be registered using the ResourceLoaderForeignApiModules hook. See
29          * CentralAuth for a practical example. The general pattern to extend and override the name is:
30          * ```
31          * function MyForeignApi() {};
32          * OO.inheritClass( MyForeignApi, mw.ForeignApi );
33          * mw.ForeignApi = MyForeignApi;
34          * ```
35          *
36          * @class mw.ForeignApi
37          * @extends mw.Api
38          * @since 1.26
39          *
40          * @constructor
41          * @description Create an instance of `mw.ForeignApi`.
42          * @param {string} url URL pointing to another wiki's `api.php` endpoint.
43          * @param {mw.Api.Options} [options] Also accepts all the options from {@link mw.Api.Options}.
44          * @param {boolean} [options.anonymous=false] Perform all requests anonymously. Use this option if
45          *     the target wiki may otherwise not accept cross-origin requests, or if you don't need to
46          *     perform write actions or read restricted information and want to avoid the overhead.
47          *
48          * @author Bartosz DziewoƄski
49          * @author Jon Robson
50          */
51         function CoreForeignApi( url, options ) {
52                 if ( !url || $.isPlainObject( url ) ) {
53                         throw new Error( 'mw.ForeignApi() requires a `url` parameter' );
54                 }
56                 this.apiUrl = String( url );
57                 this.anonymous = options && options.anonymous;
59                 options = $.extend( /* deep= */ true,
60                         {
61                                 ajax: {
62                                         url: this.apiUrl,
63                                         xhrFields: {
64                                                 withCredentials: !this.anonymous
65                                         }
66                                 },
67                                 parameters: {
68                                         origin: this.getOrigin()
69                                 }
70                         },
71                         options
72                 );
74                 // Call parent constructor
75                 CoreForeignApi.super.call( this, options );
76         }
78         OO.inheritClass( CoreForeignApi, mw.Api );
80         /**
81          * Return the origin to use for API requests, in the required format (protocol, host and port, if
82          * any).
83          *
84          * @memberof mw.ForeignApi.prototype
85          * @protected
86          * @return {string|undefined}
87          */
88         CoreForeignApi.prototype.getOrigin = function () {
89                 if ( this.anonymous ) {
90                         return '*';
91                 }
93                 const origin = location.origin;
94                 const apiOrigin = new URL( this.apiUrl, location.origin ).origin;
96                 if ( origin === apiOrigin ) {
97                         // requests are not cross-origin, omit parameter
98                         return undefined;
99                 }
101                 return origin;
102         };
104         /**
105          * @inheritdoc
106          */
107         CoreForeignApi.prototype.ajax = function ( parameters, ajaxOptions ) {
108                 let newAjaxOptions;
110                 // 'origin' query parameter must be part of the request URI, and not just POST request body
111                 if ( ajaxOptions.type === 'POST' ) {
112                         let url = ( ajaxOptions && ajaxOptions.url ) || this.defaults.ajax.url;
113                         const origin = ( parameters && parameters.origin ) || this.defaults.parameters.origin;
114                         if ( origin !== undefined ) {
115                                 url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' ) +
116                                         'origin=' + encodeURIComponent( origin );
117                         }
118                         newAjaxOptions = Object.assign( {}, ajaxOptions, { url: url } );
119                 } else {
120                         newAjaxOptions = ajaxOptions;
121                 }
123                 return CoreForeignApi.super.prototype.ajax.call( this, parameters, newAjaxOptions );
124         };
126         return CoreForeignApi;
127 }() );