MOBILE-3659 course: Implement course sync
parent
9a935a3946
commit
310ee19d26
|
@ -0,0 +1,26 @@
|
|||
// (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 { Translate } from '@singletons';
|
||||
|
||||
/**
|
||||
* Network error. It will automatically set the right error message if none is provided.
|
||||
*/
|
||||
export class CoreNetworkError extends Error {
|
||||
|
||||
constructor(message?: string) {
|
||||
super(message || Translate.instance.instant('core.networkerrormsg'));
|
||||
}
|
||||
|
||||
}
|
|
@ -25,6 +25,9 @@ import { SITE_SCHEMA as LOG_SITE_SCHEMA } from './services/database/log';
|
|||
import { SITE_SCHEMA as PREFETCH_SITE_SCHEMA } from './services/database/module-prefetch';
|
||||
import { CoreCourseIndexRoutingModule } from './pages/index/index-routing.module';
|
||||
import { CoreCourseModulePrefetchDelegate } from './services/module-prefetch-delegate';
|
||||
import { CoreCronDelegate } from '@services/cron';
|
||||
import { CoreCourseLogCronHandler } from './services/handlers/log-cron';
|
||||
import { CoreCourseSyncCronHandler } from './services/handlers/sync-cron';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
|
@ -60,6 +63,9 @@ const courseIndexRoutes: Routes = [
|
|||
multi: true,
|
||||
deps: [],
|
||||
useFactory: () => () => {
|
||||
CoreCronDelegate.instance.register(CoreCourseSyncCronHandler.instance);
|
||||
CoreCronDelegate.instance.register(CoreCourseLogCronHandler.instance);
|
||||
|
||||
CoreCourseModulePrefetchDelegate.instance.initialize();
|
||||
},
|
||||
},
|
||||
|
|
|
@ -36,7 +36,7 @@ import {
|
|||
CoreCourseOptionsDelegate,
|
||||
CoreCourseOptionsMenuHandlerToDisplay,
|
||||
} from '@features/course/services/course-options-delegate';
|
||||
// import { CoreCourseSyncProvider } from '../../providers/sync';
|
||||
import { CoreCourseAutoSyncData, CoreCourseSync, CoreCourseSyncProvider } from '@features/course/services/sync';
|
||||
import { CoreCourseFormatComponent } from '../../components/format/format';
|
||||
import {
|
||||
CoreEvents,
|
||||
|
@ -144,15 +144,17 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy {
|
|||
},
|
||||
);
|
||||
|
||||
// @todo this.syncObserver = CoreEvents.on(CoreCourseSyncProvider.AUTO_SYNCED, (data) => {
|
||||
// if (data && data.courseId == this.course.id) {
|
||||
// this.refreshAfterCompletionChange(false);
|
||||
this.syncObserver = CoreEvents.on<CoreCourseAutoSyncData>(CoreCourseSyncProvider.AUTO_SYNCED, (data) => {
|
||||
if (!data || data.courseId != this.course.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (data.warnings && data.warnings[0]) {
|
||||
// CoreDomUtils.instance.showErrorModal(data.warnings[0]);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
this.refreshAfterCompletionChange(false);
|
||||
|
||||
if (data.warnings && data.warnings[0]) {
|
||||
CoreDomUtils.instance.showErrorModal(data.warnings[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,13 +212,11 @@ export class CoreCourseContentsPage implements OnInit, OnDestroy {
|
|||
|
||||
if (sync) {
|
||||
// Try to synchronize the course data.
|
||||
// @todo return this.syncProvider.syncCourse(this.course.id).then((result) => {
|
||||
// if (result.warnings && result.warnings.length) {
|
||||
// CoreDomUtils.instance.showErrorModal(result.warnings[0]);
|
||||
// }
|
||||
// }).catch(() => {
|
||||
// // For now we don't allow manual syncing, so ignore errors.
|
||||
// });
|
||||
// For now we don't allow manual syncing, so ignore errors.
|
||||
const result = await CoreUtils.instance.ignoreErrors(CoreCourseSync.instance.syncCourse(this.course.id));
|
||||
if (result?.warnings?.length) {
|
||||
CoreDomUtils.instance.showErrorModal(result.warnings[0]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -63,6 +63,7 @@ import { CoreTextUtils } from '@services/utils/text';
|
|||
import { CoreTimeUtils } from '@services/utils/time';
|
||||
import { CoreEventObserver, CoreEventPackageStatusChanged, CoreEvents } from '@singletons/events';
|
||||
import { CoreFilterHelper } from '@features/filter/services/filter-helper';
|
||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||
|
||||
/**
|
||||
* Prefetch info of a module.
|
||||
|
@ -732,7 +733,7 @@ export class CoreCourseHelperProvider {
|
|||
try {
|
||||
path = await CoreFilepool.instance.getInternalUrlByUrl(site.getId(), fileUrl);
|
||||
} catch {
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
return CoreUtils.instance.openFile(path);
|
||||
|
@ -857,7 +858,7 @@ export class CoreCourseHelperProvider {
|
|||
|
||||
if (!isOnline && status === CoreConstants.NOT_DOWNLOADED) {
|
||||
// Not downloaded and we're offline, reject.
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
const shouldDownloadFirst = await CoreFilepool.instance.shouldDownloadFileBeforeOpen(fixedUrl, mainFile.filesize);
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
// (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 { Injectable } from '@angular/core';
|
||||
|
||||
import { CoreCronHandler } from '@services/cron';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { makeSingleton } from '@singletons';
|
||||
|
||||
/**
|
||||
* Log cron handler. It will update last access of the user while app is open.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCourseLogCronHandlerService implements CoreCronHandler {
|
||||
|
||||
name = 'CoreCourseLogCronHandler';
|
||||
|
||||
/**
|
||||
* Execute the process.
|
||||
* Receives the ID of the site affected, undefined for all sites.
|
||||
*
|
||||
* @param siteId ID of the site affected, undefined for all sites.
|
||||
* @param force Wether the execution is forced (manual sync).
|
||||
* @return Promise resolved when done, rejected if failure.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async execute(siteId?: string, force?: boolean): Promise<void> {
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
return CoreCourse.instance.logView(site.getSiteHomeId(), undefined, site.getId(), site.getInfo()?.sitename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether it's a synchronization process or not.
|
||||
*
|
||||
* @return Whether it's a synchronization process or not.
|
||||
*/
|
||||
isSync(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time between consecutive executions.
|
||||
*
|
||||
* @return Time between consecutive executions (in ms).
|
||||
*/
|
||||
getInterval(): number {
|
||||
return 240000; // 4 minutes. By default platform will see the user as online if lastaccess is less than 5 minutes.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CoreCourseLogCronHandler extends makeSingleton(CoreCourseLogCronHandlerService) {}
|
|
@ -0,0 +1,52 @@
|
|||
// (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 { Injectable } from '@angular/core';
|
||||
|
||||
import { CoreCronHandler } from '@services/cron';
|
||||
import { makeSingleton } from '@singletons';
|
||||
import { CoreCourseSync } from '../sync';
|
||||
|
||||
/**
|
||||
* Synchronization cron handler.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCourseSyncCronHandlerService implements CoreCronHandler {
|
||||
|
||||
name = 'CoreCourseSyncCronHandler';
|
||||
|
||||
/**
|
||||
* Execute the process.
|
||||
* Receives the ID of the site affected, undefined for all sites.
|
||||
*
|
||||
* @param siteId ID of the site affected, undefined for all sites.
|
||||
* @param force Wether the execution is forced (manual sync).
|
||||
* @return Promise resolved when done, rejected if failure.
|
||||
*/
|
||||
execute(siteId?: string, force?: boolean): Promise<void> {
|
||||
return CoreCourseSync.instance.syncAllCourses(siteId, force);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time between consecutive executions.
|
||||
*
|
||||
* @return Time between consecutive executions (in ms).
|
||||
*/
|
||||
getInterval(): number {
|
||||
return CoreCourseSync.instance.syncInterval;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CoreCourseSyncCronHandler extends makeSingleton(CoreCourseSyncCronHandlerService) {}
|
|
@ -0,0 +1,260 @@
|
|||
// (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 { Injectable } from '@angular/core';
|
||||
|
||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
||||
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreApp } from '@services/app';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
import { CoreCourseOffline } from './course-offline';
|
||||
import { CoreCourse } from './course';
|
||||
import { CoreCourseLogHelper } from './log-helper';
|
||||
import { CoreWSExternalWarning } from '@services/ws';
|
||||
import { CoreCourseManualCompletionDBRecord } from './database/course';
|
||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { CoreEvents, CoreEventSiteData } from '@singletons/events';
|
||||
|
||||
/**
|
||||
* Service to sync course offline data. This only syncs the offline data of the course itself, not the offline data of
|
||||
* the activities in the course.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class CoreCourseSyncProvider extends CoreSyncBaseProvider<CoreCourseSyncResult> {
|
||||
|
||||
static readonly AUTO_SYNCED = 'core_course_autom_synced';
|
||||
|
||||
constructor() {
|
||||
super('CoreCourseSyncProvider');
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to synchronize all the courses in a certain site or in all sites.
|
||||
*
|
||||
* @param siteId Site ID to sync. If not defined, sync all sites.
|
||||
* @param force Wether the execution is forced (manual sync).
|
||||
* @return Promise resolved if sync is successful, rejected if sync fails.
|
||||
*/
|
||||
syncAllCourses(siteId?: string, force?: boolean): Promise<void> {
|
||||
return this.syncOnSites('courses', this.syncAllCoursesFunc.bind(this, siteId, force), siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync all courses on a site.
|
||||
*
|
||||
* @param siteId Site ID to sync.
|
||||
* @param force Wether the execution is forced (manual sync).
|
||||
* @return Promise resolved if sync is successful, rejected if sync fails.
|
||||
*/
|
||||
protected async syncAllCoursesFunc(siteId: string, force: boolean): Promise<void> {
|
||||
await Promise.all([
|
||||
CoreCourseLogHelper.instance.syncSite(siteId),
|
||||
this.syncCoursesCompletion(siteId, force),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync courses offline completion.
|
||||
*
|
||||
* @param siteId Site ID to sync.
|
||||
* @param force Wether the execution is forced (manual sync).
|
||||
* @return Promise resolved if sync is successful, rejected if sync fails.
|
||||
*/
|
||||
protected async syncCoursesCompletion(siteId: string, force: boolean): Promise<void> {
|
||||
const completions = await CoreCourseOffline.instance.getAllManualCompletions(siteId);
|
||||
|
||||
// Sync all courses.
|
||||
await Promise.all(completions.map(async (completion) => {
|
||||
const result = await (force ? this.syncCourse(completion.courseid, siteId) :
|
||||
this.syncCourseIfNeeded(completion.courseid, siteId));
|
||||
|
||||
if (!result || !result.updated) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync successful, send event.
|
||||
CoreEvents.trigger<CoreCourseAutoSyncData>(CoreCourseSyncProvider.AUTO_SYNCED, {
|
||||
courseId: completion.courseid,
|
||||
warnings: result.warnings,
|
||||
}, siteId);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync a course if it's needed.
|
||||
*
|
||||
* @param courseId Course ID to be synced.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved when the course is synced or it doesn't need to be synced.
|
||||
*/
|
||||
syncCourseIfNeeded(courseId: number, siteId?: string): Promise<CoreCourseSyncResult> {
|
||||
// Usually we call isSyncNeeded to check if a certain time has passed.
|
||||
// However, since we barely send data for now just sync the course.
|
||||
return this.syncCourse(courseId, siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronize a course.
|
||||
*
|
||||
* @param courseId Course ID to be synced.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved if sync is successful, rejected otherwise.
|
||||
*/
|
||||
async syncCourse(courseId: number, siteId?: string): Promise<CoreCourseSyncResult> {
|
||||
siteId = siteId || CoreSites.instance.getCurrentSiteId();
|
||||
|
||||
if (this.isSyncing(courseId, siteId)) {
|
||||
// There's already a sync ongoing for this discussion, return the promise.
|
||||
return this.getOngoingSync(courseId, siteId)!;
|
||||
}
|
||||
|
||||
this.logger.debug(`Try to sync course '${courseId}'`);
|
||||
|
||||
return this.addOngoingSync(courseId, this.syncCourseCompletion(courseId, siteId), siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync course offline completion.
|
||||
*
|
||||
* @param courseId Course ID to be synced.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved if sync is successful, rejected otherwise.
|
||||
*/
|
||||
protected async syncCourseCompletion(courseId: number, siteId?: string): Promise<CoreCourseSyncResult> {
|
||||
const result: CoreCourseSyncResult = {
|
||||
warnings: [],
|
||||
updated: false,
|
||||
};
|
||||
|
||||
// Get offline responses to be sent.
|
||||
const completions = await CoreUtils.instance.ignoreErrors(
|
||||
CoreCourseOffline.instance.getCourseManualCompletions(courseId, siteId),
|
||||
<CoreCourseManualCompletionDBRecord[]> [],
|
||||
);
|
||||
|
||||
|
||||
if (!completions || !completions.length) {
|
||||
// Nothing to sync, set sync time.
|
||||
await this.setSyncTime(String(courseId), siteId);
|
||||
|
||||
// All done, return the data.
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!CoreApp.instance.isOnline()) {
|
||||
// Cannot sync in offline.
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
// Get the current completion status to check if any completion was modified in web.
|
||||
// This can be retrieved on core_course_get_contents since 3.6 but this is an easy way to get them.
|
||||
const onlineCompletions = await CoreCourse.instance.getActivitiesCompletionStatus(
|
||||
courseId,
|
||||
siteId,
|
||||
undefined,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
|
||||
// Send all the completions.
|
||||
await Promise.all(completions.map(async (entry) => {
|
||||
const onlineComp = onlineCompletions[entry.cmid];
|
||||
|
||||
// Check if the completion was modified in online. If so, discard it.
|
||||
if (onlineComp && onlineComp.timecompleted * 1000 > entry.timecompleted) {
|
||||
await CoreCourseOffline.instance.deleteManualCompletion(entry.cmid, siteId);
|
||||
|
||||
// Completion deleted, add a warning if the completion status doesn't match.
|
||||
if (onlineComp.state != entry.completed) {
|
||||
result.warnings.push(Translate.instance.instant('core.course.warningofflinemanualcompletiondeleted', {
|
||||
name: entry.coursename || courseId,
|
||||
error: Translate.instance.instant('core.course.warningmanualcompletionmodified'),
|
||||
}));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await CoreCourse.instance.markCompletedManuallyOnline(entry.cmid, !!entry.completed, siteId);
|
||||
|
||||
result.updated = true;
|
||||
|
||||
await CoreCourseOffline.instance.deleteManualCompletion(entry.cmid, siteId);
|
||||
} catch (error) {
|
||||
if (!CoreUtils.instance.isWebServiceError(error)) {
|
||||
// Couldn't connect to server, reject.
|
||||
throw error;
|
||||
}
|
||||
|
||||
// The WebService has thrown an error, this means that the completion cannot be submitted. Delete it.
|
||||
result.updated = true;
|
||||
|
||||
await CoreCourseOffline.instance.deleteManualCompletion(entry.cmid, siteId);
|
||||
|
||||
// Completion deleted, add a warning.
|
||||
result.warnings.push(Translate.instance.instant('core.course.warningofflinemanualcompletiondeleted', {
|
||||
name: entry.coursename || courseId,
|
||||
error: CoreTextUtils.instance.getErrorMessageFromError(error),
|
||||
}));
|
||||
}
|
||||
}));
|
||||
|
||||
if (result.updated) {
|
||||
try {
|
||||
// Update data.
|
||||
await CoreCourse.instance.invalidateSections(courseId, siteId);
|
||||
|
||||
const currentSite = CoreSites.instance.getCurrentSite();
|
||||
|
||||
if (currentSite?.isVersionGreaterEqualThan('3.6')) {
|
||||
await CoreCourse.instance.getSections(courseId, false, true, undefined, siteId);
|
||||
} else {
|
||||
await CoreCourse.instance.getActivitiesCompletionStatus(courseId, siteId);
|
||||
}
|
||||
} catch {
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
|
||||
// Sync finished, set sync time.
|
||||
await this.setSyncTime(String(courseId), siteId);
|
||||
|
||||
// All done, return the data.
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class CoreCourseSync extends makeSingleton(CoreCourseSyncProvider) {}
|
||||
|
||||
/**
|
||||
* Result of course sync.
|
||||
*/
|
||||
export type CoreCourseSyncResult = {
|
||||
updated: boolean;
|
||||
warnings: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Data passed to AUTO_SYNCED event.
|
||||
*/
|
||||
export type CoreCourseAutoSyncData = CoreEventSiteData & {
|
||||
courseId: number;
|
||||
warnings: CoreWSExternalWarning[];
|
||||
};
|
|
@ -26,6 +26,7 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
import { CoreConstants } from '@/core/constants';
|
||||
import { CoreError } from '@classes/errors/error';
|
||||
import { makeSingleton, Translate } from '@singletons';
|
||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||
|
||||
/**
|
||||
* Provider to provide some helper functions regarding files and packages.
|
||||
|
@ -152,7 +153,7 @@ export class CoreFileHelperProvider {
|
|||
} else {
|
||||
if (!isOnline && !this.isStateDownloaded(state)) {
|
||||
// Not downloaded and user is offline, reject.
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
if (onProgress) {
|
||||
|
|
|
@ -49,6 +49,7 @@ import {
|
|||
SchemaVersionsDBEntry,
|
||||
} from '@services/database/sites';
|
||||
import { CoreArray } from '../singletons/array';
|
||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||
|
||||
export const CORE_SITE_SCHEMAS = new InjectionToken('CORE_SITE_SCHEMAS');
|
||||
|
||||
|
@ -136,7 +137,7 @@ export class CoreSitesProvider {
|
|||
if (!CoreUrlUtils.instance.isHttpURL(siteUrl)) {
|
||||
throw new CoreError(Translate.instance.instant('core.login.invalidsite'));
|
||||
} else if (!CoreApp.instance.isOnline()) {
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -359,7 +360,7 @@ export class CoreSitesProvider {
|
|||
retry?: boolean,
|
||||
): Promise<CoreSiteUserTokenResponse> {
|
||||
if (!CoreApp.instance.isOnline()) {
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
if (!service) {
|
||||
|
|
|
@ -35,6 +35,7 @@ import { CoreSilentError } from '@classes/errors/silenterror';
|
|||
import { makeSingleton, Translate, AlertController, LoadingController, ToastController } from '@singletons';
|
||||
import { CoreLogger } from '@singletons/logger';
|
||||
import { CoreFileSizeSum } from '@services/plugin-file-delegate';
|
||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||
|
||||
/*
|
||||
* "Utils" service with helper functions for UI, DOM elements and HTML code.
|
||||
|
@ -642,11 +643,13 @@ export class CoreDomUtilsProvider {
|
|||
* Given a message, it deduce if it's a network error.
|
||||
*
|
||||
* @param message Message text.
|
||||
* @param error Error object.
|
||||
* @return True if the message error is a network error, false otherwise.
|
||||
*/
|
||||
protected isNetworkError(message: string): boolean {
|
||||
protected isNetworkError(message: string, error?: CoreError | CoreTextErrorObject | string): boolean {
|
||||
return message == Translate.instance.instant('core.networkerrormsg') ||
|
||||
message == Translate.instance.instant('core.fileuploader.errormustbeonlinetoupload');
|
||||
message == Translate.instance.instant('core.fileuploader.errormustbeonlinetoupload') ||
|
||||
error instanceof CoreNetworkError;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1365,7 +1368,7 @@ export class CoreDomUtilsProvider {
|
|||
buttons: [Translate.instance.instant('core.ok')],
|
||||
};
|
||||
|
||||
if (this.isNetworkError(message)) {
|
||||
if (this.isNetworkError(message, error)) {
|
||||
alertOptions.cssClass = 'core-alert-network-error';
|
||||
} else {
|
||||
alertOptions.header = Translate.instance.instant('core.error');
|
||||
|
|
|
@ -36,6 +36,7 @@ import { CoreLogger } from '@singletons/logger';
|
|||
import { CoreWSError } from '@classes/errors/wserror';
|
||||
import { CoreAjaxError } from '@classes/errors/ajaxerror';
|
||||
import { CoreAjaxWSError } from '@classes/errors/ajaxwserror';
|
||||
import { CoreNetworkError } from '@classes/errors/network-error';
|
||||
|
||||
/**
|
||||
* This service allows performing WS calls and download/upload files.
|
||||
|
@ -107,7 +108,7 @@ export class CoreWSProvider {
|
|||
if (!preSets) {
|
||||
throw new CoreError(Translate.instance.instant('core.unexpectederror'));
|
||||
} else if (!CoreApp.instance.isOnline()) {
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
preSets.typeExpected = preSets.typeExpected || 'object';
|
||||
|
@ -249,7 +250,7 @@ export class CoreWSProvider {
|
|||
this.logger.debug('Downloading file', url, path, addExtension);
|
||||
|
||||
if (!CoreApp.instance.isOnline()) {
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
// Use a tmp path to download the file and then move it to final location.
|
||||
|
@ -741,7 +742,7 @@ export class CoreWSProvider {
|
|||
if (!preSets) {
|
||||
throw new CoreError(Translate.instance.instant('core.unexpectederror'));
|
||||
} else if (!CoreApp.instance.isOnline()) {
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
preSets.typeExpected = preSets.typeExpected || 'object';
|
||||
|
@ -825,7 +826,7 @@ export class CoreWSProvider {
|
|||
}
|
||||
|
||||
if (!CoreApp.instance.isOnline()) {
|
||||
throw new CoreError(Translate.instance.instant('core.networkerrormsg'));
|
||||
throw new CoreNetworkError();
|
||||
}
|
||||
|
||||
const uploadUrl = preSets.siteUrl + '/webservice/upload.php';
|
||||
|
|
Loading…
Reference in New Issue