MOBILE-4059 core: Refactor site errors hierarchy

main
Noel De Martin 2022-10-06 14:05:46 +02:00
parent 734f1c6323
commit 23341a7436
5 changed files with 65 additions and 29 deletions

View File

@ -23,6 +23,7 @@ import { CoreAjaxWSError } from './ajaxwserror';
import { CoreCaptureError } from './captureerror'; import { CoreCaptureError } from './captureerror';
import { CoreNetworkError } from './network-error'; import { CoreNetworkError } from './network-error';
import { CoreSiteError } from './siteerror'; import { CoreSiteError } from './siteerror';
import { CoreLoginError } from './loginerror';
import { CoreErrorWithOptions } from './errorwithtitle'; import { CoreErrorWithOptions } from './errorwithtitle';
import { CoreHttpError } from './httperror'; import { CoreHttpError } from './httperror';
@ -35,6 +36,7 @@ export const CORE_ERRORS_CLASSES: Type<unknown>[] = [
CoreNetworkError, CoreNetworkError,
CoreSilentError, CoreSilentError,
CoreSiteError, CoreSiteError,
CoreLoginError,
CoreWSError, CoreWSError,
CoreErrorWithOptions, CoreErrorWithOptions,
CoreHttpError, CoreHttpError,

View File

@ -0,0 +1,37 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { CoreSiteError, CoreSiteErrorOptions } from '@classes/errors/siteerror';
/**
* Error returned when performing operations during login.
*/
export class CoreLoginError extends CoreSiteError {
critical?: boolean;
loggedOut?: boolean;
constructor(options: CoreLoginErrorOptions) {
super(options);
this.critical = options.critical;
this.loggedOut = options.loggedOut;
}
}
export type CoreLoginErrorOptions = CoreSiteErrorOptions & {
critical?: boolean; // Whether the error is important enough to abort the operation.
loggedOut?: boolean; // Whether site has been marked as logged out.
};

View File

@ -17,14 +17,12 @@ import { CoreSitePublicConfigResponse } from '@classes/site';
import { CoreUserSupport } from '@features/user/services/support'; import { CoreUserSupport } from '@features/user/services/support';
/** /**
* Error returned when performing operations regarding a site (check if it exists, authenticate user, etc.). * Error returned when performing operations regarding a site.
*/ */
export class CoreSiteError extends CoreError { export class CoreSiteError extends CoreError {
errorcode?: string; errorcode?: string;
errorDetails?: string; errorDetails?: string;
critical?: boolean;
loggedOut?: boolean;
contactSupport?: boolean; contactSupport?: boolean;
siteConfig?: CoreSitePublicConfigResponse; siteConfig?: CoreSitePublicConfigResponse;
@ -33,8 +31,6 @@ export class CoreSiteError extends CoreError {
this.errorcode = options.errorcode; this.errorcode = options.errorcode;
this.errorDetails = options.errorDetails; this.errorDetails = options.errorDetails;
this.critical = options.critical;
this.loggedOut = options.loggedOut;
this.contactSupport = options.contactSupport; this.contactSupport = options.contactSupport;
this.siteConfig = options.siteConfig; this.siteConfig = options.siteConfig;
} }
@ -86,11 +82,9 @@ function getErrorMessage(options: CoreSiteErrorOptions): string {
export type CoreSiteErrorOptions = { export type CoreSiteErrorOptions = {
message: string; message: string;
fallbackMessage?: string; // Message to use if contacting support was intended but isn't possible. fallbackMessage?: string; // Message to use when contacting support is not possible but warranted.
errorcode?: string; errorcode?: string; // Technical error code useful for technical assistance.
errorDetails?: string; errorDetails?: string; // Technical error details useful for technical assistance.
critical?: boolean; // Whether the error is important enough to abort the operation. contactSupport?: boolean; // Whether this error warrants contacting site support or not.
loggedOut?: boolean; // Whether site has been marked as logged out.
contactSupport?: boolean;
siteConfig?: CoreSitePublicConfigResponse; siteConfig?: CoreSitePublicConfigResponse;
}; };

View File

@ -14,7 +14,7 @@
import { CoreSharedModule } from '@/core/shared.module'; import { CoreSharedModule } from '@/core/shared.module';
import { findElement, mockSingleton, renderPageComponent, requireElement } from '@/testing/utils'; import { findElement, mockSingleton, renderPageComponent, requireElement } from '@/testing/utils';
import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreLoginError } from '@classes/errors/loginerror';
import { CoreLoginComponentsModule } from '@features/login/components/components.module'; import { CoreLoginComponentsModule } from '@features/login/components/components.module';
import { CoreLoginCredentialsPage } from '@features/login/pages/credentials/credentials'; import { CoreLoginCredentialsPage } from '@features/login/pages/credentials/credentials';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
@ -42,7 +42,7 @@ describe('Credentials page', () => {
// Arrange. // Arrange.
mockSingleton(CoreSites, { mockSingleton(CoreSites, {
getUserToken: () => { getUserToken: () => {
throw new CoreSiteError({ throw new CoreLoginError({
message: '', message: '',
errorcode: 'invalidlogin', errorcode: 'invalidlogin',
}); });

View File

@ -34,7 +34,7 @@ import {
} from '@classes/site'; } from '@classes/site';
import { SQLiteDB, SQLiteDBRecordValues, SQLiteDBTableSchema } from '@classes/sqlitedb'; import { SQLiteDB, SQLiteDBRecordValues, SQLiteDBTableSchema } from '@classes/sqlitedb';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
import { CoreSiteError } from '@classes/errors/siteerror'; import { CoreLoginError } from '@classes/errors/loginerror';
import { makeSingleton, Translate, Http } from '@singletons'; import { makeSingleton, Translate, Http } from '@singletons';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { import {
@ -313,7 +313,7 @@ export class CoreSitesProvider {
message += config.maintenancemessage; message += config.maintenancemessage;
} }
throw new CoreSiteError({ throw new CoreLoginError({
message, message,
critical: true, critical: true,
}); });
@ -336,8 +336,8 @@ export class CoreSitesProvider {
errorcode: string, errorcode: string,
errorDetails: string, errorDetails: string,
siteConfig: CoreSitePublicConfigResponse, siteConfig: CoreSitePublicConfigResponse,
): CoreSiteError { ): CoreLoginError {
return new CoreSiteError({ return new CoreLoginError({
errorcode, errorcode,
errorDetails, errorDetails,
siteConfig, siteConfig,
@ -349,16 +349,19 @@ export class CoreSitesProvider {
} }
/** /**
* Treat an error returned by getPublicConfig in checkSiteWithProtocol. Converts the error to a CoreSiteError. * Treat an error returned by getPublicConfig in checkSiteWithProtocol. Converts the error to a CoreLoginError.
* *
* @param siteUrl Site URL. * @param siteUrl Site URL.
* @param error Error returned. * @param error Error returned.
* @return Promise resolved with the treated error. * @return Promise resolved with the treated error.
*/ */
protected async treatGetPublicConfigError(siteUrl: string, error: CoreAjaxError | CoreAjaxWSError): Promise<CoreSiteError> { protected async treatGetPublicConfigError(
if (!('errorcode' in error)) { siteUrl: string,
error: CoreError | CoreAjaxError | CoreAjaxWSError,
): Promise<CoreLoginError> {
if (error instanceof CoreAjaxError || !('errorcode' in error)) {
// The WS didn't return data, probably cannot connect. // The WS didn't return data, probably cannot connect.
return new CoreSiteError({ return new CoreLoginError({
message: error.message || '', message: error.message || '',
critical: false, // Allow fallback to http if siteUrl uses https. critical: false, // Allow fallback to http if siteUrl uses https.
}); });
@ -385,7 +388,7 @@ export class CoreSitesProvider {
critical = false; // Keep checking fallback URLs. critical = false; // Keep checking fallback URLs.
} }
return new CoreSiteError({ return new CoreLoginError({
message: error.message, message: error.message,
errorcode: error.errorcode, errorcode: error.errorcode,
critical, critical,
@ -410,27 +413,27 @@ export class CoreSitesProvider {
.toPromise(); .toPromise();
} catch (error) { } catch (error) {
// Default error messages are kinda bad, return our own message. // Default error messages are kinda bad, return our own message.
throw new CoreSiteError({ throw new CoreLoginError({
message: Translate.instant('core.cannotconnecttrouble'), message: Translate.instant('core.cannotconnecttrouble'),
}); });
} }
if (data === null) { if (data === null) {
// Cannot connect. // Cannot connect.
throw new CoreSiteError({ throw new CoreLoginError({
message: Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }), message: Translate.instant('core.cannotconnect', { $a: CoreSite.MINIMUM_MOODLE_VERSION }),
}); });
} }
if (data.errorcode && (data.errorcode == 'enablewsdescription' || data.errorcode == 'requirecorrectaccess')) { if (data.errorcode && (data.errorcode == 'enablewsdescription' || data.errorcode == 'requirecorrectaccess')) {
throw new CoreSiteError({ throw new CoreLoginError({
errorcode: data.errorcode, errorcode: data.errorcode,
message: data.error ?? '', message: data.error ?? '',
}); });
} }
if (data.error && data.error == 'Web services must be enabled in Advanced features.') { if (data.error && data.error == 'Web services must be enabled in Advanced features.') {
throw new CoreSiteError({ throw new CoreLoginError({
errorcode: 'enablewsdescription', errorcode: 'enablewsdescription',
message: data.error, message: data.error,
}); });
@ -492,13 +495,13 @@ export class CoreSitesProvider {
const redirect = await CoreUtils.checkRedirect(loginUrl); const redirect = await CoreUtils.checkRedirect(loginUrl);
if (redirect) { if (redirect) {
throw new CoreSiteError({ throw new CoreLoginError({
message: Translate.instant('core.login.sitehasredirect'), message: Translate.instant('core.login.sitehasredirect'),
}); });
} }
} }
throw new CoreSiteError({ throw new CoreLoginError({
message: data.error, message: data.error,
errorcode: data.errorcode, errorcode: data.errorcode,
}); });
@ -641,7 +644,7 @@ export class CoreSitesProvider {
await this.setSiteLoggedOut(siteId); await this.setSiteLoggedOut(siteId);
} }
throw new CoreSiteError({ throw new CoreLoginError({
message: Translate.instant(errorKey, translateParams), message: Translate.instant(errorKey, translateParams),
errorcode: errorCode, errorcode: errorCode,
loggedOut: true, loggedOut: true,