MOBILE-2873 sync: Sync activities on course prefetch

main
Pau Ferrer Ocaña 2019-03-05 17:09:07 +01:00
parent a26fbeab92
commit 910ee50600
21 changed files with 306 additions and 73 deletions

View File

@ -28,6 +28,7 @@ import { CoreGradesHelperProvider } from '@core/grades/providers/helper';
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModAssignProvider } from './assign'; import { AddonModAssignProvider } from './assign';
import { AddonModAssignHelperProvider } from './helper'; import { AddonModAssignHelperProvider } from './helper';
import { AddonModAssignSyncProvider } from './assign-sync';
import { AddonModAssignFeedbackDelegate } from './feedback-delegate'; import { AddonModAssignFeedbackDelegate } from './feedback-delegate';
import { AddonModAssignSubmissionDelegate } from './submission-delegate'; import { AddonModAssignSubmissionDelegate } from './submission-delegate';
@ -47,7 +48,8 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
protected textUtils: CoreTextUtilsProvider, protected feedbackDelegate: AddonModAssignFeedbackDelegate, protected textUtils: CoreTextUtilsProvider, protected feedbackDelegate: AddonModAssignFeedbackDelegate,
protected submissionDelegate: AddonModAssignSubmissionDelegate, protected courseHelper: CoreCourseHelperProvider, protected submissionDelegate: AddonModAssignSubmissionDelegate, protected courseHelper: CoreCourseHelperProvider,
protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider, protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider,
protected userProvider: CoreUserProvider, protected assignHelper: AddonModAssignHelperProvider) { protected userProvider: CoreUserProvider, protected assignHelper: AddonModAssignHelperProvider,
protected syncProvider: AddonModAssignSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -454,4 +456,15 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
return Promise.all(promises); return Promise.all(promises);
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
return this.syncProvider.syncAssign(module.instance, siteId);
}
} }

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 { Injectable } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreFilepoolProvider } from '@providers/filepool';
@ -22,6 +22,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModChoiceSyncProvider } from './sync';
import { AddonModChoiceProvider } from './choice'; import { AddonModChoiceProvider } from './choice';
/** /**
@ -34,10 +35,12 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan
component = AddonModChoiceProvider.COMPONENT; component = AddonModChoiceProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^answers$/; updatesNames = /^configuration$|^.*files$|^answers$/;
protected syncProvider: AddonModChoiceSyncProvider; // It will be injected later to prevent circular dependencies.
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected choiceProvider: AddonModChoiceProvider, domUtils: CoreDomUtilsProvider, protected choiceProvider: AddonModChoiceProvider,
protected userProvider: CoreUserProvider) { protected userProvider: CoreUserProvider, protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -133,4 +136,19 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan
invalidateModule(module: any, courseId: number): Promise<any> { invalidateModule(module: any, courseId: number): Promise<any> {
return this.choiceProvider.invalidateChoiceData(courseId); return this.choiceProvider.invalidateChoiceData(courseId);
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
if (!this.syncProvider) {
this.syncProvider = this.injector.get(AddonModChoiceSyncProvider);
}
return this.syncProvider.syncChoice(module.instance, undefined, siteId);
}
} }

View File

@ -127,12 +127,13 @@ export class AddonModChoiceSyncProvider extends CoreCourseActivitySyncBaseProvid
* Synchronize a choice. * Synchronize a choice.
* *
* @param {number} choiceId Choice ID to be synced. * @param {number} choiceId Choice ID to be synced.
* @param {number} userId User the answers belong to. * @param {number} [userId] User the answers belong to.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise. * @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
*/ */
syncChoice(choiceId: number, userId: number, siteId?: string): Promise<any> { syncChoice(choiceId: number, userId?: number, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
userId = userId || this.sitesProvider.getCurrentSiteUserId();
const syncId = this.getSyncId(choiceId, userId); const syncId = this.getSyncId(choiceId, userId);
if (this.isSyncing(syncId, siteId)) { if (this.isSyncing(syncId, siteId)) {

View File

@ -27,6 +27,7 @@ import { AddonModDataHelperProvider } from '../../providers/helper';
import { AddonModDataOfflineProvider } from '../../providers/offline'; import { AddonModDataOfflineProvider } from '../../providers/offline';
import { AddonModDataSyncProvider } from '../../providers/sync'; import { AddonModDataSyncProvider } from '../../providers/sync';
import { AddonModDataComponentsModule } from '../components.module'; import { AddonModDataComponentsModule } from '../components.module';
import { AddonModDataPrefetchHandler } from '../../providers/prefetch-handler';
/** /**
* Component that displays a data index page. * Component that displays a data index page.
@ -82,7 +83,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
constructor(injector: Injector, private dataProvider: AddonModDataProvider, private dataHelper: AddonModDataHelperProvider, constructor(injector: Injector, private dataProvider: AddonModDataProvider, private dataHelper: AddonModDataHelperProvider,
private dataOffline: AddonModDataOfflineProvider, @Optional() content: Content, private dataOffline: AddonModDataOfflineProvider, @Optional() content: Content,
private dataSync: AddonModDataSyncProvider, private timeUtils: CoreTimeUtilsProvider, private prefetchHandler: AddonModDataPrefetchHandler, private timeUtils: CoreTimeUtilsProvider,
private groupsProvider: CoreGroupsProvider, private commentsProvider: CoreCommentsProvider, private groupsProvider: CoreGroupsProvider, private commentsProvider: CoreCommentsProvider,
private modalCtrl: ModalController, private utils: CoreUtilsProvider, protected navCtrl: NavController, private modalCtrl: ModalController, private utils: CoreUtilsProvider, protected navCtrl: NavController,
private ratingOffline: CoreRatingOfflineProvider) { private ratingOffline: CoreRatingOfflineProvider) {
@ -520,17 +521,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
protected sync(): Promise<any> { protected sync(): Promise<any> {
const promises = [ return this.prefetchHandler.sync(this.module);
this.dataSync.syncDatabase(this.data.id),
this.dataSync.syncRatings(this.data.coursemodule)
];
return Promise.all(promises).then((results) => {
return results.reduce((a, b) => ({
updated: a.updated || b.updated,
warnings: (a.warnings || []).concat(b.warnings || []),
}), {updated: false});
});
} }
/** /**

View File

@ -26,6 +26,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { CoreRatingProvider } from '@core/rating/providers/rating'; import { CoreRatingProvider } from '@core/rating/providers/rating';
import { AddonModDataProvider } from './data'; import { AddonModDataProvider } from './data';
import { AddonModDataSyncProvider } from './sync';
import { AddonModDataHelperProvider } from './helper'; import { AddonModDataHelperProvider } from './helper';
/** /**
@ -43,7 +44,7 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
domUtils: CoreDomUtilsProvider, protected dataProvider: AddonModDataProvider, domUtils: CoreDomUtilsProvider, protected dataProvider: AddonModDataProvider,
protected timeUtils: CoreTimeUtilsProvider, protected dataHelper: AddonModDataHelperProvider, protected timeUtils: CoreTimeUtilsProvider, protected dataHelper: AddonModDataHelperProvider,
protected groupsProvider: CoreGroupsProvider, protected commentsProvider: CoreCommentsProvider, protected groupsProvider: CoreGroupsProvider, protected commentsProvider: CoreCommentsProvider,
private ratingProvider: CoreRatingProvider) { private ratingProvider: CoreRatingProvider, protected syncProvider: AddonModDataSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -301,4 +302,25 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
return Promise.all(promises); return Promise.all(promises);
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
const promises = [
this.syncProvider.syncDatabase(module.instance, siteId),
this.syncProvider.syncRatings(module.id, true, siteId)
];
return Promise.all(promises).then((results) => {
return results.reduce((a, b) => ({
updated: a.updated || b.updated,
warnings: (a.warnings || []).concat(b.warnings || []),
}), {updated: false});
});
}
} }

View File

@ -114,7 +114,7 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
return Promise.all(this.utils.objectToArray(promises)); return Promise.all(this.utils.objectToArray(promises));
})); }));
promises.push(this.syncRatings(undefined, siteId)); promises.push(this.syncRatings(undefined, force, siteId));
return Promise.all(promises); return Promise.all(promises);
} }
@ -362,13 +362,14 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
* Synchronize offline ratings. * Synchronize offline ratings.
* *
* @param {number} [cmId] Course module to be synced. If not defined, sync all databases. * @param {number} [cmId] Course module to be synced. If not defined, sync all databases.
* @param {boolean} [force] Wether to force sync not depending on last execution.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise. * @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
*/ */
syncRatings(cmId?: number, siteId?: string): Promise<any> { syncRatings(cmId?: number, force?: boolean, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.ratingSync.syncRatings('mod_data', 'entry', 'module', cmId, 0, siteId).then((results) => { return this.ratingSync.syncRatings('mod_data', 'entry', 'module', cmId, 0, force, siteId).then((results) => {
let updated = false; let updated = false;
const warnings = []; const warnings = [];
const promises = []; const promises = [];

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 { Injectable } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreFilepoolProvider } from '@providers/filepool';
@ -25,6 +25,7 @@ import { AddonModFeedbackProvider } from './feedback';
import { AddonModFeedbackHelperProvider } from './helper'; import { AddonModFeedbackHelperProvider } from './helper';
import { CoreTimeUtilsProvider } from '@providers/utils/time'; import { CoreTimeUtilsProvider } from '@providers/utils/time';
import { CoreGroupsProvider } from '@providers/groups'; import { CoreGroupsProvider } from '@providers/groups';
import { AddonModFeedbackSyncProvider } from './sync';
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
/** /**
@ -37,11 +38,14 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
component = AddonModFeedbackProvider.COMPONENT; component = AddonModFeedbackProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^attemptsfinished|^attemptsunfinished$/; updatesNames = /^configuration$|^.*files$|^attemptsfinished|^attemptsunfinished$/;
protected syncProvider: AddonModFeedbackSyncProvider; // It will be injected later to prevent circular dependencies.
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected feedbackProvider: AddonModFeedbackProvider, domUtils: CoreDomUtilsProvider, protected feedbackProvider: AddonModFeedbackProvider,
protected userProvider: CoreUserProvider, protected feedbackHelper: AddonModFeedbackHelperProvider, protected userProvider: CoreUserProvider, protected feedbackHelper: AddonModFeedbackHelperProvider,
protected timeUtils: CoreTimeUtilsProvider, protected groupsProvider: CoreGroupsProvider) { protected timeUtils: CoreTimeUtilsProvider, protected groupsProvider: CoreGroupsProvider,
protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -239,4 +243,19 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
}); });
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
if (!this.syncProvider) {
this.syncProvider = this.injector.get(AddonModFeedbackSyncProvider);
}
return this.syncProvider.syncFeedback(module.instance, siteId);
}
} }

View File

@ -376,18 +376,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
protected sync(): Promise<boolean> { protected sync(): Promise<boolean> {
const promises = []; return this.prefetchHandler.sync(this.module);
promises.push(this.forumSync.syncForumDiscussions(this.forum.id));
promises.push(this.forumSync.syncForumReplies(this.forum.id));
promises.push(this.forumSync.syncRatings(this.forum.cmid));
return Promise.all(promises).then((results) => {
return results.reduce((a, b) => ({
updated: a.updated || b.updated,
warnings: (a.warnings || []).concat(b.warnings || []),
}), {updated: false});
});
} }
/** /**

View File

@ -24,6 +24,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
import { CoreGroupsProvider } from '@providers/groups'; import { CoreGroupsProvider } from '@providers/groups';
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModForumProvider } from './forum'; import { AddonModForumProvider } from './forum';
import { AddonModForumSyncProvider } from './sync';
import { CoreRatingProvider } from '@core/rating/providers/rating'; import { CoreRatingProvider } from '@core/rating/providers/rating';
/** /**
@ -46,7 +47,8 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
private groupsProvider: CoreGroupsProvider, private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider, private userProvider: CoreUserProvider,
private forumProvider: AddonModForumProvider, private forumProvider: AddonModForumProvider,
private ratingProvider: CoreRatingProvider) { private ratingProvider: CoreRatingProvider,
private syncProvider: AddonModForumSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -264,4 +266,26 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
} }
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
const promises = [];
promises.push(this.syncProvider.syncForumDiscussions(module.instance, undefined, siteId));
promises.push(this.syncProvider.syncForumReplies(module.instance, undefined, siteId));
promises.push(this.syncProvider.syncRatings(module.id, undefined, true, siteId));
return Promise.all(promises).then((results) => {
return results.reduce((a, b) => ({
updated: a.updated || b.updated,
warnings: (a.warnings || []).concat(b.warnings || []),
}), {updated: false});
});
}
} }

View File

@ -23,6 +23,7 @@ import { AddonModGlossaryProvider } from '../../providers/glossary';
import { AddonModGlossaryOfflineProvider } from '../../providers/offline'; import { AddonModGlossaryOfflineProvider } from '../../providers/offline';
import { AddonModGlossarySyncProvider } from '../../providers/sync'; import { AddonModGlossarySyncProvider } from '../../providers/sync';
import { AddonModGlossaryModePickerPopoverComponent } from '../mode-picker/mode-picker'; import { AddonModGlossaryModePickerPopoverComponent } from '../mode-picker/mode-picker';
import { AddonModGlossaryPrefetchHandler } from '../../providers/prefetch-handler';
type FetchMode = 'author_all' | 'cat_all' | 'newest_first' | 'recently_updated' | 'search' | 'letter_all'; type FetchMode = 'author_all' | 'cat_all' | 'newest_first' | 'recently_updated' | 'search' | 'letter_all';
@ -68,7 +69,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
private popoverCtrl: PopoverController, private popoverCtrl: PopoverController,
private glossaryProvider: AddonModGlossaryProvider, private glossaryProvider: AddonModGlossaryProvider,
private glossaryOffline: AddonModGlossaryOfflineProvider, private glossaryOffline: AddonModGlossaryOfflineProvider,
private glossarySync: AddonModGlossarySyncProvider, private prefetchHandler: AddonModGlossaryPrefetchHandler,
private ratingOffline: CoreRatingOfflineProvider) { private ratingOffline: CoreRatingOfflineProvider) {
super(injector); super(injector);
} }
@ -219,17 +220,7 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
protected sync(): Promise<boolean> { protected sync(): Promise<boolean> {
const promises = [ return this.prefetchHandler.sync(this.module);
this.glossarySync.syncGlossaryEntries(this.glossary.id),
this.glossarySync.syncRatings(this.glossary.coursemodule)
];
return Promise.all(promises).then((results) => {
return results.reduce((a, b) => ({
updated: a.updated || b.updated,
warnings: (a.warnings || []).concat(b.warnings || []),
}), {updated: false});
});
} }
/** /**

View File

@ -24,6 +24,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModGlossaryProvider } from './glossary'; import { AddonModGlossaryProvider } from './glossary';
import { CoreRatingProvider } from '@core/rating/providers/rating'; import { CoreRatingProvider } from '@core/rating/providers/rating';
import { AddonModGlossarySyncProvider } from './sync';
/** /**
* Handler to prefetch forums. * Handler to prefetch forums.
@ -44,7 +45,8 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
domUtils: CoreDomUtilsProvider, domUtils: CoreDomUtilsProvider,
private userProvider: CoreUserProvider, private userProvider: CoreUserProvider,
private ratingProvider: CoreRatingProvider, private ratingProvider: CoreRatingProvider,
private glossaryProvider: AddonModGlossaryProvider) { private glossaryProvider: AddonModGlossaryProvider,
private syncProvider: AddonModGlossarySyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -187,4 +189,25 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
return Promise.all(promises); return Promise.all(promises);
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
const promises = [
this.syncProvider.syncGlossaryEntries(module.instance, undefined, siteId),
this.syncProvider.syncRatings(module.id, undefined, siteId)
];
return Promise.all(promises).then((results) => {
return results.reduce((a, b) => ({
updated: a.updated || b.updated,
warnings: (a.warnings || []).concat(b.warnings || []),
}), {updated: false});
});
}
} }

View File

@ -118,7 +118,7 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
return Promise.all(this.utils.objectToArray(promises)); return Promise.all(this.utils.objectToArray(promises));
})); }));
promises.push(this.syncRatings(undefined, siteId)); promises.push(this.syncRatings(undefined, force, siteId));
return Promise.all(promises); return Promise.all(promises);
} }
@ -259,13 +259,14 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
* Synchronize offline ratings. * Synchronize offline ratings.
* *
* @param {number} [cmId] Course module to be synced. If not defined, sync all glossaries. * @param {number} [cmId] Course module to be synced. If not defined, sync all glossaries.
* @param {boolean} [force] Wether to force sync not depending on last execution.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise. * @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
*/ */
syncRatings(cmId?: number, siteId?: string): Promise<any> { syncRatings(cmId?: number, force?: boolean, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
return this.ratingSync.syncRatings('mod_glossary', 'entry', 'module', cmId, 0, siteId).then((results) => { return this.ratingSync.syncRatings('mod_glossary', 'entry', 'module', cmId, 0, force, siteId).then((results) => {
let updated = false; let updated = false;
const warnings = []; const warnings = [];
const promises = []; const promises = [];

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 { Injectable } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { ModalController } from 'ionic-angular'; import { ModalController } from 'ionic-angular';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
@ -24,6 +24,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreGroupsProvider } from '@providers/groups'; import { CoreGroupsProvider } from '@providers/groups';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModLessonProvider } from './lesson'; import { AddonModLessonProvider } from './lesson';
import { AddonModLessonSyncProvider } from './lesson-sync';
/** /**
* Handler to prefetch lessons. * Handler to prefetch lessons.
@ -36,10 +37,12 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
// Don't check timers to decrease positives. If a user performs some action it will be reflected in other items. // Don't check timers to decrease positives. If a user performs some action it will be reflected in other items.
updatesNames = /^configuration$|^.*files$|^grades$|^gradeitems$|^pages$|^answers$|^questionattempts$|^pagesviewed$/; updatesNames = /^configuration$|^.*files$|^grades$|^gradeitems$|^pages$|^answers$|^questionattempts$|^pagesviewed$/;
protected syncProvider: AddonModLessonSyncProvider; // It will be injected later to prevent circular dependencies.
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected modalCtrl: ModalController, protected groupsProvider: CoreGroupsProvider, domUtils: CoreDomUtilsProvider, protected modalCtrl: ModalController, protected groupsProvider: CoreGroupsProvider,
protected lessonProvider: AddonModLessonProvider) { protected lessonProvider: AddonModLessonProvider, protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -429,4 +432,19 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
}); });
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
if (!this.syncProvider) {
this.syncProvider = this.injector.get(AddonModLessonSyncProvider);
}
return this.syncProvider.syncLesson(module.instance, false, false, siteId);
}
} }

View File

@ -554,4 +554,19 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
} }
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
if (!this.syncProvider) {
this.syncProvider = this.injector.get(AddonModQuizSyncProvider);
}
return this.syncProvider.syncQuiz(module.instance, false, siteId);
}
} }

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 { Injectable } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreFilepoolProvider } from '@providers/filepool';
@ -24,6 +24,7 @@ import { CoreFileProvider } from '@providers/file';
import { CoreTextUtilsProvider } from '@providers/utils/text'; import { CoreTextUtilsProvider } from '@providers/utils/text';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModScormProvider } from './scorm'; import { AddonModScormProvider } from './scorm';
import { AddonModScormSyncProvider } from './scorm-sync';
/** /**
* Progress event used when downloading a SCORM. * Progress event used when downloading a SCORM.
@ -58,10 +59,12 @@ export class AddonModScormPrefetchHandler extends CoreCourseActivityPrefetchHand
component = AddonModScormProvider.COMPONENT; component = AddonModScormProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^tracks$/; updatesNames = /^configuration$|^.*files$|^tracks$/;
protected syncProvider: AddonModScormSyncProvider; // It will be injected later to prevent circular dependencies.
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected fileProvider: CoreFileProvider, protected textUtils: CoreTextUtilsProvider, domUtils: CoreDomUtilsProvider, protected fileProvider: CoreFileProvider, protected textUtils: CoreTextUtilsProvider,
protected scormProvider: AddonModScormProvider) { protected scormProvider: AddonModScormProvider, protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -423,4 +426,19 @@ export class AddonModScormPrefetchHandler extends CoreCourseActivityPrefetchHand
return Promise.all(promises); return Promise.all(promises);
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
if (!this.syncProvider) {
this.syncProvider = this.injector.get(AddonModScormSyncProvider);
}
return this.syncProvider.syncScorm(module.instance, siteId);
}
} }

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 { Injectable } from '@angular/core'; import { Injectable, Injector } from '@angular/core';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { CoreAppProvider } from '@providers/app'; import { CoreAppProvider } from '@providers/app';
import { CoreFilepoolProvider } from '@providers/filepool'; import { CoreFilepoolProvider } from '@providers/filepool';
@ -22,6 +22,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
import { CoreCourseProvider } from '@core/course/providers/course'; import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler'; import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
import { AddonModSurveyProvider } from './survey'; import { AddonModSurveyProvider } from './survey';
import { AddonModSurveySyncProvider } from './sync';
import { AddonModSurveyHelperProvider } from './helper'; import { AddonModSurveyHelperProvider } from './helper';
/** /**
@ -34,10 +35,12 @@ export class AddonModSurveyPrefetchHandler extends CoreCourseActivityPrefetchHan
component = AddonModSurveyProvider.COMPONENT; component = AddonModSurveyProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^answers$/; updatesNames = /^configuration$|^.*files$|^answers$/;
protected syncProvider: AddonModSurveySyncProvider; // It will be injected later to prevent circular dependencies.
constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider, constructor(translate: TranslateService, appProvider: CoreAppProvider, utils: CoreUtilsProvider,
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected surveyProvider: AddonModSurveyProvider, domUtils: CoreDomUtilsProvider, protected surveyProvider: AddonModSurveyProvider,
protected surveyHelper: AddonModSurveyHelperProvider) { protected surveyHelper: AddonModSurveyHelperProvider, protected injector: Injector) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -126,4 +129,19 @@ export class AddonModSurveyPrefetchHandler extends CoreCourseActivityPrefetchHan
return Promise.all(promises); return Promise.all(promises);
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
if (!this.syncProvider) {
this.syncProvider = this.injector.get(AddonModSurveySyncProvider);
}
return this.syncProvider.syncSurvey(module.instance, undefined, siteId);
}
} }

View File

@ -130,12 +130,13 @@ export class AddonModSurveySyncProvider extends CoreCourseActivitySyncBaseProvid
* Synchronize a survey. * Synchronize a survey.
* *
* @param {number} surveyId Survey ID. * @param {number} surveyId Survey ID.
* @param {number} userId User the answers belong to. * @param {number} [userId] User the answers belong to. If not defined, current user.
* @param {string} [siteId] Site ID. If not defined, current site. * @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise. * @return {Promise<any>} Promise resolved if sync is successful, rejected otherwise.
*/ */
syncSurvey(surveyId: number, userId: number, siteId?: string): Promise<any> { syncSurvey(surveyId: number, userId?: number, siteId?: string): Promise<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId(); siteId = siteId || this.sitesProvider.getCurrentSiteId();
userId = userId || this.sitesProvider.getCurrentSiteUserId();
const syncId = this.getSyncId(surveyId, userId); const syncId = this.getSyncId(surveyId, userId);
if (this.isSyncing(syncId, siteId)) { if (this.isSyncing(syncId, siteId)) {

View File

@ -27,6 +27,7 @@ import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreGradesHelperProvider } from '@core/grades/providers/helper'; import { CoreGradesHelperProvider } from '@core/grades/providers/helper';
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModWikiProvider } from './wiki'; import { AddonModWikiProvider } from './wiki';
import { AddonModWikiSyncProvider } from './wiki-sync';
/** /**
* Handler to prefetch wikis. * Handler to prefetch wikis.
@ -42,7 +43,8 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider, courseProvider: CoreCourseProvider, filepoolProvider: CoreFilepoolProvider, sitesProvider: CoreSitesProvider,
domUtils: CoreDomUtilsProvider, protected wikiProvider: AddonModWikiProvider, protected userProvider: CoreUserProvider, domUtils: CoreDomUtilsProvider, protected wikiProvider: AddonModWikiProvider, protected userProvider: CoreUserProvider,
protected textUtils: CoreTextUtilsProvider, protected courseHelper: CoreCourseHelperProvider, protected textUtils: CoreTextUtilsProvider, protected courseHelper: CoreCourseHelperProvider,
protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider) { protected groupsProvider: CoreGroupsProvider, protected gradesHelper: CoreGradesHelperProvider,
protected syncProvider: AddonModWikiSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -210,4 +212,15 @@ export class AddonModWikiPrefetchHandler extends CoreCourseActivityPrefetchHandl
return Promise.all(promises); return Promise.all(promises);
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
return this.syncProvider.syncWiki(module.instance, module.course, module.id, siteId);
}
} }

View File

@ -24,6 +24,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
import { CoreGroupsProvider } from '@providers/groups'; import { CoreGroupsProvider } from '@providers/groups';
import { CoreUserProvider } from '@core/user/providers/user'; import { CoreUserProvider } from '@core/user/providers/user';
import { AddonModWorkshopProvider } from './workshop'; import { AddonModWorkshopProvider } from './workshop';
import { AddonModWorkshopSyncProvider } from './sync';
import { AddonModWorkshopHelperProvider } from './helper'; import { AddonModWorkshopHelperProvider } from './helper';
/** /**
@ -47,7 +48,8 @@ export class AddonModWorkshopPrefetchHandler extends CoreCourseActivityPrefetchH
private groupsProvider: CoreGroupsProvider, private groupsProvider: CoreGroupsProvider,
private userProvider: CoreUserProvider, private userProvider: CoreUserProvider,
private workshopProvider: AddonModWorkshopProvider, private workshopProvider: AddonModWorkshopProvider,
private workshopHelper: AddonModWorkshopHelperProvider) { private workshopHelper: AddonModWorkshopHelperProvider,
private syncProvider: AddonModWorkshopSyncProvider) {
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils); super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
} }
@ -365,4 +367,15 @@ export class AddonModWorkshopPrefetchHandler extends CoreCourseActivityPrefetchH
}); });
}); });
} }
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync(module: any, siteId?: string): Promise<any> {
return this.syncProvider.syncWorkshop(module.instance, siteId);
}
} }

View File

@ -294,6 +294,7 @@ export class CoreCourseHelperProvider {
} }
return promise.then((sections) => { return promise.then((sections) => {
// Confirm the download. // Confirm the download.
return this.confirmDownloadSizeSection(course.id, undefined, sections, true).then(() => { return this.confirmDownloadSizeSection(course.id, undefined, sections, true).then(() => {
// User confirmed, get the course handlers if needed. // User confirmed, get the course handlers if needed.
@ -1317,18 +1318,22 @@ export class CoreCourseHelperProvider {
section.isDownloading = true; section.isDownloading = true;
// Validate the section needs to be downloaded and calculate amount of modules that need to be downloaded. // Sync the modules first.
promises.push(this.prefetchDelegate.getModulesStatus(section.modules, courseId, section.id).then((result) => { promises.push(this.prefetchDelegate.syncModules(section.modules).then(() => {
if (result.status == CoreConstants.DOWNLOADED || result.status == CoreConstants.NOT_DOWNLOADABLE) { // Validate the section needs to be downloaded and calculate amount of modules that need to be downloaded.
// Section is downloaded or not downloadable, nothing to do. return this.prefetchDelegate.getModulesStatus(section.modules, courseId, section.id).then((result) => {
return; if (result.status == CoreConstants.DOWNLOADED || result.status == CoreConstants.NOT_DOWNLOADABLE) {
} // Section is downloaded or not downloadable, nothing to do.
return this.prefetchSingleSection(section, result, courseId); return ;
}, (error) => { }
section.isDownloading = false;
return Promise.reject(error); return this.prefetchSingleSection(section, result, courseId);
}, (error) => {
section.isDownloading = false;
return Promise.reject(error);
});
})); }));
// Download the files in the section description. // Download the files in the section description.

View File

@ -206,6 +206,15 @@ export interface CoreCourseModulePrefetchHandler extends CoreDelegateHandler {
* @return {Promise<any>} Promise resolved when done. * @return {Promise<any>} Promise resolved when done.
*/ */
removeFiles?(module: any, courseId: number): Promise<any>; removeFiles?(module: any, courseId: number): Promise<any>;
/**
* Sync a module.
*
* @param {any} module Module.
* @param {string} [siteId] Site ID. If not defined, current site.
* @return {Promise<any>} Promise resolved when done.
*/
sync?(module: any, siteId?: any): Promise<any>;
} }
/** /**
@ -1139,12 +1148,42 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
// Check if the module has a prefetch handler. // Check if the module has a prefetch handler.
if (handler) { if (handler) {
return handler.prefetch(module, courseId, single); return this.syncModule(module).then(() => {
return handler.prefetch(module, courseId, single);
});
} }
return Promise.resolve(); return Promise.resolve();
} }
/**
* Sync a group of modules.
*
* @param {any[]} modules Array of modules to sync.
* @return {Promise<any>} Promise resolved when finished.
*/
syncModules(modules: any[]): Promise<any> {
return Promise.all(modules.map((module) => {
return this.syncModule(module);
}));
}
/**
* Sync a module.
*
* @param {any} module Module to sync.
* @return {Promise<any>} Promise resolved when finished.
*/
syncModule(module: any): Promise<any> {
const handler = this.getPrefetchHandlerFor(module);
const promise = handler && handler.sync ? handler.sync(module) : Promise.resolve();
return promise.catch(() => {
// Ignore errors.
});
}
/** /**
* Prefetches a list of modules using their prefetch handlers. * Prefetches a list of modules using their prefetch handlers.
* If a prefetch already exists for this site and id, returns the current promise. * If a prefetch already exists for this site and id, returns the current promise.