MOBILE-4268 core: Require details with error code

main
Noel De Martin 2023-03-07 11:28:19 +01:00
parent 6ce688e76c
commit eb0738cb0f
10 changed files with 219 additions and 122 deletions

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror';
/** /**
* Error returned by WS. * Error returned by WS.
@ -29,10 +29,7 @@ export class CoreAjaxWSError extends CoreSiteError {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
constructor(error: any, available?: number) { constructor(error: any, available?: number) {
super({ super(getErrorOptions(error));
message: error.message || error.error,
errorcode: error.errorcode,
});
this.exception = error.exception; this.exception = error.exception;
this.warningcode = error.warningcode; this.warningcode = error.warningcode;
@ -40,15 +37,37 @@ export class CoreAjaxWSError extends CoreSiteError {
this.moreinfourl = error.moreinfourl; this.moreinfourl = error.moreinfourl;
this.debuginfo = error.debuginfo; this.debuginfo = error.debuginfo;
this.backtrace = error.backtrace; this.backtrace = error.backtrace;
this.available = available ?? (
this.available = available; this.debug
if (this.available === undefined) { ? (this.debug.code == 'invalidrecord' ? -1 : 1)
if (this.errorcode) { : 0
this.available = this.errorcode == 'invalidrecord' ? -1 : 1; );
} else {
this.available = 0;
}
}
} }
} }
/**
* Get error options from unknown error instance.
*
* @param error The error.
* @returns Options
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getErrorOptions(error: any): CoreSiteErrorOptions {
const options: CoreSiteErrorOptions = {
message: error.message || error.error,
};
if ('debug' in error) {
options.debug = error.debug;
}
if ('errorcode' in error) {
options.debug = {
code: error.errorcode,
details: error.message || error.error,
};
}
return options;
}

View File

@ -20,24 +20,39 @@ import { CoreUserSupportConfig } from '@features/user/classes/support/support-co
*/ */
export class CoreSiteError extends CoreError { export class CoreSiteError extends CoreError {
errorcode?: string; debug?: CoreSiteErrorDebug;
errorDetails?: string;
supportConfig?: CoreUserSupportConfig; supportConfig?: CoreUserSupportConfig;
constructor(options: CoreSiteErrorOptions) { constructor(options: CoreSiteErrorOptions) {
super(options.message); super(options.message);
this.errorcode = options.errorcode; this.debug = options.debug;
this.errorDetails = options.errorDetails;
this.supportConfig = options.supportConfig; this.supportConfig = options.supportConfig;
} }
/**
* @deprecated This getter should not be called directly, but it's defined for backwards compatibility with many
* parts of the code that type errors as any and use it. We cannot rename those because the errors could also be
* CoreWSError instances which do have an "errorcode" property.
*
* @returns error code.
*/
get errorcode(): string | undefined {
return this.debug?.code;
}
} }
export type CoreSiteErrorDebug = {
code: string; // Technical error code useful for technical assistance.
details: string; // Technical error details useful for technical assistance.
};
export type CoreSiteErrorOptions = { export type CoreSiteErrorOptions = {
message: string; message: string;
errorcode?: string; // Technical error code useful for technical assistance.
errorDetails?: string; // Technical error details useful for technical assistance. // Debugging information.
debug?: CoreSiteErrorDebug;
// Configuration to use to contact site support. If this attribute is present, it means // Configuration to use to contact site support. If this attribute is present, it means
// that the error warrants contacting support. // that the error warrants contacting support.

View File

@ -943,8 +943,10 @@ export class CoreAuthenticatedSite extends CoreUnauthenticatedSite {
throw new CoreSiteError({ throw new CoreSiteError({
supportConfig: new CoreUserAuthenticatedSupportConfig(this), supportConfig: new CoreUserAuthenticatedSupportConfig(this),
message: Translate.instant('core.siteunavailablehelp', { site: this.siteUrl }), message: Translate.instant('core.siteunavailablehelp', { site: this.siteUrl }),
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.errorinvalidresponse', { method: 'tool_mobile_call_external_functions' }), code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method: 'tool_mobile_call_external_functions' }),
},
}); });
} }

View File

@ -36,7 +36,7 @@ export class CoreErrorInfoComponent implements OnInit, OnChanges {
* @param errorCode Error code. * @param errorCode Error code.
* @returns Component HTML. * @returns Component HTML.
*/ */
static render(errorDetails: string, errorCode?: string): string { static render(errorDetails: string, errorCode: string): string {
const toggleId = CoreForms.uniqueId('error-info-toggle'); const toggleId = CoreForms.uniqueId('error-info-toggle');
const errorCodeLabel = Translate.instant('core.errorcode', { errorCode }); const errorCodeLabel = Translate.instant('core.errorcode', { errorCode });
const hideDetailsLabel = Translate.instant('core.errordetailshide'); const hideDetailsLabel = Translate.instant('core.errordetailshide');
@ -45,7 +45,7 @@ export class CoreErrorInfoComponent implements OnInit, OnChanges {
return ` return `
<div class="core-error-info"> <div class="core-error-info">
<input id="${toggleId}" type="checkbox" class="core-error-info--checkbox" /> <input id="${toggleId}" type="checkbox" class="core-error-info--checkbox" />
${errorCode ? `<div class="core-error-info--code"><strong>${errorCodeLabel}</strong></div>` : ''} <div class="core-error-info--code"><strong>${errorCodeLabel}</strong></div>
<div class="core-error-info--details"> <div class="core-error-info--details">
<p>${errorDetails}</p> <p>${errorDetails}</p>
</div> </div>
@ -64,7 +64,7 @@ export class CoreErrorInfoComponent implements OnInit, OnChanges {
} }
@Input() errorDetails!: string; @Input() errorDetails!: string;
@Input() errorCode?: string; @Input() errorCode!: string;
constructor(private element: ElementRef) {} constructor(private element: ElementRef) {}

View File

@ -38,7 +38,7 @@ import { CoreCustomURLSchemes, CoreCustomURLSchemesHandleError } from '@services
import { CoreTextUtils } from '@services/utils/text'; import { CoreTextUtils } from '@services/utils/text';
import { CoreForms } from '@singletons/form'; import { CoreForms } from '@singletons/form';
import { AlertButton } from '@ionic/core'; import { AlertButton } from '@ionic/core';
import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreSiteError, CoreSiteErrorDebug } from '@classes/errors/siteerror';
import { CoreUserSupport } from '@features/user/services/support'; import { CoreUserSupport } from '@features/user/services/support';
import { CoreErrorInfoComponent } from '@components/error-info/error-info'; import { CoreErrorInfoComponent } from '@components/error-info/error-info';
import { CoreUserSupportConfig } from '@features/user/classes/support/support-config'; import { CoreUserSupportConfig } from '@features/user/classes/support/support-config';
@ -408,21 +408,19 @@ export class CoreLoginSitePage implements OnInit {
let siteExists = false; let siteExists = false;
let supportConfig: CoreUserSupportConfig | undefined = undefined; let supportConfig: CoreUserSupportConfig | undefined = undefined;
let errorTitle: string | undefined; let errorTitle: string | undefined;
let errorDetails: string | undefined; let debug: CoreSiteErrorDebug | undefined;
let errorCode: string | undefined;
if (error instanceof CoreSiteError) { if (error instanceof CoreSiteError) {
supportConfig = error.supportConfig; supportConfig = error.supportConfig;
errorDetails = error.errorDetails;
errorCode = error.errorcode;
siteExists = supportConfig instanceof CoreUserGuestSupportConfig; siteExists = supportConfig instanceof CoreUserGuestSupportConfig;
debug = error.debug;
} }
if (error instanceof CoreLoginError) { if (error instanceof CoreLoginError) {
errorTitle = error.title; errorTitle = error.title;
} }
if (errorDetails) { if (debug) {
errorMessage = `<p>${errorMessage}</p><div class="core-error-info-container"></div>`; errorMessage = `<p>${errorMessage}</p><div class="core-error-info-container"></div>`;
} }
@ -438,7 +436,7 @@ export class CoreLoginSitePage implements OnInit {
handler: () => CoreUserSupport.contact({ handler: () => CoreUserSupport.contact({
supportConfig: alertSupportConfig, supportConfig: alertSupportConfig,
subject: Translate.instant('core.cannotconnect'), subject: Translate.instant('core.cannotconnect'),
message: `Error: ${errorCode}\n\n${errorDetails}`, message: `Error: ${debug?.code}\n\n${debug?.details}`,
}), }),
} }
: ( : (
@ -458,11 +456,10 @@ export class CoreLoginSitePage implements OnInit {
buttons: buttons as AlertButton[], buttons: buttons as AlertButton[],
}); });
if (errorDetails) { if (debug) {
// Avoid sanitizing JS.
const containerElement = alertElement.querySelector('.core-error-info-container'); const containerElement = alertElement.querySelector('.core-error-info-container');
if (containerElement) { if (containerElement) {
containerElement.innerHTML = CoreErrorInfoComponent.render(errorDetails, errorCode); containerElement.innerHTML = CoreErrorInfoComponent.render(debug.details, debug.code);
} }
} }
} }

View File

@ -39,7 +39,6 @@ import { CorePushNotifications } from '@features/pushnotifications/services/push
import { CorePath } from '@singletons/path'; import { CorePath } from '@singletons/path';
import { CorePromisedValue } from '@classes/promised-value'; import { CorePromisedValue } from '@classes/promised-value';
import { SafeHtml } from '@angular/platform-browser'; import { SafeHtml } from '@angular/platform-browser';
import { CoreLoginError } from '@classes/errors/loginerror';
import { CoreSettingsHelper } from '@features/settings/services/settings-helper'; import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
import { import {
CoreSiteIdentityProvider, CoreSiteIdentityProvider,
@ -916,8 +915,8 @@ export class CoreLoginHelperProvider {
/** /**
* Show a modal warning that the credentials introduced were not correct. * Show a modal warning that the credentials introduced were not correct.
*/ */
protected showInvalidLoginModal(error: CoreLoginError): void { protected showInvalidLoginModal(error: CoreWSError): void {
CoreDomUtils.showErrorModal(error.errorDetails ?? error.message); CoreDomUtils.showErrorModal(error.message);
} }
/** /**

View File

@ -124,7 +124,10 @@ describe('Credentials page', () => {
getUserToken: () => { getUserToken: () => {
throw new CoreLoginError({ throw new CoreLoginError({
message: '', message: '',
errorcode: 'invalidlogin', debug: {
code: 'invalidlogin',
details: 'Invalid login',
},
}); });
}, },
checkSite: async () => (siteCheck), checkSite: async () => (siteCheck),

View File

@ -66,6 +66,7 @@ import { CoreSiteInfo, CoreSiteInfoResponse, CoreSitePublicConfigResponse } from
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site'; import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { CoreHTMLClasses } from '@singletons/html-classes'; import { CoreHTMLClasses } from '@singletons/html-classes';
import { CoreSiteErrorDebug } from '@classes/errors/siteerror';
export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS'); export const CORE_SITE_SCHEMAS = new InjectionToken<CoreSiteSchema[]>('CORE_SITE_SCHEMAS');
export const CORE_SITE_CURRENT_SITE_ID_CONFIG = 'current_site_id'; export const CORE_SITE_CURRENT_SITE_ID_CONFIG = 'current_site_id';
@ -362,18 +363,22 @@ export class CoreSitesProvider {
if (!config.enablewebservices) { if (!config.enablewebservices) {
throw this.createCannotConnectLoginError(config.httpswwwroot || config.wwwroot, { throw this.createCannotConnectLoginError(config.httpswwwroot || config.wwwroot, {
supportConfig: new CoreUserGuestSupportConfig(temporarySite, config), supportConfig: new CoreUserGuestSupportConfig(temporarySite, config),
errorcode: 'webservicesnotenabled',
errorDetails: Translate.instant('core.login.webservicesnotenabled'),
critical: true, critical: true,
debug: {
code: 'webservicesnotenabled',
details: Translate.instant('core.login.webservicesnotenabled'),
},
}); });
} }
if (!config.enablemobilewebservice) { if (!config.enablemobilewebservice) {
throw this.createCannotConnectLoginError(config.httpswwwroot || config.wwwroot, { throw this.createCannotConnectLoginError(config.httpswwwroot || config.wwwroot, {
supportConfig: new CoreUserGuestSupportConfig(temporarySite, config), supportConfig: new CoreUserGuestSupportConfig(temporarySite, config),
errorcode: 'mobileservicesnotenabled',
errorDetails: Translate.instant('core.login.mobileservicesnotenabled'),
critical: true, critical: true,
debug: {
code: 'mobileservicesnotenabled',
details: Translate.instant('core.login.mobileservicesnotenabled'),
},
}); });
} }
@ -421,14 +426,16 @@ export class CoreSitesProvider {
siteUrl: string, siteUrl: string,
error: CoreError | CoreAjaxError | CoreAjaxWSError, error: CoreError | CoreAjaxError | CoreAjaxWSError,
): Promise<CoreLoginError> { ): Promise<CoreLoginError> {
if (error instanceof CoreAjaxError || !('errorcode' in error)) { if (error instanceof CoreAjaxError || (!('debug' in error) && !('errorcode' in error))) {
// The WS didn't return data, probably cannot connect. // The WS didn't return data, probably cannot connect.
return new CoreLoginError({ return new CoreLoginError({
title: Translate.instant('core.cannotconnect'), title: Translate.instant('core.cannotconnect'),
message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }), message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }),
errorcode: 'publicconfigfailed',
errorDetails: error.message || '',
critical: false, // Allow fallback to http if siteUrl uses https. critical: false, // Allow fallback to http if siteUrl uses https.
debug: {
code: 'publicconfigfailed',
details: error.message || 'Failed getting public config',
},
}); });
} }
@ -437,28 +444,31 @@ export class CoreSitesProvider {
critical: true, critical: true,
title: Translate.instant('core.cannotconnect'), title: Translate.instant('core.cannotconnect'),
message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }), message: Translate.instant('core.siteunavailablehelp', { site: siteUrl }),
errorcode: error.errorcode,
supportConfig: error.supportConfig, supportConfig: error.supportConfig,
errorDetails: error.errorDetails ?? error.message, debug: error.debug,
}; };
if (error.errorcode === 'codingerror') { if (error.debug?.code === 'codingerror') {
// This could be caused by a redirect. Check if it's the case. // This could be caused by a redirect. Check if it's the case.
const redirect = await CoreUtils.checkRedirect(siteUrl); const redirect = await CoreUtils.checkRedirect(siteUrl);
options.message = Translate.instant('core.siteunavailablehelp', { site: siteUrl }); options.message = Translate.instant('core.siteunavailablehelp', { site: siteUrl });
if (redirect) { if (redirect) {
options.errorcode = 'sitehasredirect';
options.errorDetails = Translate.instant('core.login.sitehasredirect');
options.critical = false; // Keep checking fallback URLs. options.critical = false; // Keep checking fallback URLs.
options.debug = {
code: 'sitehasredirect',
details: Translate.instant('core.login.sitehasredirect'),
};
} }
} else if (error.errorcode === 'invalidrecord') { } else if (error.debug?.code === 'invalidrecord') {
// WebService not found, site not supported. // WebService not found, site not supported.
options.message = Translate.instant('core.siteunavailablehelp', { site: siteUrl }); options.message = Translate.instant('core.siteunavailablehelp', { site: siteUrl });
options.errorcode = 'invalidmoodleversion'; options.debug = {
options.errorDetails = Translate.instant('core.login.invalidmoodleversion', { $a: CoreSite.MINIMUM_MOODLE_VERSION }); code: 'invalidmoodleversion',
} else if (error.errorcode === 'redirecterrordetected') { details: Translate.instant('core.login.invalidmoodleversion', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
};
} else if (error.debug?.code === 'redirecterrordetected') {
options.critical = false; // Keep checking fallback URLs. options.critical = false; // Keep checking fallback URLs.
} }
@ -538,16 +548,20 @@ export class CoreSitesProvider {
if (redirect) { if (redirect) {
throw this.createCannotConnectLoginError(siteUrl, { throw this.createCannotConnectLoginError(siteUrl, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl), supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
errorcode: 'sitehasredirect', debug: {
errorDetails: Translate.instant('core.login.sitehasredirect'), code: 'sitehasredirect',
details: Translate.instant('core.login.sitehasredirect'),
},
}); });
} }
} }
throw this.createCannotConnectLoginError(siteUrl, { throw this.createCannotConnectLoginError(siteUrl, {
supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl), supportConfig: await CoreUserGuestSupportConfig.forSite(siteUrl),
errorcode: data.errorcode, debug: {
errorDetails: data.error, code: data.errorcode ?? 'loginfailed',
details: data.error ?? 'Could not get a user token in /login/token.php',
},
}); });
} }
@ -659,23 +673,33 @@ export class CoreSitesProvider {
* @returns A promise rejected with the error info. * @returns A promise rejected with the error info.
*/ */
protected async treatInvalidAppVersion(result: number, siteId?: string): Promise<never> { protected async treatInvalidAppVersion(result: number, siteId?: string): Promise<never> {
let errorCode: string | undefined; let debug: CoreSiteErrorDebug | undefined;
let errorKey: string | undefined; let errorKey: string | undefined;
let translateParams = {}; let translateParams = {};
switch (result) { switch (result) {
case CoreSitesProvider.MOODLE_APP: case CoreSitesProvider.MOODLE_APP:
errorKey = 'core.login.connecttomoodleapp'; errorKey = 'core.login.connecttomoodleapp';
errorCode = 'connecttomoodleapp'; debug = {
code: 'connecttomoodleapp',
details: 'Cannot connect to app',
};
break; break;
case CoreSitesProvider.WORKPLACE_APP: case CoreSitesProvider.WORKPLACE_APP:
errorKey = 'core.login.connecttoworkplaceapp'; errorKey = 'core.login.connecttoworkplaceapp';
errorCode = 'connecttoworkplaceapp'; debug = {
code: 'connecttoworkplaceapp',
details: 'Cannot connect to app',
};
break; break;
default: default:
errorCode = 'invalidmoodleversion';
errorKey = 'core.login.invalidmoodleversion'; errorKey = 'core.login.invalidmoodleversion';
translateParams = { $a: CoreSite.MINIMUM_MOODLE_VERSION }; translateParams = { $a: CoreSite.MINIMUM_MOODLE_VERSION };
debug = {
code: 'invalidmoodleversion',
details: 'Cannot connect to app',
};
break;
} }
if (siteId) { if (siteId) {
@ -683,8 +707,8 @@ export class CoreSitesProvider {
} }
throw new CoreLoginError({ throw new CoreLoginError({
debug,
message: Translate.instant(errorKey, translateParams), message: Translate.instant(errorKey, translateParams),
errorcode: errorCode,
loggedOut: true, loggedOut: true,
}); });
} }

View File

@ -1037,7 +1037,7 @@ export class CoreDomUtilsProvider {
if (typeof error !== 'string' && 'buttons' in error && typeof error.buttons !== 'undefined') { if (typeof error !== 'string' && 'buttons' in error && typeof error.buttons !== 'undefined') {
alertOptions.buttons = error.buttons; alertOptions.buttons = error.buttons;
} else if (error instanceof CoreSiteError) { } else if (error instanceof CoreSiteError) {
if (error.errorDetails) { if (error.debug) {
alertOptions.message = `<p>${alertOptions.message}</p><div class="core-error-info-container"></div>`; alertOptions.message = `<p>${alertOptions.message}</p><div class="core-error-info-container"></div>`;
} }
@ -1051,7 +1051,7 @@ export class CoreDomUtilsProvider {
handler: () => CoreUserSupport.contact({ handler: () => CoreUserSupport.contact({
supportConfig, supportConfig,
subject: alertOptions.header, subject: alertOptions.header,
message: `${error.errorcode}\n\n${error.errorDetails}`, message: `${error.debug?.code}\n\n${error.debug?.details}`,
}), }),
}); });
} }
@ -1061,11 +1061,11 @@ export class CoreDomUtilsProvider {
const alertElement = await this.showAlertWithOptions(alertOptions, autocloseTime); const alertElement = await this.showAlertWithOptions(alertOptions, autocloseTime);
if (error instanceof CoreSiteError && error.errorDetails) { if (error instanceof CoreSiteError && error.debug) {
const containerElement = alertElement.querySelector('.core-error-info-container'); const containerElement = alertElement.querySelector('.core-error-info-container');
if (containerElement) { if (containerElement) {
containerElement.innerHTML = CoreErrorInfoComponent.render(error.errorDetails, error.errorcode); containerElement.innerHTML = CoreErrorInfoComponent.render(error.debug.details, error.debug.code);
} }
} }

View File

@ -497,10 +497,12 @@ export class CoreWSProvider {
throw new CoreAjaxError({ throw new CoreAjaxError({
message, message,
supportConfig: await CoreUserGuestSupportConfig.forSite(preSets.siteUrl), supportConfig: await CoreUserGuestSupportConfig.forSite(preSets.siteUrl),
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.serverconnection', { code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method }), details: Translate.instant('core.serverconnection', {
}), details: Translate.instant('core.errorinvalidresponse', { method }),
}),
},
}); });
} else if (data.error) { } else if (data.error) {
throw new CoreAjaxWSError(data); throw new CoreAjaxWSError(data);
@ -527,54 +529,72 @@ export class CoreWSProvider {
if (CorePlatform.isMobile()) { if (CorePlatform.isMobile()) {
switch (data.status) { switch (data.status) {
case NativeHttp.ErrorCode.SSL_EXCEPTION: case NativeHttp.ErrorCode.SSL_EXCEPTION:
options.errorcode = 'invalidcertificate'; options.debug = {
options.errorDetails = Translate.instant('core.certificaterror', { code: 'invalidcertificate',
details: CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Invalid certificate', details: Translate.instant('core.certificaterror', {
}); details: CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Invalid certificate',
}),
};
break; break;
case NativeHttp.ErrorCode.SERVER_NOT_FOUND: case NativeHttp.ErrorCode.SERVER_NOT_FOUND:
options.errorcode = 'servernotfound'; options.debug = {
options.errorDetails = CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Server could not be found'; code: 'servernotfound',
details: CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Server could not be found',
};
break; break;
case NativeHttp.ErrorCode.TIMEOUT: case NativeHttp.ErrorCode.TIMEOUT:
options.errorcode = 'requesttimeout'; options.debug = {
options.errorDetails = CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Request timed out'; code: 'requesttimeout',
details: CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Request timed out',
};
break; break;
case NativeHttp.ErrorCode.UNSUPPORTED_URL: case NativeHttp.ErrorCode.UNSUPPORTED_URL:
options.errorcode = 'unsupportedurl'; options.debug = {
options.errorDetails = CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Url not supported'; code: 'unsupportedurl',
details: CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Url not supported',
};
break; break;
case NativeHttp.ErrorCode.NOT_CONNECTED: case NativeHttp.ErrorCode.NOT_CONNECTED:
options.errorcode = 'connectionerror'; options.debug = {
options.errorDetails = CoreTextUtils.getErrorMessageFromError(data.error) code: 'connectionerror',
?? 'Connection error, is network available?'; details: CoreTextUtils.getErrorMessageFromError(data.error)
?? 'Connection error, is network available?',
};
break; break;
case NativeHttp.ErrorCode.ABORTED: case NativeHttp.ErrorCode.ABORTED:
options.errorcode = 'requestaborted'; options.debug = {
options.errorDetails = CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Request aborted'; code: 'requestaborted',
details: CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Request aborted',
};
break; break;
case NativeHttp.ErrorCode.POST_PROCESSING_FAILED: case NativeHttp.ErrorCode.POST_PROCESSING_FAILED:
options.errorcode = 'requestprocessingfailed'; options.debug = {
options.errorDetails = CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Request processing failed'; code: 'requestprocessingfailed',
details: CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Request processing failed',
};
break; break;
} }
} }
if (!options.errorcode) { if (!options.debug) {
switch (data.status) { switch (data.status) {
case 404: case 404:
options.errorcode = 'endpointnotfound'; options.debug = {
options.errorDetails = Translate.instant('core.ajaxendpointnotfound', { code: 'endpointnotfound',
$a: CoreSite.MINIMUM_MOODLE_VERSION, details: Translate.instant('core.ajaxendpointnotfound', {
}); $a: CoreSite.MINIMUM_MOODLE_VERSION,
}),
};
break; break;
default: { default: {
const details = CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Unknown error'; const details = CoreTextUtils.getErrorMessageFromError(data.error) ?? 'Unknown error';
options.errorcode = 'serverconnectionajax'; options.debug = {
options.errorDetails = Translate.instant('core.serverconnection', { code: 'serverconnectionajax',
details: `[Response status code: ${data.status}] ${details}`, details: Translate.instant('core.serverconnection', {
}); details: `[Response status code: ${data.status}] ${details}`,
}),
};
} }
break; break;
} }
@ -716,10 +736,12 @@ export class CoreWSProvider {
if (!data) { if (!data) {
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'serverconnectionpost', debug: {
errorDetails: Translate.instant('core.serverconnection', { code: 'serverconnectionpost',
details: Translate.instant('core.errorinvalidresponse', { method }), details: Translate.instant('core.serverconnection', {
}), details: Translate.instant('core.errorinvalidresponse', { method }),
}),
},
}); });
} else if (typeof data !== typeExpected) { } else if (typeof data !== typeExpected) {
// If responseType is text an string will be returned, parse before returning. // If responseType is text an string will be returned, parse before returning.
@ -730,8 +752,10 @@ export class CoreWSProvider {
this.logger.warn(`Response expected type "${typeExpected}" cannot be parsed to number`); this.logger.warn(`Response expected type "${typeExpected}" cannot be parsed to number`);
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.errorinvalidresponse', { method }), code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method }),
},
}); });
} }
} else if (typeExpected === 'boolean') { } else if (typeExpected === 'boolean') {
@ -743,24 +767,30 @@ export class CoreWSProvider {
this.logger.warn(`Response expected type "${typeExpected}" is not true or false`); this.logger.warn(`Response expected type "${typeExpected}" is not true or false`);
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.errorinvalidresponse', { method }), code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method }),
},
}); });
} }
} else { } else {
this.logger.warn('Response of type "' + typeof data + `" received, expecting "${typeExpected}"`); this.logger.warn('Response of type "' + typeof data + `" received, expecting "${typeExpected}"`);
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.errorinvalidresponse', { method }), code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method }),
},
}); });
} }
} else { } else {
this.logger.warn('Response of type "' + typeof data + `" received, expecting "${typeExpected}"`); this.logger.warn('Response of type "' + typeof data + `" received, expecting "${typeExpected}"`);
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.errorinvalidresponse', { method }), code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method }),
},
}); });
} }
} }
@ -803,10 +833,12 @@ export class CoreWSProvider {
return retryPromise; return retryPromise;
} else if (error.status === -2) { } else if (error.status === -2) {
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'invalidcertificate', debug: {
errorDetails: Translate.instant('core.certificaterror', { code: 'invalidcertificate',
details: CoreTextUtils.getErrorMessageFromError(error) ?? 'Unknown error', details: Translate.instant('core.certificaterror', {
}), details: CoreTextUtils.getErrorMessageFromError(error) ?? 'Unknown error',
}),
},
}); });
} else if (error.status > 0) { } else if (error.status > 0) {
throw this.createHttpError(error, error.status); throw this.createHttpError(error, error.status);
@ -1033,24 +1065,30 @@ export class CoreWSProvider {
if (data === null) { if (data === null) {
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.errorinvalidresponse', { method: 'upload.php' }), code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method: 'upload.php' }),
},
}); });
} }
if (!data) { if (!data) {
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'serverconnectionupload', debug: {
errorDetails: Translate.instant('core.serverconnection', { code: 'serverconnectionupload',
details: Translate.instant('core.errorinvalidresponse', { method: 'upload.php' }), details: Translate.instant('core.serverconnection', {
}), details: Translate.instant('core.errorinvalidresponse', { method: 'upload.php' }),
}),
},
}); });
} else if (typeof data != 'object') { } else if (typeof data != 'object') {
this.logger.warn('Upload file: Response of type "' + typeof data + '" received, expecting "object"'); this.logger.warn('Upload file: Response of type "' + typeof data + '" received, expecting "object"');
throw await this.createCannotConnectSiteError(preSets.siteUrl, { throw await this.createCannotConnectSiteError(preSets.siteUrl, {
errorcode: 'invalidresponse', debug: {
errorDetails: Translate.instant('core.errorinvalidresponse', { method: 'upload.php' }), code: 'invalidresponse',
details: Translate.instant('core.errorinvalidresponse', { method: 'upload.php' }),
},
}); });
} }