@@ -171,6 +171,7 @@ export class CoreWSProvider {
171171
172172 /**
173173 * Call a Moodle WS using the AJAX API. Please use it if the WS layer is not an option.
174+ * It uses a cache to prevent duplicate requests.
174175 *
175176 * @param method The WebService method to be called.
176177 * @param data Arguments to pass to the method.
@@ -181,79 +182,19 @@ export class CoreWSProvider {
181182 * - available: 0 if unknown, 1 if available, -1 if not available.
182183 */
183184 callAjax ( method : string , data : any , preSets : CoreWSAjaxPreSets ) : Promise < any > {
184- let promise ;
185-
186- if ( typeof preSets . siteUrl == 'undefined' ) {
187- return rejectWithError ( this . createFakeWSError ( 'core.unexpectederror' , true ) ) ;
188- } else if ( ! this . appProvider . isOnline ( ) ) {
189- return rejectWithError ( this . createFakeWSError ( 'core.networkerrormsg' , true ) ) ;
190- }
191-
192- if ( typeof preSets . responseExpected == 'undefined' ) {
193- preSets . responseExpected = true ;
194- }
195-
196- const script = preSets . noLogin ? 'service-nologin.php' : 'service.php' ,
197- ajaxData = JSON . stringify ( [ {
198- index : 0 ,
199- methodname : method ,
200- args : this . convertValuesToString ( data )
201- } ] ) ;
185+ const cacheParams = {
186+ methodname : method ,
187+ args : data ,
188+ } ;
202189
203- // The info= parameter has no function. It is just to help with debugging.
204- // We call it info to match the parameter name use by Moodle's AMD ajax module.
205- let siteUrl = preSets . siteUrl + '/lib/ajax/' + script + '?info=' + method ;
190+ let promise = this . getPromiseHttp ( 'ajax' , preSets . siteUrl , cacheParams ) ;
206191
207- if ( preSets . noLogin && preSets . useGet ) {
208- // Send params using GET.
209- siteUrl += '&args=' + encodeURIComponent ( ajaxData ) ;
210- promise = this . http . get ( siteUrl ) . timeout ( this . getRequestTimeout ( ) ) . toPromise ( ) ;
211- } else {
212- promise = this . http . post ( siteUrl , ajaxData ) . timeout ( this . getRequestTimeout ( ) ) . toPromise ( ) ;
192+ if ( ! promise ) {
193+ promise = this . performAjax ( method , data , preSets ) ;
194+ promise = this . setPromiseHttp ( promise , 'ajax' , preSets . siteUrl , cacheParams ) ;
213195 }
214196
215- return promise . then ( ( data : any ) => {
216- // Some moodle web services return null.
217- // If the responseExpected value is set then so long as no data is returned, we create a blank object.
218- if ( ! data && ! preSets . responseExpected ) {
219- data = [ { } ] ;
220- }
221-
222- // Check if error. Ajax layer should always return an object (if error) or an array (if success).
223- if ( ! data || typeof data != 'object' ) {
224- return rejectWithError ( this . createFakeWSError ( 'core.serverconnection' , true ) ) ;
225- } else if ( data . error ) {
226- return rejectWithError ( data ) ;
227- }
228-
229- // Get the first response since only one request was done.
230- data = data [ 0 ] ;
231-
232- if ( data . error ) {
233- return rejectWithError ( data . exception ) ;
234- }
235-
236- return data . data ;
237- } , ( data ) => {
238- const available = data . status == 404 ? - 1 : 0 ;
239-
240- return rejectWithError ( this . createFakeWSError ( 'core.serverconnection' , true ) , available ) ;
241- } ) ;
242-
243- // Convenience function to return an error.
244- function rejectWithError ( exception : any , available ?: number ) : Promise < never > {
245- if ( typeof available == 'undefined' ) {
246- if ( exception . errorcode ) {
247- available = exception . errorcode == 'invalidrecord' ? - 1 : 1 ;
248- } else {
249- available = 0 ;
250- }
251- }
252-
253- exception . available = available ;
254-
255- return Promise . reject ( exception ) ;
256- }
197+ return promise ;
257198 }
258199
259200 /**
@@ -496,6 +437,94 @@ export class CoreWSProvider {
496437 return method + '#' + Md5 . hashAsciiStr ( url ) ;
497438 }
498439
440+ /**
441+ * Call a Moodle WS using the AJAX API.
442+ *
443+ * @param method The WebService method to be called.
444+ * @param data Arguments to pass to the method.
445+ * @param preSets Extra settings and information. Only some
446+ * @return Promise resolved with the response data in success and rejected with an object containing:
447+ * - error: Error message.
448+ * - errorcode: Error code returned by the site (if any).
449+ * - available: 0 if unknown, 1 if available, -1 if not available.
450+ */
451+ protected performAjax ( method : string , data : any , preSets : CoreWSAjaxPreSets ) : Promise < any > {
452+
453+ let promise ;
454+
455+ if ( typeof preSets . siteUrl == 'undefined' ) {
456+ return rejectWithError ( this . createFakeWSError ( 'core.unexpectederror' , true ) ) ;
457+ } else if ( ! this . appProvider . isOnline ( ) ) {
458+ return rejectWithError ( this . createFakeWSError ( 'core.networkerrormsg' , true ) ) ;
459+ }
460+
461+ if ( typeof preSets . responseExpected == 'undefined' ) {
462+ preSets . responseExpected = true ;
463+ }
464+
465+ const script = preSets . noLogin ? 'service-nologin.php' : 'service.php' ,
466+ ajaxData = JSON . stringify ( [ {
467+ index : 0 ,
468+ methodname : method ,
469+ args : this . convertValuesToString ( data )
470+ } ] ) ;
471+
472+ // The info= parameter has no function. It is just to help with debugging.
473+ // We call it info to match the parameter name use by Moodle's AMD ajax module.
474+ let siteUrl = preSets . siteUrl + '/lib/ajax/' + script + '?info=' + method ;
475+
476+ if ( preSets . noLogin && preSets . useGet ) {
477+ // Send params using GET.
478+ siteUrl += '&args=' + encodeURIComponent ( ajaxData ) ;
479+ promise = this . http . get ( siteUrl ) . timeout ( this . getRequestTimeout ( ) ) . toPromise ( ) ;
480+ } else {
481+ promise = this . http . post ( siteUrl , ajaxData ) . timeout ( this . getRequestTimeout ( ) ) . toPromise ( ) ;
482+ }
483+
484+ return promise . then ( ( data : any ) => {
485+ // Some moodle web services return null.
486+ // If the responseExpected value is set then so long as no data is returned, we create a blank object.
487+ if ( ! data && ! preSets . responseExpected ) {
488+ data = [ { } ] ;
489+ }
490+
491+ // Check if error. Ajax layer should always return an object (if error) or an array (if success).
492+ if ( ! data || typeof data != 'object' ) {
493+ return rejectWithError ( this . createFakeWSError ( 'core.serverconnection' , true ) ) ;
494+ } else if ( data . error ) {
495+ return rejectWithError ( data ) ;
496+ }
497+
498+ // Get the first response since only one request was done.
499+ data = data [ 0 ] ;
500+
501+ if ( data . error ) {
502+ return rejectWithError ( data . exception ) ;
503+ }
504+
505+ return data . data ;
506+ } , ( data ) => {
507+ const available = data . status == 404 ? - 1 : 0 ;
508+
509+ return rejectWithError ( this . createFakeWSError ( 'core.serverconnection' , true ) , available ) ;
510+ } ) ;
511+
512+ // Convenience function to return an error.
513+ function rejectWithError ( exception : any , available ?: number ) : Promise < never > {
514+ if ( typeof available == 'undefined' ) {
515+ if ( exception . errorcode ) {
516+ available = exception . errorcode == 'invalidrecord' ? - 1 : 1 ;
517+ } else {
518+ available = 0 ;
519+ }
520+ }
521+
522+ exception . available = available ;
523+
524+ return Promise . reject ( exception ) ;
525+ }
526+ }
527+
499528 /**
500529 * Perform a HEAD request and save the promise while waiting to be resolved.
501530 *
0 commit comments