MOBILE-4268 core: Require details with error code
parent
6ce688e76c
commit
eb0738cb0f
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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' }),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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' }),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue