From 9ded4b7c5ba03ce4d0ec65d12e122afc0dda5d89 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 23 Feb 2022 16:14:28 +0100 Subject: [PATCH] MOBILE-3780 core: Don't store offline if 4xx or 5xx http error --- src/addons/mod/assign/pages/edit/edit.ts | 3 +- src/addons/mod/data/pages/edit/edit.ts | 3 +- src/addons/mod/forum/components/post/post.ts | 2 +- src/addons/mod/forum/services/forum-helper.ts | 4 +++ src/addons/mod/glossary/pages/edit/edit.ts | 7 ++++- .../assessment-strategy.ts | 6 +++- .../pages/edit-submission/edit-submission.ts | 7 ++++- src/core/classes/errors/errors.ts | 2 ++ src/core/classes/errors/httperror.ts | 30 +++++++++++++++++++ src/core/services/utils/utils.ts | 11 +++++-- src/core/services/ws.ts | 26 ++++++++++++---- 11 files changed, 87 insertions(+), 14 deletions(-) create mode 100644 src/core/classes/errors/httperror.ts diff --git a/src/addons/mod/assign/pages/edit/edit.ts b/src/addons/mod/assign/pages/edit/edit.ts index 01ddb7499..6e0f06b8d 100644 --- a/src/addons/mod/assign/pages/edit/edit.ts +++ b/src/addons/mod/assign/pages/edit/edit.ts @@ -36,6 +36,7 @@ import { import { AddonModAssignHelper } from '../../services/assign-helper'; import { AddonModAssignOffline } from '../../services/assign-offline'; import { AddonModAssignSync } from '../../services/assign-sync'; +import { CoreUtils } from '@services/utils/utils'; /** * Page that allows adding or editing an assigment submission. @@ -255,7 +256,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy, CanLeave { this.hasOffline, ); } catch (error) { - if (this.allowOffline && !this.saveOffline) { + if (this.allowOffline && !this.saveOffline && !CoreUtils.isWebServiceError(error)) { // Cannot submit in online, prepare for offline usage. this.saveOffline = true; diff --git a/src/addons/mod/data/pages/edit/edit.ts b/src/addons/mod/data/pages/edit/edit.ts index dc307eaa2..e6878e177 100644 --- a/src/addons/mod/data/pages/edit/edit.ts +++ b/src/addons/mod/data/pages/edit/edit.ts @@ -266,9 +266,10 @@ export class AddonModDataEditPage implements OnInit { this.offline, ); } catch (error) { - if (this.offline) { + if (this.offline || CoreUtils.isWebServiceError(error)) { throw error; } + // Cannot submit in online, prepare for offline usage. this.offline = true; diff --git a/src/addons/mod/forum/components/post/post.ts b/src/addons/mod/forum/components/post/post.ts index 2a2cf19ed..cfd60670f 100644 --- a/src/addons/mod/forum/components/post/post.ts +++ b/src/addons/mod/forum/components/post/post.ts @@ -364,7 +364,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges ); } catch (error) { // Cannot upload them in online, save them in offline. - if (!this.forum.id || isEditOnline) { + if (!this.forum.id || isEditOnline || CoreUtils.isWebServiceError(error)) { // Cannot store them in offline. Reject. throw error; } diff --git a/src/addons/mod/forum/services/forum-helper.ts b/src/addons/mod/forum/services/forum-helper.ts index 0519efe28..47c2bd0cc 100644 --- a/src/addons/mod/forum/services/forum-helper.ts +++ b/src/addons/mod/forum/services/forum-helper.ts @@ -106,6 +106,10 @@ export class AddonModForumHelperProvider { try { await Promise.all(promises); } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. saveOffline = true; diff --git a/src/addons/mod/glossary/pages/edit/edit.ts b/src/addons/mod/glossary/pages/edit/edit.ts index 2edc0d440..127a5ea4a 100644 --- a/src/addons/mod/glossary/pages/edit/edit.ts +++ b/src/addons/mod/glossary/pages/edit/edit.ts @@ -25,6 +25,7 @@ import { CoreNavigator } from '@services/navigator'; import { CoreSites } from '@services/sites'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; +import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreForms } from '@singletons/form'; @@ -392,7 +393,11 @@ export class AddonModGlossaryEditPage implements OnInit, OnDestroy, CanLeave { saveOffline: false, attachmentsResult, }; - } catch { + } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. const attachmentsResult = await AddonModGlossaryHelper.storeFiles( this.glossary.id, diff --git a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts index f46b85d90..26d9b61c1 100644 --- a/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts +++ b/src/addons/mod/workshop/components/assessment-strategy/assessment-strategy.ts @@ -304,7 +304,11 @@ export class AddonModWorkshopAssessmentStrategyComponent implements OnInit, OnDe files, saveOffline, ); - } catch { + } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. saveOffline = true; allowOffline = true; diff --git a/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts b/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts index aa215a1ce..23b7e7e5e 100644 --- a/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts +++ b/src/addons/mod/workshop/pages/edit-submission/edit-submission.ts @@ -25,6 +25,7 @@ import { CoreSites } from '@services/sites'; import { CoreSync } from '@services/sync'; import { CoreDomUtils } from '@services/utils/dom'; import { CoreTextUtils } from '@services/utils/text'; +import { CoreUtils } from '@services/utils/utils'; import { Translate } from '@singletons'; import { CoreEvents } from '@singletons/events'; import { CoreForms } from '@singletons/form'; @@ -349,7 +350,11 @@ export class AddonModWorkshopEditSubmissionPage implements OnInit, OnDestroy, Ca inputData.attachmentfiles, false, ); - } catch { + } catch (error) { + if (CoreUtils.isWebServiceError(error)) { + throw error; + } + // Cannot upload them in online, save them in offline. saveOffline = true; allowOffline = true; diff --git a/src/core/classes/errors/errors.ts b/src/core/classes/errors/errors.ts index 94b34a72f..517d91910 100644 --- a/src/core/classes/errors/errors.ts +++ b/src/core/classes/errors/errors.ts @@ -24,6 +24,7 @@ import { CoreCaptureError } from './captureerror'; import { CoreNetworkError } from './network-error'; import { CoreSiteError } from './siteerror'; import { CoreErrorWithTitle } from './errorwithtitle'; +import { CoreHttpError } from './httperror'; export const CORE_ERRORS_CLASSES: Type[] = [ CoreAjaxError, @@ -36,4 +37,5 @@ export const CORE_ERRORS_CLASSES: Type[] = [ CoreSiteError, CoreWSError, CoreErrorWithTitle, + CoreHttpError, ]; diff --git a/src/core/classes/errors/httperror.ts b/src/core/classes/errors/httperror.ts new file mode 100644 index 000000000..598cc4455 --- /dev/null +++ b/src/core/classes/errors/httperror.ts @@ -0,0 +1,30 @@ +// (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 { CoreError } from '@classes/errors/error'; + +/** + * HTTP error. + */ +export class CoreHttpError extends CoreError { + + status: number; // HTTP status. 0 if cannot connect or similar errors. + + constructor(message: string, status?: number) { + super(message); + + this.status = status ?? 0; + } + +} diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index 4808ccca5..e211d3350 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -858,12 +858,17 @@ export class CoreUtilsProvider { */ // eslint-disable-next-line @typescript-eslint/no-explicit-any isWebServiceError(error: any): boolean { - return error && (error.warningcode !== undefined || (error.errorcode !== undefined && - error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' && + return error && ( + error.warningcode !== undefined || + ( + error.errorcode !== undefined && error.errorcode != 'userdeleted' && error.errorcode != 'upgraderunning' && error.errorcode != 'forcepasswordchangenotice' && error.errorcode != 'usernotfullysetup' && error.errorcode != 'sitepolicynotagreed' && error.errorcode != 'sitemaintenance' && error.errorcode != 'wsaccessusersuspended' && error.errorcode != 'wsaccessuserdeleted' && - !this.isExpiredTokenError(error))); + !this.isExpiredTokenError(error) + ) || + error.status && error.status >= 400 // CoreHttpError, assume status 400 and above are like WebService errors. + ); } /** diff --git a/src/core/services/ws.ts b/src/core/services/ws.ts index bde6e1526..866ed0724 100644 --- a/src/core/services/ws.ts +++ b/src/core/services/ws.ts @@ -25,7 +25,7 @@ import { CoreNativeToAngularHttpResponse } from '@classes/native-to-angular-http import { CoreApp } from '@services/app'; import { CoreFile, CoreFileFormat } from '@services/file'; import { CoreMimetypeUtils } from '@services/utils/mimetype'; -import { CoreTextUtils } from '@services/utils/text'; +import { CoreTextErrorObject, CoreTextUtils } from '@services/utils/text'; import { CoreUtils, PromiseDefer } from '@services/utils/utils'; import { CoreConstants } from '@/core/constants'; import { CoreError } from '@classes/errors/error'; @@ -38,6 +38,7 @@ import { CoreAjaxError } from '@classes/errors/ajaxerror'; import { CoreAjaxWSError } from '@classes/errors/ajaxwserror'; import { CoreNetworkError } from '@classes/errors/network-error'; import { CoreSite } from '@classes/site'; +import { CoreHttpError } from '@classes/errors/httperror'; /** * This service allows performing WS calls and download/upload files. @@ -693,6 +694,8 @@ export class CoreWSProvider { return retryPromise; } else if (error.status === -2) { throw new CoreError(this.getCertificateErrorMessage(error.error)); + } else if (error.status > 0) { + throw this.createHttpError(error, error.status); } throw new CoreError(Translate.instant('core.serverconnection')); @@ -892,10 +895,7 @@ export class CoreWSProvider { } catch (error) { this.logger.error('Error while uploading file', filePath, error); - throw new CoreError(CoreTextUtils.buildSeveralParagraphsMessage([ - Translate.instant('core.cannotconnecttrouble'), - CoreTextUtils.getHTMLBodyContent(CoreTextUtils.getErrorMessageFromError(error) || ''), - ])); + throw this.createHttpError(error, error.http_status ?? 0); } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -937,6 +937,22 @@ export class CoreWSProvider { return data[0]; } + /** + * Create a CoreHttpError based on a certain error. + * + * @param error Original error. + * @param status Status code (if any). + * @return CoreHttpError. + */ + protected createHttpError(error: CoreTextErrorObject, status: number): CoreHttpError { + const message = CoreTextUtils.buildSeveralParagraphsMessage([ + Translate.instant('core.cannotconnecttrouble'), + CoreTextUtils.getHTMLBodyContent(CoreTextUtils.getErrorMessageFromError(error) || ''), + ]); + + return new CoreHttpError(message, status); + } + /** * Perform an HTTP request requesting for a text response. *