Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/core/classes/sites/authenticated-site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,8 +465,13 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
}

const observable = this.performRequest<T>(method, data, preSets, wsPreSets).pipe(
// Return a clone of the original object, this may prevent errors if in the callback the object is modified.
map((data) => CoreUtils.clone(data)),
map((data) => {
// Always clone the object because it can be modified when applying patches or in the caller function
// and we don't want to store the modified object in cache.
const clonedData = CoreUtils.clone(data);

return this.applyWSOverrides(method, clonedData);
}),
);

this.setOngoingRequest(cacheId, preSets, observable);
Expand Down Expand Up @@ -1347,13 +1352,13 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
* @inheritdoc
*/
async getPublicConfig(options: { readingStrategy?: CoreSitesReadingStrategy } = {}): Promise<CoreSitePublicConfigResponse> {
const method = 'tool_mobile_get_public_config';
const ignoreCache = options.readingStrategy === CoreSitesReadingStrategy.ONLY_NETWORK ||
options.readingStrategy === CoreSitesReadingStrategy.PREFER_NETWORK;
if (!ignoreCache && this.publicConfig) {
return this.publicConfig;
return this.overridePublicConfig(this.publicConfig);
}

const method = 'tool_mobile_get_public_config';
const cacheId = this.getCacheId(method, {});
const cachePreSets: CoreSiteWSPreSets = {
getFromCache: true,
Expand All @@ -1378,8 +1383,7 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {

const subject = new Subject<CoreSitePublicConfigResponse>();
const observable = subject.pipe(
// Return a clone of the original object, this may prevent errors if in the callback the object is modified.
map((data) => CoreUtils.clone(data)),
map((data) => this.overridePublicConfig(data)),
finalize(() => {
this.clearOngoingRequest(cacheId, cachePreSets, observable);
}),
Expand Down
54 changes: 52 additions & 2 deletions src/core/classes/sites/unauthenticated-site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { CoreText } from '@singletons/text';
import { CoreUrl, CoreUrlPartNames } from '@singletons/url';
import { CoreWS, CoreWSAjaxPreSets, CoreWSExternalWarning } from '@services/ws';
import { CorePath } from '@singletons/path';
import { CoreJsonPatch } from '@singletons/json-patch';
import { CoreUtils } from '@singletons/utils';

/**
* Class that represents a Moodle site where the user still hasn't authenticated.
Expand Down Expand Up @@ -251,7 +253,7 @@ export class CoreUnauthenticatedSite {
const ignoreCache = options.readingStrategy === CoreSitesReadingStrategy.ONLY_NETWORK ||
options.readingStrategy === CoreSitesReadingStrategy.PREFER_NETWORK;
if (!ignoreCache && this.publicConfig) {
return this.publicConfig;
return this.overridePublicConfig(this.publicConfig);
}

if (options.readingStrategy === CoreSitesReadingStrategy.ONLY_CACHE) {
Expand All @@ -263,7 +265,7 @@ export class CoreUnauthenticatedSite {

this.setPublicConfig(config);

return config;
return this.overridePublicConfig(config);
} catch (error) {
if (options.readingStrategy === CoreSitesReadingStrategy.ONLY_NETWORK || !this.publicConfig) {
throw error;
Expand All @@ -284,6 +286,20 @@ export class CoreUnauthenticatedSite {
this.publicConfig = publicConfig;
}

/**
* Apply overrides to the public config of the site.
*
* @param config Public config.
* @returns Public config with overrides if any.
*/
protected overridePublicConfig(config: CoreSitePublicConfigResponse): CoreSitePublicConfigResponse {
// Always clone the object because it can be modified when applying patches or in the caller function
// and we don't want to modify the stored public config.
const clonedData = CoreUtils.clone(config);

return this.applyWSOverrides('tool_mobile_get_public_config', clonedData);
}

/**
* Perform a request to the server to get the public config of this site.
*
Expand Down Expand Up @@ -452,6 +468,40 @@ export class CoreUnauthenticatedSite {
return features;
}

/**
* Call a Moodle WS using the AJAX API and applies WebService overrides (if any) to the result.
*
* @param method WS method name.
* @param data Arguments to pass to the method.
* @param preSets Extra settings and information.
* @returns Promise resolved with the response data in success and rejected with CoreAjaxError.
*/
async callAjax<T = unknown>(
method: string,
data: Record<string, unknown> = {},
preSets: Omit<CoreWSAjaxPreSets, 'siteUrl'> = {},
): Promise<T> {
const result = await CoreWS.callAjax<T>(method, data, { ...preSets, siteUrl: this.siteUrl });

// No need to clone the data in this case because it's not stored in any cache.
return this.applyWSOverrides(method, result);
}

/**
* Apply WS overrides (if any) to the data of a WebService response.
*
* @param method WS method name.
* @param data WS response data.
* @returns Modified data (or original data if no overrides).
*/
protected applyWSOverrides<T>(method: string, data: T): T {
if (!CoreConstants.CONFIG.wsOverrides || !CoreConstants.CONFIG.wsOverrides[method]) {
return data;
}

return CoreJsonPatch.applyPatches(data, CoreConstants.CONFIG.wsOverrides[method]);
}

}

/**
Expand Down
11 changes: 4 additions & 7 deletions src/core/features/login/pages/email-signup/email-signup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Component, ElementRef, OnInit, ChangeDetectorRef, inject, viewChild } f
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
import { CoreText } from '@singletons/text';
import { CoreCountries, CoreCountry } from '@singletons/countries';
import { CoreWS, CoreWSExternalWarning } from '@services/ws';
import { CoreWSExternalWarning } from '@services/ws';
import { Translate } from '@singletons';
import { CoreSitePublicConfigResponse, CoreUnauthenticatedSite } from '@classes/sites/unauthenticated-site';
import { CoreUserProfileFieldDelegate } from '@features/user/services/user-profile-field-delegate';
Expand Down Expand Up @@ -197,10 +197,8 @@ export default class CoreLoginEmailSignupPage implements OnInit {
if (this.ageDigitalConsentVerification === undefined) {

const result = await CorePromiseUtils.ignoreErrors(
CoreWS.callAjax<IsAgeVerificationEnabledWSResponse>(
this.site.callAjax<IsAgeVerificationEnabledWSResponse>(
'core_auth_is_age_digital_consent_verification_enabled',
{},
{ siteUrl: this.site.getURL() },
),
);

Expand Down Expand Up @@ -344,10 +342,9 @@ export default class CoreLoginEmailSignupPage implements OnInit {
this.signupForm.value,
);

const result = await CoreWS.callAjax<SignupUserWSResult>(
const result = await this.site.callAjax<SignupUserWSResult>(
'auth_email_signup_user',
params,
{ siteUrl: this.site.getURL() },
);

if (result.success) {
Expand Down Expand Up @@ -430,7 +427,7 @@ export default class CoreLoginEmailSignupPage implements OnInit {
params.age = parseInt(params.age, 10); // Use just the integer part.

try {
const result = await CoreWS.callAjax<IsMinorWSResult>('core_auth_is_minor', params, { siteUrl: this.site.getURL() });
const result = await this.site.callAjax<IsMinorWSResult>('core_auth_is_minor', params);

CoreForms.triggerFormSubmittedEvent(this.ageFormElement(), true);

Expand Down
13 changes: 6 additions & 7 deletions src/core/features/login/services/login-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { CoreApp, CoreStoreConfig } from '@services/app';
import { CoreConfig } from '@services/config';
import { CoreEvents, CoreEventSessionExpiredData, CoreEventSiteData } from '@singletons/events';
import { CoreSites, CoreLoginSiteInfo, CoreSiteBasicInfo } from '@services/sites';
import { CoreWS, CoreWSExternalWarning } from '@services/ws';
import { CoreWSExternalWarning } from '@services/ws';
import { CoreText, CoreTextFormat } from '@singletons/text';
import { CoreObject } from '@singletons/object';
import { CoreConstants } from '@/core/constants';
Expand Down Expand Up @@ -65,6 +65,7 @@ import { CorePromiseUtils } from '@singletons/promise-utils';
import { CoreOpener } from '@singletons/opener';
import { CoreAlerts } from '@services/overlays/alerts';
import { CorePrompts } from '@services/overlays/prompts';
import { CoreSitesFactory } from '@services/sites-factory';

/**
* Helper provider that provides some common features regarding authentication.
Expand Down Expand Up @@ -271,7 +272,7 @@ export class CoreLoginHelperProvider {
* @returns Signup settings.
*/
async getEmailSignupSettings(siteUrl: string): Promise<AuthEmailSignupSettings> {
return await CoreWS.callAjax('auth_email_get_signup_settings', {}, { siteUrl });
return await CoreSitesFactory.makeUnauthenticatedSite(siteUrl).callAjax('auth_email_get_signup_settings');
}

/**
Expand Down Expand Up @@ -830,7 +831,7 @@ export class CoreLoginHelperProvider {
params.email = email.trim().toLowerCase();
}

return CoreWS.callAjax('core_auth_request_password_reset', params, { siteUrl });
return CoreSitesFactory.makeUnauthenticatedSite(siteUrl).callAjax('core_auth_request_password_reset', params);
}

/**
Expand Down Expand Up @@ -1038,13 +1039,11 @@ export class CoreLoginHelperProvider {
// Call the WS to resend the confirmation email.
const modal = await CoreLoadings.show('core.sending', true);
const data = { username: username?.toLowerCase(), password };
const preSets = { siteUrl };

try {
const result = <ResendConfirmationEmailResult> await CoreWS.callAjax(
const result = <ResendConfirmationEmailResult> await CoreSitesFactory.makeUnauthenticatedSite(siteUrl).callAjax(
'core_auth_resend_confirmation_email',
data,
preSets,
);

if (!result.status) {
Expand Down Expand Up @@ -1077,7 +1076,7 @@ export class CoreLoginHelperProvider {
// We don't have site info before login, the only way to check if the WS is available is by calling it.
try {
// This call will always fail because we aren't sending parameters.
await CoreWS.callAjax('core_auth_resend_confirmation_email', {}, { siteUrl });
await CoreSitesFactory.makeUnauthenticatedSite(siteUrl).callAjax('core_auth_resend_confirmation_email');

return true; // We should never reach here.
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion src/core/services/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export class CoreWSProvider {
*
* @param method The WebService method to be called.
* @param data Arguments to pass to the method.
* @param preSets Extra settings and information. Only some
* @param preSets Extra settings and information.
* @returns Promise resolved with the response data in success and rejected with CoreAjaxError.
*/
callAjax<T = unknown>(method: string, data: Record<string, unknown>, preSets: CoreWSAjaxPreSets): Promise<T> {
Expand Down
Loading