commit
aac8ee7b3a
|
@ -352,14 +352,13 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
}
|
}
|
||||||
|
|
||||||
const modal = this.domUtils.showModalLoading('core.sending', true);
|
const modal = this.domUtils.showModalLoading('core.sending', true);
|
||||||
this.choiceProvider.submitResponse(this.choice.id, this.choice.name, this.courseId, responses).then(() => {
|
this.choiceProvider.submitResponse(this.choice.id, this.choice.name, this.courseId, responses).then((online) => {
|
||||||
// Success!
|
// Success!
|
||||||
// Check completion since it could be configured to complete once the user answers the choice.
|
// Check completion since it could be configured to complete once the user answers the choice.
|
||||||
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata);
|
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata);
|
||||||
this.domUtils.scrollToTop(this.content);
|
this.domUtils.scrollToTop(this.content);
|
||||||
|
|
||||||
// Let's refresh the data.
|
return this.dataUpdated(online);
|
||||||
return this.refreshContent(false);
|
|
||||||
}).catch((message) => {
|
}).catch((message) => {
|
||||||
this.domUtils.showErrorModalDefault(message, 'addon.mod_choice.cannotsubmit', true);
|
this.domUtils.showErrorModalDefault(message, 'addon.mod_choice.cannotsubmit', true);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
|
@ -377,7 +376,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
this.choiceProvider.deleteResponses(this.choice.id, this.choice.name, this.courseId).then(() => {
|
this.choiceProvider.deleteResponses(this.choice.id, this.choice.name, this.courseId).then(() => {
|
||||||
this.domUtils.scrollToTop(this.content);
|
this.domUtils.scrollToTop(this.content);
|
||||||
|
|
||||||
// Success! Let's refresh the data.
|
// Refresh the data. Don't call dataUpdated because deleting an answer doesn't mark the choice as outdated.
|
||||||
return this.refreshContent(false);
|
return this.refreshContent(false);
|
||||||
}).catch((message) => {
|
}).catch((message) => {
|
||||||
this.domUtils.showErrorModalDefault(message, 'addon.mod_choice.cannotsubmit', true);
|
this.domUtils.showErrorModalDefault(message, 'addon.mod_choice.cannotsubmit', true);
|
||||||
|
@ -389,6 +388,28 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to call when some data has changed. It will refresh/prefetch data.
|
||||||
|
*
|
||||||
|
* @param {boolean} online Whether the data was sent to server or stored in offline.
|
||||||
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
|
*/
|
||||||
|
protected dataUpdated(online: boolean): Promise<any> {
|
||||||
|
if (online && this.isPrefetched()) {
|
||||||
|
// The choice is downloaded, update the data.
|
||||||
|
return this.choiceSync.prefetchAfterUpdate(this.module, this.courseId).then(() => {
|
||||||
|
// Update the view.
|
||||||
|
this.showLoadingAndFetch(false, false);
|
||||||
|
}).catch(() => {
|
||||||
|
// Prefetch failed, refresh the data.
|
||||||
|
return this.refreshContent(false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Not downloaded, refresh the data.
|
||||||
|
return this.refreshContent(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the sync of the activity.
|
* Performs the sync of the activity.
|
||||||
*
|
*
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
import { AddonModChoiceOfflineProvider } from './offline';
|
import { AddonModChoiceOfflineProvider } from './offline';
|
||||||
|
import { CoreSiteWSPreSets } from '@classes/site';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides some features for choices.
|
* Service that provides some features for choices.
|
||||||
|
@ -68,9 +69,9 @@ export class AddonModChoiceProvider {
|
||||||
* @param {number} courseId Course ID the choice belongs to.
|
* @param {number} courseId Course ID the choice belongs to.
|
||||||
* @param {number[]} [responses] IDs of the answers. If not defined, delete all the answers of the current user.
|
* @param {number[]} [responses] IDs of the answers. If not defined, delete all the answers of the 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 when the options are deleted.
|
* @return {Promise<boolean>} Promise resolved with boolean: true if response was sent to server, false if stored in device.
|
||||||
*/
|
*/
|
||||||
deleteResponses(choiceId: number, name: string, courseId: number, responses?: number[], siteId?: string): Promise<any> {
|
deleteResponses(choiceId: number, name: string, courseId: number, responses?: number[], siteId?: string): Promise<boolean> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
responses = responses || [];
|
responses = responses || [];
|
||||||
|
|
||||||
|
@ -173,20 +174,29 @@ export class AddonModChoiceProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {string} key Name of the property to check.
|
* @param {string} key Name of the property to check.
|
||||||
* @param {any} value Value to search.
|
* @param {any} value Value to search.
|
||||||
* @param {boolean} [forceCache=false] True to always get the value from cache, false otherwise. Default false.
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<any>} Promise resolved when the choice is retrieved.
|
* @return {Promise<any>} Promise resolved when the choice is retrieved.
|
||||||
*/
|
*/
|
||||||
protected getChoiceByDataKey(siteId: string, courseId: number, key: string, value: any, forceCache: boolean = false)
|
protected getChoiceByDataKey(siteId: string, courseId: number, key: string, value: any, forceCache?: boolean,
|
||||||
: Promise<any> {
|
ignoreCache?: boolean): Promise<any> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
courseids: [courseId]
|
courseids: [courseId]
|
||||||
};
|
};
|
||||||
const preSets = {
|
const preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getChoiceDataCacheKey(courseId),
|
cacheKey: this.getChoiceDataCacheKey(courseId),
|
||||||
omitExpires: forceCache
|
omitExpires: forceCache
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (forceCache) {
|
||||||
|
preSets.omitExpires = true;
|
||||||
|
} else if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_choice_get_choices_by_courses', params, preSets).then((response) => {
|
return site.read('mod_choice_get_choices_by_courses', params, preSets).then((response) => {
|
||||||
if (response && response.choices) {
|
if (response && response.choices) {
|
||||||
const currentChoice = response.choices.find((choice) => choice[key] == value);
|
const currentChoice = response.choices.find((choice) => choice[key] == value);
|
||||||
|
@ -206,11 +216,12 @@ export class AddonModChoiceProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} cmId Course module ID.
|
* @param {number} cmId Course module ID.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {boolean} [forceCache=false] True to always get the value from cache, false otherwise. Default false.
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<any>} Promise resolved when the choice is retrieved.
|
* @return {Promise<any>} Promise resolved when the choice is retrieved.
|
||||||
*/
|
*/
|
||||||
getChoice(courseId: number, cmId: number, siteId?: string, forceCache: boolean = false): Promise<any> {
|
getChoice(courseId: number, cmId: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean): Promise<any> {
|
||||||
return this.getChoiceByDataKey(siteId, courseId, 'coursemodule', cmId, forceCache);
|
return this.getChoiceByDataKey(siteId, courseId, 'coursemodule', cmId, forceCache, ignoreCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -219,29 +230,36 @@ export class AddonModChoiceProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} choiceId Choice ID.
|
* @param {number} choiceId Choice ID.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {boolean} [forceCache=false] True to always get the value from cache, false otherwise. Default false.
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<any>} Promise resolved when the choice is retrieved.
|
* @return {Promise<any>} Promise resolved when the choice is retrieved.
|
||||||
*/
|
*/
|
||||||
getChoiceById(courseId: number, choiceId: number, siteId?: string, forceCache: boolean = false): Promise<any> {
|
getChoiceById(courseId: number, choiceId: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean): Promise<any> {
|
||||||
return this.getChoiceByDataKey(siteId, courseId, 'id', choiceId, forceCache);
|
return this.getChoiceByDataKey(siteId, courseId, 'id', choiceId, forceCache, ignoreCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get choice options.
|
* Get choice options.
|
||||||
*
|
*
|
||||||
* @param {number} choiceId Choice ID.
|
* @param {number} choiceId Choice ID.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @return {Promise<any>} Promise resolved with choice options.
|
* @return {Promise<any>} Promise resolved with choice options.
|
||||||
*/
|
*/
|
||||||
getOptions(choiceId: number, siteId?: string): Promise<any> {
|
getOptions(choiceId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
choiceid: choiceId
|
choiceid: choiceId
|
||||||
};
|
};
|
||||||
const preSets = {
|
const preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getChoiceOptionsCacheKey(choiceId)
|
cacheKey: this.getChoiceOptionsCacheKey(choiceId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_choice_get_choice_options', params, preSets).then((response) => {
|
return site.read('mod_choice_get_choice_options', params, preSets).then((response) => {
|
||||||
if (response.options) {
|
if (response.options) {
|
||||||
return response.options;
|
return response.options;
|
||||||
|
@ -255,19 +273,25 @@ export class AddonModChoiceProvider {
|
||||||
/**
|
/**
|
||||||
* Get choice results.
|
* Get choice results.
|
||||||
*
|
*
|
||||||
* @param {number} choiceId Choice ID.
|
* @param {number} choiceId Choice ID.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @return {Promise<any>} Promise resolved with choice results.
|
* @return {Promise<any>} Promise resolved with choice results.
|
||||||
*/
|
*/
|
||||||
getResults(choiceId: number, siteId?: string): Promise<any> {
|
getResults(choiceId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
choiceid: choiceId
|
choiceid: choiceId
|
||||||
};
|
};
|
||||||
const preSets = {
|
const preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getChoiceResultsCacheKey(choiceId)
|
cacheKey: this.getChoiceResultsCacheKey(choiceId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_choice_get_choice_results', params, preSets).then((response) => {
|
return site.read('mod_choice_get_choice_results', params, preSets).then((response) => {
|
||||||
if (response.options) {
|
if (response.options) {
|
||||||
return response.options;
|
return response.options;
|
||||||
|
|
|
@ -23,7 +23,6 @@ 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 { AddonModChoiceProvider } from './choice';
|
import { AddonModChoiceProvider } from './choice';
|
||||||
import { AddonModChoiceSyncProvider } from './sync';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler to prefetch choices.
|
* Handler to prefetch choices.
|
||||||
|
@ -38,7 +37,7 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
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 syncProvider: AddonModChoiceSyncProvider, protected userProvider: CoreUserProvider) {
|
protected userProvider: CoreUserProvider) {
|
||||||
|
|
||||||
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
|
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
|
||||||
}
|
}
|
||||||
|
@ -66,12 +65,12 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected prefetchChoice(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
protected prefetchChoice(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||||
return this.choiceProvider.getChoice(courseId, module.id, siteId).then((choice) => {
|
return this.choiceProvider.getChoice(courseId, module.id, siteId, false, true).then((choice) => {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
// Get the options and results.
|
// Get the options and results.
|
||||||
promises.push(this.choiceProvider.getOptions(choice.id, siteId));
|
promises.push(this.choiceProvider.getOptions(choice.id, true, siteId));
|
||||||
promises.push(this.choiceProvider.getResults(choice.id, siteId).then((options) => {
|
promises.push(this.choiceProvider.getResults(choice.id, true, siteId).then((options) => {
|
||||||
// If we can see the users that answered, prefetch their profile and avatar.
|
// If we can see the users that answered, prefetch their profile and avatar.
|
||||||
const subPromises = [];
|
const subPromises = [];
|
||||||
options.forEach((option) => {
|
options.forEach((option) => {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
|
@ -26,13 +25,16 @@ import { CoreEventsProvider } from '@providers/events';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
|
import { CoreCourseActivitySyncBaseProvider } from '@core/course/classes/activity-sync';
|
||||||
import { CoreSyncProvider } from '@providers/sync';
|
import { CoreSyncProvider } from '@providers/sync';
|
||||||
|
import { AddonModChoicePrefetchHandler } from './prefetch-handler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to sync choices.
|
* Service to sync choices.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModChoiceSyncProvider extends CoreSyncBaseProvider {
|
export class AddonModChoiceSyncProvider extends CoreCourseActivitySyncBaseProvider {
|
||||||
|
|
||||||
static AUTO_SYNCED = 'addon_mod_choice_autom_synced';
|
static AUTO_SYNCED = 'addon_mod_choice_autom_synced';
|
||||||
protected componentTranslate: string;
|
protected componentTranslate: string;
|
||||||
|
@ -42,9 +44,11 @@ export class AddonModChoiceSyncProvider extends CoreSyncBaseProvider {
|
||||||
private eventsProvider: CoreEventsProvider, private choiceProvider: AddonModChoiceProvider,
|
private eventsProvider: CoreEventsProvider, private choiceProvider: AddonModChoiceProvider,
|
||||||
translate: TranslateService, private utils: CoreUtilsProvider, protected textUtils: CoreTextUtilsProvider,
|
translate: TranslateService, private utils: CoreUtilsProvider, protected textUtils: CoreTextUtilsProvider,
|
||||||
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider, timeUtils: CoreTimeUtilsProvider,
|
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider, timeUtils: CoreTimeUtilsProvider,
|
||||||
private logHelper: CoreCourseLogHelperProvider) {
|
private logHelper: CoreCourseLogHelperProvider, prefetchHandler: AddonModChoicePrefetchHandler,
|
||||||
|
prefetchDelegate: CoreCourseModulePrefetchDelegate) {
|
||||||
|
|
||||||
super('AddonModChoiceSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
super('AddonModChoiceSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
||||||
timeUtils);
|
timeUtils, prefetchDelegate, prefetchHandler);
|
||||||
|
|
||||||
this.componentTranslate = courseProvider.translateModuleName('choice');
|
this.componentTranslate = courseProvider.translateModuleName('choice');
|
||||||
}
|
}
|
||||||
|
@ -195,16 +199,8 @@ export class AddonModChoiceSyncProvider extends CoreSyncBaseProvider {
|
||||||
});
|
});
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (courseId) {
|
if (courseId) {
|
||||||
const promises = [
|
// Data has been sent to server, prefetch choice if needed.
|
||||||
this.choiceProvider.invalidateChoiceData(courseId),
|
return this.prefetchAfterUpdate(module, courseId, undefined, siteId).catch(() => {
|
||||||
choiceId ? this.choiceProvider.invalidateOptions(choiceId) : Promise.resolve(),
|
|
||||||
choiceId ? this.choiceProvider.invalidateResults(choiceId) : Promise.resolve(),
|
|
||||||
];
|
|
||||||
|
|
||||||
// Data has been sent to server, update choice data.
|
|
||||||
return Promise.all(promises).then(() => {
|
|
||||||
return this.choiceProvider.getChoiceById(courseId, choiceId, siteId);
|
|
||||||
}).catch(() => {
|
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,15 +77,29 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
||||||
// Listen for form submit events.
|
// Listen for form submit events.
|
||||||
this.submitObserver = this.eventsProvider.on(AddonModFeedbackProvider.FORM_SUBMITTED, (data) => {
|
this.submitObserver = this.eventsProvider.on(AddonModFeedbackProvider.FORM_SUBMITTED, (data) => {
|
||||||
if (this.feedback && data.feedbackId == this.feedback.id) {
|
if (this.feedback && data.feedbackId == this.feedback.id) {
|
||||||
// Go to review attempt if an attempt in this quiz was finished and synced.
|
|
||||||
this.tabsLoaded['analysis'] = false;
|
this.tabsLoaded['analysis'] = false;
|
||||||
this.tabsLoaded['overview'] = false;
|
this.tabsLoaded['overview'] = false;
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
if (data.tab != this.tab) {
|
|
||||||
this.tabChanged(data.tab);
|
let promise;
|
||||||
|
|
||||||
|
// Prefetch data if needed.
|
||||||
|
if (!data.offline && this.isPrefetched()) {
|
||||||
|
promise = this.feedbackSync.prefetchAfterUpdate(this.module, this.courseId).catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this.loadContent(true);
|
promise = Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
promise.then(() => {
|
||||||
|
// Load the right tab.
|
||||||
|
if (data.tab != this.tab) {
|
||||||
|
this.tabChanged(data.tab);
|
||||||
|
} else {
|
||||||
|
this.loadContent(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, this.siteId);
|
}, this.siteId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,8 +338,13 @@ export class AddonModFeedbackFormPage implements OnDestroy {
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.submitted) {
|
if (this.submitted) {
|
||||||
const tab = this.submitted == 'analysis' ? 'analysis' : 'overview';
|
const tab = this.submitted == 'analysis' ? 'analysis' : 'overview';
|
||||||
|
|
||||||
// If form has been submitted, the info has been already invalidated but we should update index view.
|
// If form has been submitted, the info has been already invalidated but we should update index view.
|
||||||
this.eventsProvider.trigger(AddonModFeedbackProvider.FORM_SUBMITTED, {feedbackId: this.feedback.id, tab: tab});
|
this.eventsProvider.trigger(AddonModFeedbackProvider.FORM_SUBMITTED, {
|
||||||
|
feedbackId: this.feedback.id,
|
||||||
|
tab: tab,
|
||||||
|
offline: this.completedOffline
|
||||||
|
});
|
||||||
}
|
}
|
||||||
this.onlineObserver && this.onlineObserver.unsubscribe();
|
this.onlineObserver && this.onlineObserver.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { CoreFilepoolProvider } from '@providers/filepool';
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
import { AddonModFeedbackOfflineProvider } from './offline';
|
import { AddonModFeedbackOfflineProvider } from './offline';
|
||||||
|
import { CoreSiteWSPreSets } from '@classes/site';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides some features for feedbacks.
|
* Service that provides some features for feedbacks.
|
||||||
|
@ -215,11 +216,14 @@ export class AddonModFeedbackProvider {
|
||||||
*
|
*
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
* @param {number} groupId Group id, 0 means that the function will determine the user group.
|
* @param {number} groupId Group id, 0 means that the function will determine the user group.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {any} [previous] Only for recurrent use. Object with the previous fetched info.
|
* @param {any} [previous] Only for recurrent use. Object with the previous fetched info.
|
||||||
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getAllNonRespondents(feedbackId: number, groupId: number, siteId?: string, previous?: any): Promise<any> {
|
getAllNonRespondents(feedbackId: number, groupId: number, ignoreCache?: boolean, siteId?: string, previous?: any)
|
||||||
|
: Promise<any> {
|
||||||
|
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
if (typeof previous == 'undefined') {
|
if (typeof previous == 'undefined') {
|
||||||
previous = {
|
previous = {
|
||||||
|
@ -228,7 +232,7 @@ export class AddonModFeedbackProvider {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getNonRespondents(feedbackId, groupId, previous.page, siteId).then((response) => {
|
return this.getNonRespondents(feedbackId, groupId, previous.page, ignoreCache, siteId).then((response) => {
|
||||||
if (previous.users.length < response.total) {
|
if (previous.users.length < response.total) {
|
||||||
previous.users = previous.users.concat(response.users);
|
previous.users = previous.users.concat(response.users);
|
||||||
}
|
}
|
||||||
|
@ -237,7 +241,7 @@ export class AddonModFeedbackProvider {
|
||||||
// Can load more.
|
// Can load more.
|
||||||
previous.page++;
|
previous.page++;
|
||||||
|
|
||||||
return this.getAllNonRespondents(feedbackId, groupId, siteId, previous);
|
return this.getAllNonRespondents(feedbackId, groupId, ignoreCache, siteId, previous);
|
||||||
}
|
}
|
||||||
previous.total = response.total;
|
previous.total = response.total;
|
||||||
|
|
||||||
|
@ -250,11 +254,14 @@ export class AddonModFeedbackProvider {
|
||||||
*
|
*
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
* @param {number} groupId Group id, 0 means that the function will determine the user group.
|
* @param {number} groupId Group id, 0 means that the function will determine the user group.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {any} [previous] Only for recurrent use. Object with the previous fetched info.
|
* @param {any} [previous] Only for recurrent use. Object with the previous fetched info.
|
||||||
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getAllResponsesAnalysis(feedbackId: number, groupId: number, siteId?: string, previous?: any): Promise<any> {
|
getAllResponsesAnalysis(feedbackId: number, groupId: number, ignoreCache?: boolean, siteId?: string, previous?: any)
|
||||||
|
: Promise<any> {
|
||||||
|
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
if (typeof previous == 'undefined') {
|
if (typeof previous == 'undefined') {
|
||||||
previous = {
|
previous = {
|
||||||
|
@ -264,7 +271,7 @@ export class AddonModFeedbackProvider {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getResponsesAnalysis(feedbackId, groupId, previous.page, siteId).then((responses) => {
|
return this.getResponsesAnalysis(feedbackId, groupId, previous.page, ignoreCache, siteId).then((responses) => {
|
||||||
if (previous.anonattempts.length < responses.totalanonattempts) {
|
if (previous.anonattempts.length < responses.totalanonattempts) {
|
||||||
previous.anonattempts = previous.anonattempts.concat(responses.anonattempts);
|
previous.anonattempts = previous.anonattempts.concat(responses.anonattempts);
|
||||||
}
|
}
|
||||||
|
@ -277,7 +284,7 @@ export class AddonModFeedbackProvider {
|
||||||
// Can load more.
|
// Can load more.
|
||||||
previous.page++;
|
previous.page++;
|
||||||
|
|
||||||
return this.getAllResponsesAnalysis(feedbackId, groupId, siteId, previous);
|
return this.getAllResponsesAnalysis(feedbackId, groupId, ignoreCache, siteId, previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
previous.totalattempts = responses.totalattempts;
|
previous.totalattempts = responses.totalattempts;
|
||||||
|
@ -292,15 +299,16 @@ export class AddonModFeedbackProvider {
|
||||||
*
|
*
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
* @param {number} [groupId] Group ID.
|
* @param {number} [groupId] Group ID.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the feedback is retrieved.
|
* @return {Promise<any>} Promise resolved when the feedback is retrieved.
|
||||||
*/
|
*/
|
||||||
getAnalysis(feedbackId: number, groupId?: number, siteId?: string): Promise<any> {
|
getAnalysis(feedbackId: number, groupId?: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
feedbackid: feedbackId
|
feedbackid: feedbackId
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getAnalysisDataCacheKey(feedbackId, groupId)
|
cacheKey: this.getAnalysisDataCacheKey(feedbackId, groupId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -308,6 +316,11 @@ export class AddonModFeedbackProvider {
|
||||||
params['groupid'] = groupId;
|
params['groupid'] = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_feedback_get_analysis', params, preSets);
|
return site.read('mod_feedback_get_analysis', params, preSets);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -338,11 +351,12 @@ export class AddonModFeedbackProvider {
|
||||||
*
|
*
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
* @param {number} attemptId Attempt id to find.
|
* @param {number} attemptId Attempt id to find.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {any} [previous] Only for recurrent use. Object with the previous fetched info.
|
* @param {any} [previous] Only for recurrent use. Object with the previous fetched info.
|
||||||
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getAttempt(feedbackId: number, attemptId: number, siteId?: string, previous?: any): Promise<any> {
|
getAttempt(feedbackId: number, attemptId: number, ignoreCache?: boolean, siteId?: string, previous?: any): Promise<any> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
if (typeof previous == 'undefined') {
|
if (typeof previous == 'undefined') {
|
||||||
previous = {
|
previous = {
|
||||||
|
@ -352,7 +366,7 @@ export class AddonModFeedbackProvider {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getResponsesAnalysis(feedbackId, 0, previous.page, siteId).then((responses) => {
|
return this.getResponsesAnalysis(feedbackId, 0, previous.page, ignoreCache, siteId).then((responses) => {
|
||||||
let attempt;
|
let attempt;
|
||||||
|
|
||||||
attempt = responses.attempts.find((attempt) => {
|
attempt = responses.attempts.find((attempt) => {
|
||||||
|
@ -383,7 +397,7 @@ export class AddonModFeedbackProvider {
|
||||||
// Can load more. Check there.
|
// Can load more. Check there.
|
||||||
previous.page++;
|
previous.page++;
|
||||||
|
|
||||||
return this.getAttempt(feedbackId, attemptId, siteId, previous);
|
return this.getAttempt(feedbackId, attemptId, ignoreCache, siteId, previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not found and all loaded. Reject.
|
// Not found and all loaded. Reject.
|
||||||
|
@ -405,18 +419,24 @@ export class AddonModFeedbackProvider {
|
||||||
* Returns the temporary completion timemodified for the current user.
|
* Returns the temporary completion timemodified for the current user.
|
||||||
*
|
*
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the info is retrieved.
|
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getCurrentCompletedTimeModified(feedbackId: number, siteId?: string): Promise<any> {
|
getCurrentCompletedTimeModified(feedbackId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
feedbackid: feedbackId
|
feedbackid: feedbackId
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getCurrentCompletedTimeModifiedDataCacheKey(feedbackId)
|
cacheKey: this.getCurrentCompletedTimeModifiedDataCacheKey(feedbackId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_feedback_get_current_completed_tmp', params, preSets).then((response) => {
|
return site.read('mod_feedback_get_current_completed_tmp', params, preSets).then((response) => {
|
||||||
if (response && typeof response.feedback != 'undefined' && typeof response.feedback.timemodified != 'undefined') {
|
if (response && typeof response.feedback != 'undefined' && typeof response.feedback.timemodified != 'undefined') {
|
||||||
return response.feedback.timemodified;
|
return response.feedback.timemodified;
|
||||||
|
@ -552,20 +572,26 @@ export class AddonModFeedbackProvider {
|
||||||
* @param {string} key Name of the property to check.
|
* @param {string} key Name of the property to check.
|
||||||
* @param {any} value Value to search.
|
* @param {any} value Value to search.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {boolean} [forceCache=false] True to always get the value from cache, false otherwise. Default false.
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<any>} Promise resolved when the feedback is retrieved.
|
* @return {Promise<any>} Promise resolved when the feedback is retrieved.
|
||||||
*/
|
*/
|
||||||
protected getFeedbackDataByKey(courseId: number, key: string, value: any, siteId?: string, forceCache?: boolean): Promise<any> {
|
protected getFeedbackDataByKey(courseId: number, key: string, value: any, siteId?: string, forceCache?: boolean,
|
||||||
|
ignoreCache?: boolean): Promise<any> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
courseids: [courseId]
|
courseids: [courseId]
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getFeedbackCacheKey(courseId)
|
cacheKey: this.getFeedbackCacheKey(courseId)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (forceCache) {
|
if (forceCache) {
|
||||||
preSets['omitExpires'] = true;
|
preSets.omitExpires = true;
|
||||||
|
} else if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('mod_feedback_get_feedbacks_by_courses', params, preSets).then((response) => {
|
return site.read('mod_feedback_get_feedbacks_by_courses', params, preSets).then((response) => {
|
||||||
|
@ -589,11 +615,12 @@ export class AddonModFeedbackProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} cmId Course module ID.
|
* @param {number} cmId Course module ID.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<any>} Promise resolved when the feedback is retrieved.
|
* @return {Promise<any>} Promise resolved when the feedback is retrieved.
|
||||||
*/
|
*/
|
||||||
getFeedback(courseId: number, cmId: number, siteId?: string, forceCache?: boolean): Promise<any> {
|
getFeedback(courseId: number, cmId: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean): Promise<any> {
|
||||||
return this.getFeedbackDataByKey(courseId, 'coursemodule', cmId, siteId, forceCache);
|
return this.getFeedbackDataByKey(courseId, 'coursemodule', cmId, siteId, forceCache, ignoreCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -603,28 +630,35 @@ export class AddonModFeedbackProvider {
|
||||||
* @param {number} id Feedback ID.
|
* @param {number} id Feedback ID.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
* @param {boolean} [forceCache] True to always get the value from cache, false otherwise. Default false.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<any>} Promise resolved when the feedback is retrieved.
|
* @return {Promise<any>} Promise resolved when the feedback is retrieved.
|
||||||
*/
|
*/
|
||||||
getFeedbackById(courseId: number, id: number, siteId?: string, forceCache?: boolean): Promise<any> {
|
getFeedbackById(courseId: number, id: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean): Promise<any> {
|
||||||
return this.getFeedbackDataByKey(courseId, 'id', id, siteId, forceCache);
|
return this.getFeedbackDataByKey(courseId, 'id', id, siteId, forceCache, ignoreCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the items (questions) in the given feedback.
|
* Returns the items (questions) in the given feedback.
|
||||||
*
|
*
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the info is retrieved.
|
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getItems(feedbackId: number, siteId?: string): Promise<any> {
|
getItems(feedbackId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
feedbackid: feedbackId
|
feedbackid: feedbackId
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getItemsDataCacheKey(feedbackId)
|
cacheKey: this.getItemsDataCacheKey(feedbackId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_feedback_get_items', params, preSets);
|
return site.read('mod_feedback_get_items', params, preSets);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -645,20 +679,28 @@ export class AddonModFeedbackProvider {
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
* @param {number} [groupId=0] Group id, 0 means that the function will determine the user group.
|
* @param {number} [groupId=0] Group id, 0 means that the function will determine the user group.
|
||||||
* @param {number} [page=0] The page of records to return.
|
* @param {number} [page=0] The page of records to return.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the info is retrieved.
|
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getNonRespondents(feedbackId: number, groupId: number = 0, page: number = 0, siteId?: string): Promise<any> {
|
getNonRespondents(feedbackId: number, groupId: number = 0, page: number = 0, ignoreCache?: boolean, siteId?: string)
|
||||||
|
: Promise<any> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
feedbackid: feedbackId,
|
feedbackid: feedbackId,
|
||||||
groupid: groupId,
|
groupid: groupId,
|
||||||
page: page
|
page: page
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getNonRespondentsDataCacheKey(feedbackId, groupId)
|
cacheKey: this.getNonRespondentsDataCacheKey(feedbackId, groupId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_feedback_get_non_respondents', params, preSets);
|
return site.read('mod_feedback_get_non_respondents', params, preSets);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -725,7 +767,7 @@ export class AddonModFeedbackProvider {
|
||||||
});
|
});
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
// If getPageItems fail we should calculate it using getItems.
|
// If getPageItems fail we should calculate it using getItems.
|
||||||
return this.getItems(feedbackId, siteId).then((response) => {
|
return this.getItems(feedbackId, false, siteId).then((response) => {
|
||||||
return this.fillValues(feedbackId, response.items, offline, ignoreCache, siteId).then((items) => {
|
return this.fillValues(feedbackId, response.items, offline, ignoreCache, siteId).then((items) => {
|
||||||
// Separate items by pages.
|
// Separate items by pages.
|
||||||
let currentPage = 0;
|
let currentPage = 0;
|
||||||
|
@ -802,20 +844,26 @@ export class AddonModFeedbackProvider {
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
* @param {number} groupId Group id, 0 means that the function will determine the user group.
|
* @param {number} groupId Group id, 0 means that the function will determine the user group.
|
||||||
* @param {number} page The page of records to return.
|
* @param {number} page The page of records to return.
|
||||||
|
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the info is retrieved.
|
* @return {Promise<any>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
getResponsesAnalysis(feedbackId: number, groupId: number, page: number, siteId?: string): Promise<any> {
|
getResponsesAnalysis(feedbackId: number, groupId: number, page: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
feedbackid: feedbackId,
|
feedbackid: feedbackId,
|
||||||
groupid: groupId || 0,
|
groupid: groupId || 0,
|
||||||
page: page || 0
|
page: page || 0
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getResponsesAnalysisDataCacheKey(feedbackId, groupId)
|
cacheKey: this.getResponsesAnalysisDataCacheKey(feedbackId, groupId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_feedback_get_responses_analysis', params, preSets);
|
return site.read('mod_feedback_get_responses_analysis', params, preSets);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1037,18 +1085,24 @@ export class AddonModFeedbackProvider {
|
||||||
* Returns if feedback has been completed
|
* Returns if feedback has been completed
|
||||||
*
|
*
|
||||||
* @param {number} feedbackId Feedback ID.
|
* @param {number} feedbackId Feedback ID.
|
||||||
|
* @param {boolean} [ignoreCache=false] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
* @return {Promise<boolean>} Promise resolved when the info is retrieved.
|
* @return {Promise<boolean>} Promise resolved when the info is retrieved.
|
||||||
*/
|
*/
|
||||||
isCompleted(feedbackId: number, siteId?: string): Promise<boolean> {
|
isCompleted(feedbackId: number, ignoreCache?: boolean, siteId?: string): Promise<boolean> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
feedbackid: feedbackId
|
feedbackid: feedbackId
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getCompletedDataCacheKey(feedbackId)
|
cacheKey: this.getCompletedDataCacheKey(feedbackId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return this.utils.promiseWorks(site.read('mod_feedback_get_last_completed', params, preSets));
|
return this.utils.promiseWorks(site.read('mod_feedback_get_last_completed', params, preSets));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,19 +173,15 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
||||||
*/
|
*/
|
||||||
protected prefetchFeedback(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
protected prefetchFeedback(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||||
// Prefetch the feedback data.
|
// Prefetch the feedback data.
|
||||||
return this.feedbackProvider.getFeedback(courseId, module.id).then((feedback) => {
|
return this.feedbackProvider.getFeedback(courseId, module.id, siteId, false, true).then((feedback) => {
|
||||||
const p1 = [];
|
let files = (feedback.pageaftersubmitfiles || []).concat(this.getIntroFilesFromInstance(module, feedback));
|
||||||
|
|
||||||
p1.push(this.getFiles(module, courseId).then((files) => {
|
return this.feedbackProvider.getFeedbackAccessInformation(feedback.id, false, true, siteId).then((accessData) => {
|
||||||
return this.filepoolProvider.addFilesToQueue(siteId, files, this.component, module.id);
|
|
||||||
}));
|
|
||||||
|
|
||||||
p1.push(this.feedbackProvider.getFeedbackAccessInformation(feedback.id, false, true, siteId).then((accessData) => {
|
|
||||||
const p2 = [];
|
const p2 = [];
|
||||||
if (accessData.canedititems || accessData.canviewreports) {
|
if (accessData.canedititems || accessData.canviewreports) {
|
||||||
// Get all groups analysis.
|
// Get all groups analysis.
|
||||||
p2.push(this.feedbackProvider.getAnalysis(feedback.id, undefined, siteId));
|
p2.push(this.feedbackProvider.getAnalysis(feedback.id, undefined, true, siteId));
|
||||||
p2.push(this.groupsProvider.getActivityGroupInfo(feedback.coursemodule, true, undefined, siteId)
|
p2.push(this.groupsProvider.getActivityGroupInfo(feedback.coursemodule, true, undefined, siteId, true)
|
||||||
.then((groupInfo) => {
|
.then((groupInfo) => {
|
||||||
const p3 = [],
|
const p3 = [],
|
||||||
userIds = [];
|
userIds = [];
|
||||||
|
@ -194,8 +190,8 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
||||||
groupInfo.groups = [{id: 0}];
|
groupInfo.groups = [{id: 0}];
|
||||||
}
|
}
|
||||||
groupInfo.groups.forEach((group) => {
|
groupInfo.groups.forEach((group) => {
|
||||||
p3.push(this.feedbackProvider.getAnalysis(feedback.id, group.id, siteId));
|
p3.push(this.feedbackProvider.getAnalysis(feedback.id, group.id, true, siteId));
|
||||||
p3.push(this.feedbackProvider.getAllResponsesAnalysis(feedback.id, group.id, siteId)
|
p3.push(this.feedbackProvider.getAllResponsesAnalysis(feedback.id, group.id, true, siteId)
|
||||||
.then((responses) => {
|
.then((responses) => {
|
||||||
responses.attempts.forEach((attempt) => {
|
responses.attempts.forEach((attempt) => {
|
||||||
userIds.push(attempt.userid);
|
userIds.push(attempt.userid);
|
||||||
|
@ -203,7 +199,7 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (!accessData.isanonymous) {
|
if (!accessData.isanonymous) {
|
||||||
p3.push(this.feedbackProvider.getAllNonRespondents(feedback.id, group.id, siteId)
|
p3.push(this.feedbackProvider.getAllNonRespondents(feedback.id, group.id, true, siteId)
|
||||||
.then((responses) => {
|
.then((responses) => {
|
||||||
responses.users.forEach((user) => {
|
responses.users.forEach((user) => {
|
||||||
userIds.push(user.userid);
|
userIds.push(user.userid);
|
||||||
|
@ -219,7 +215,13 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
p2.push(this.feedbackProvider.getItems(feedback.id, siteId));
|
p2.push(this.feedbackProvider.getItems(feedback.id, true, siteId).then((response) => {
|
||||||
|
response.items.forEach((item) => {
|
||||||
|
files = files.concat(item.itemfiles);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.filepoolProvider.addFilesToQueue(siteId, files, this.component, module.id);
|
||||||
|
}));
|
||||||
|
|
||||||
if (accessData.cancomplete && accessData.cansubmit && !accessData.isempty) {
|
if (accessData.cancomplete && accessData.cansubmit && !accessData.isempty) {
|
||||||
// Send empty data, so it will recover last completed feedback attempt values.
|
// Send empty data, so it will recover last completed feedback attempt values.
|
||||||
|
@ -234,9 +236,7 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(p2);
|
return Promise.all(p2);
|
||||||
}));
|
});
|
||||||
|
|
||||||
return Promise.all(p1);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ export class AddonModFeedbackShowEntriesLinkHandler extends CoreContentLinksHand
|
||||||
return this.linkHelper.goInSite(navCtrl, 'AddonModFeedbackRespondentsPage', stateParams, siteId);
|
return this.linkHelper.goInSite(navCtrl, 'AddonModFeedbackRespondentsPage', stateParams, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.feedbackProvider.getAttempt(module.instance, params.showcompleted, siteId).then((attempt) => {
|
return this.feedbackProvider.getAttempt(module.instance, params.showcompleted, true, siteId).then((attempt) => {
|
||||||
stateParams = {
|
stateParams = {
|
||||||
moduleId: module.id,
|
moduleId: module.id,
|
||||||
attempt: attempt,
|
attempt: attempt,
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
|
@ -25,14 +24,17 @@ import { AddonModFeedbackProvider } from './feedback';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreSyncProvider } from '@providers/sync';
|
import { CoreCourseActivitySyncBaseProvider } from '@core/course/classes/activity-sync';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
|
import { CoreSyncProvider } from '@providers/sync';
|
||||||
|
import { AddonModFeedbackPrefetchHandler } from './prefetch-handler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to sync feedbacks.
|
* Service to sync feedbacks.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModFeedbackSyncProvider extends CoreSyncBaseProvider {
|
export class AddonModFeedbackSyncProvider extends CoreCourseActivitySyncBaseProvider {
|
||||||
|
|
||||||
static AUTO_SYNCED = 'addon_mod_feedback_autom_synced';
|
static AUTO_SYNCED = 'addon_mod_feedback_autom_synced';
|
||||||
protected componentTranslate: string;
|
protected componentTranslate: string;
|
||||||
|
@ -42,13 +44,30 @@ export class AddonModFeedbackSyncProvider extends CoreSyncBaseProvider {
|
||||||
private eventsProvider: CoreEventsProvider, private feedbackProvider: AddonModFeedbackProvider,
|
private eventsProvider: CoreEventsProvider, private feedbackProvider: AddonModFeedbackProvider,
|
||||||
protected translate: TranslateService, private utils: CoreUtilsProvider, protected textUtils: CoreTextUtilsProvider,
|
protected translate: TranslateService, private utils: CoreUtilsProvider, protected textUtils: CoreTextUtilsProvider,
|
||||||
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider, timeUtils: CoreTimeUtilsProvider,
|
courseProvider: CoreCourseProvider, syncProvider: CoreSyncProvider, timeUtils: CoreTimeUtilsProvider,
|
||||||
private logHelper: CoreCourseLogHelperProvider) {
|
private logHelper: CoreCourseLogHelperProvider, prefetchDelegate: CoreCourseModulePrefetchDelegate,
|
||||||
|
prefetchHandler: AddonModFeedbackPrefetchHandler) {
|
||||||
|
|
||||||
super('AddonModFeedbackSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
super('AddonModFeedbackSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
||||||
timeUtils);
|
timeUtils, prefetchDelegate, prefetchHandler);
|
||||||
|
|
||||||
this.componentTranslate = courseProvider.translateModuleName('feedback');
|
this.componentTranslate = courseProvider.translateModuleName('feedback');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conveniece function to prefetch data after an update.
|
||||||
|
*
|
||||||
|
* @param {any} module Module.
|
||||||
|
* @param {number} courseId Course ID.
|
||||||
|
* @param {RegExp} [regex] If regex matches, don't download the data. Defaults to check files and timers.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
|
*/
|
||||||
|
prefetchAfterUpdate(module: any, courseId: number, regex?: RegExp, siteId?: string): Promise<any> {
|
||||||
|
regex = regex || /^.*files$|^timers/;
|
||||||
|
|
||||||
|
return super.prefetchAfterUpdate(module, courseId, regex, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to synchronize all the feedbacks in a certain site or in all sites.
|
* Try to synchronize all the feedbacks in a certain site or in all sites.
|
||||||
*
|
*
|
||||||
|
@ -196,7 +215,7 @@ export class AddonModFeedbackSyncProvider extends CoreSyncBaseProvider {
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.feedbackProvider.getCurrentCompletedTimeModified(feedbackId, siteId).then((timemodified) => {
|
return this.feedbackProvider.getCurrentCompletedTimeModified(feedbackId, true, siteId).then((timemodified) => {
|
||||||
// Sort by page.
|
// Sort by page.
|
||||||
responses.sort((a, b) => {
|
responses.sort((a, b) => {
|
||||||
return a.page - b.page;
|
return a.page - b.page;
|
||||||
|
@ -216,8 +235,8 @@ export class AddonModFeedbackSyncProvider extends CoreSyncBaseProvider {
|
||||||
});
|
});
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (result.updated) {
|
if (result.updated) {
|
||||||
// Data has been sent to server. Now invalidate the WS calls.
|
// Data has been sent to server, update data.
|
||||||
return this.feedbackProvider.invalidateAllFeedbackData(feedbackId, siteId).catch(() => {
|
return this.prefetchAfterUpdate(module, courseId, undefined, siteId).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
protected accessInfo: any; // Lesson access info.
|
protected accessInfo: any; // Lesson access info.
|
||||||
protected password: string; // The password for the lesson.
|
protected password: string; // The password for the lesson.
|
||||||
protected hasPlayed: boolean; // Whether the user has gone to the lesson player (attempted).
|
protected hasPlayed: boolean; // Whether the user has gone to the lesson player (attempted).
|
||||||
|
protected dataSentObserver; // To detect data sent to server.
|
||||||
|
protected dataSent = false; // Whether some data was sent to server while playing the lesson.
|
||||||
|
|
||||||
constructor(injector: Injector, protected lessonProvider: AddonModLessonProvider, @Optional() content: Content,
|
constructor(injector: Injector, protected lessonProvider: AddonModLessonProvider, @Optional() content: Content,
|
||||||
protected groupsProvider: CoreGroupsProvider, protected lessonOffline: AddonModLessonOfflineProvider,
|
protected groupsProvider: CoreGroupsProvider, protected lessonOffline: AddonModLessonOfflineProvider,
|
||||||
|
@ -228,6 +230,13 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
* @return {boolean} If suceed or not.
|
* @return {boolean} If suceed or not.
|
||||||
*/
|
*/
|
||||||
protected hasSyncSucceed(result: any): boolean {
|
protected hasSyncSucceed(result: any): boolean {
|
||||||
|
if (result.updated || this.dataSent) {
|
||||||
|
// Check completion status if something was sent.
|
||||||
|
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completiondata);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dataSent = false;
|
||||||
|
|
||||||
return result.updated;
|
return result.updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,6 +252,10 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
if (this.hasPlayed) {
|
if (this.hasPlayed) {
|
||||||
this.hasPlayed = false;
|
this.hasPlayed = false;
|
||||||
|
|
||||||
|
this.dataSentObserver && this.dataSentObserver.off(); // Stop listening for changes.
|
||||||
|
this.dataSentObserver = undefined;
|
||||||
|
|
||||||
|
// Refresh data.
|
||||||
this.showLoadingAndRefresh(true, false);
|
this.showLoadingAndRefresh(true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -257,6 +270,16 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
|
|
||||||
if (this.navCtrl.getActive().component.name == 'AddonModLessonPlayerPage') {
|
if (this.navCtrl.getActive().component.name == 'AddonModLessonPlayerPage') {
|
||||||
this.hasPlayed = true;
|
this.hasPlayed = true;
|
||||||
|
|
||||||
|
// Detect if anything was sent to server.
|
||||||
|
this.dataSentObserver && this.dataSentObserver.off();
|
||||||
|
|
||||||
|
this.dataSentObserver = this.eventsProvider.on(AddonModLessonProvider.DATA_SENT_EVENT, (data) => {
|
||||||
|
// Ignore launch sending because it only affects timers.
|
||||||
|
if (data.lessonId === this.lesson.id && data.type != 'launch') {
|
||||||
|
this.dataSent = true;
|
||||||
|
}
|
||||||
|
}, this.siteId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,7 +579,18 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected sync(): Promise<any> {
|
protected sync(): Promise<any> {
|
||||||
return this.lessonSync.syncLesson(this.lesson.id, true);
|
return this.lessonSync.syncLesson(this.lesson.id, true).then((result) => {
|
||||||
|
if (!result.updated && this.dataSent && this.isPrefetched()) {
|
||||||
|
// The user sent data to server, but not in the sync process. Check if we need to fetch data.
|
||||||
|
return this.lessonSync.prefetchAfterUpdate(this.module, this.courseId).catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
}).then(() => {
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -575,4 +609,13 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being destroyed.
|
||||||
|
*/
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
super.ngOnDestroy();
|
||||||
|
|
||||||
|
this.dataSentObserver && this.dataSentObserver.off();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,8 @@ import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
|
import { CoreCourseActivitySyncBaseProvider } from '@core/course/classes/activity-sync';
|
||||||
import { AddonModLessonProvider } from './lesson';
|
import { AddonModLessonProvider } from './lesson';
|
||||||
import { AddonModLessonOfflineProvider } from './lesson-offline';
|
import { AddonModLessonOfflineProvider } from './lesson-offline';
|
||||||
import { AddonModLessonPrefetchHandler } from './prefetch-handler';
|
import { AddonModLessonPrefetchHandler } from './prefetch-handler';
|
||||||
|
@ -51,7 +52,7 @@ export interface AddonModLessonSyncResult {
|
||||||
* Service to sync lesson.
|
* Service to sync lesson.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
|
export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvider {
|
||||||
|
|
||||||
static AUTO_SYNCED = 'addon_mod_lesson_autom_synced';
|
static AUTO_SYNCED = 'addon_mod_lesson_autom_synced';
|
||||||
|
|
||||||
|
@ -92,12 +93,12 @@ export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
|
||||||
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
||||||
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
|
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
|
||||||
private lessonProvider: AddonModLessonProvider, private lessonOfflineProvider: AddonModLessonOfflineProvider,
|
private lessonProvider: AddonModLessonProvider, private lessonOfflineProvider: AddonModLessonOfflineProvider,
|
||||||
private prefetchHandler: AddonModLessonPrefetchHandler, timeUtils: CoreTimeUtilsProvider,
|
protected prefetchHandler: AddonModLessonPrefetchHandler, timeUtils: CoreTimeUtilsProvider,
|
||||||
private utils: CoreUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
private utils: CoreUtilsProvider, private urlUtils: CoreUrlUtilsProvider,
|
||||||
private logHelper: CoreCourseLogHelperProvider) {
|
private logHelper: CoreCourseLogHelperProvider, prefetchDelegate: CoreCourseModulePrefetchDelegate) {
|
||||||
|
|
||||||
super('AddonModLessonSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
super('AddonModLessonSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
||||||
timeUtils);
|
timeUtils, prefetchDelegate, prefetchHandler);
|
||||||
|
|
||||||
this.componentTranslate = courseProvider.translateModuleName('lesson');
|
this.componentTranslate = courseProvider.translateModuleName('lesson');
|
||||||
|
|
||||||
|
@ -288,7 +289,7 @@ export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
|
||||||
courseId = attempts[0].courseid;
|
courseId = attempts[0].courseid;
|
||||||
|
|
||||||
// Get the info, access info and the lesson password if needed.
|
// Get the info, access info and the lesson password if needed.
|
||||||
return this.lessonProvider.getLessonById(courseId, lessonId, false, siteId).then((lessonData) => {
|
return this.lessonProvider.getLessonById(courseId, lessonId, false, false, siteId).then((lessonData) => {
|
||||||
lesson = lessonData;
|
lesson = lessonData;
|
||||||
|
|
||||||
return this.prefetchHandler.getLessonPassword(lessonId, false, true, askPassword, siteId);
|
return this.prefetchHandler.getLessonPassword(lessonId, false, true, askPassword, siteId);
|
||||||
|
@ -364,7 +365,7 @@ export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
|
||||||
// Data already retrieved when syncing attempts.
|
// Data already retrieved when syncing attempts.
|
||||||
promise = Promise.resolve();
|
promise = Promise.resolve();
|
||||||
} else {
|
} else {
|
||||||
promise = this.lessonProvider.getLessonById(courseId, lessonId, false, siteId).then((lessonData) => {
|
promise = this.lessonProvider.getLessonById(courseId, lessonId, false, false, siteId).then((lessonData) => {
|
||||||
lesson = lessonData;
|
lesson = lessonData;
|
||||||
|
|
||||||
return this.prefetchHandler.getLessonPassword(lessonId, false, true, askPassword, siteId);
|
return this.prefetchHandler.getLessonPassword(lessonId, false, true, askPassword, siteId);
|
||||||
|
@ -429,31 +430,9 @@ export class AddonModLessonSyncProvider extends CoreSyncBaseProvider {
|
||||||
});
|
});
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (result.updated && courseId) {
|
if (result.updated && courseId) {
|
||||||
// Data has been sent to server. Now invalidate the WS calls.
|
// Data has been sent to server, update data.
|
||||||
const promises = [];
|
return this.prefetchAfterUpdate(module, courseId, undefined, siteId).catch(() => {
|
||||||
|
|
||||||
promises.push(this.lessonProvider.invalidateAccessInformation(lessonId, siteId));
|
|
||||||
promises.push(this.lessonProvider.invalidateContentPagesViewed(lessonId, siteId));
|
|
||||||
promises.push(this.lessonProvider.invalidateQuestionsAttempts(lessonId, siteId));
|
|
||||||
promises.push(this.lessonProvider.invalidatePagesPossibleJumps(lessonId, siteId));
|
|
||||||
promises.push(this.lessonProvider.invalidateTimers(lessonId, siteId));
|
|
||||||
|
|
||||||
return this.utils.allPromises(promises).catch(() => {
|
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}).then(() => {
|
|
||||||
// Sync successful, update some data that might have been modified.
|
|
||||||
return this.lessonProvider.getAccessInformation(lessonId, false, false, siteId).then((info) => {
|
|
||||||
const promises = [],
|
|
||||||
retake = info.attemptscount;
|
|
||||||
|
|
||||||
promises.push(this.lessonProvider.getContentPagesViewedOnline(lessonId, retake, false, false, siteId));
|
|
||||||
promises.push(this.lessonProvider.getQuestionsAttemptsOnline(lessonId, retake, false, undefined, false,
|
|
||||||
false, siteId));
|
|
||||||
|
|
||||||
return Promise.all(promises);
|
|
||||||
}).catch(() => {
|
|
||||||
// Ignore errors.
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
|
@ -113,6 +114,7 @@ export interface AddonModLessonGrade {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModLessonProvider {
|
export class AddonModLessonProvider {
|
||||||
static COMPONENT = 'mmaModLesson';
|
static COMPONENT = 'mmaModLesson';
|
||||||
|
static DATA_SENT_EVENT = 'addon_mod_lesson_data_sent';
|
||||||
|
|
||||||
// This page.
|
// This page.
|
||||||
static LESSON_THISPAGE = 0;
|
static LESSON_THISPAGE = 0;
|
||||||
|
@ -186,7 +188,8 @@ export class AddonModLessonProvider {
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
|
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
|
||||||
private translate: TranslateService, private textUtils: CoreTextUtilsProvider, private domUtils: CoreDomUtilsProvider,
|
private translate: TranslateService, private textUtils: CoreTextUtilsProvider, private domUtils: CoreDomUtilsProvider,
|
||||||
private lessonOfflineProvider: AddonModLessonOfflineProvider, private logHelper: CoreCourseLogHelperProvider) {
|
private lessonOfflineProvider: AddonModLessonOfflineProvider, private logHelper: CoreCourseLogHelperProvider,
|
||||||
|
private eventsProvider: CoreEventsProvider) {
|
||||||
this.logger = logger.getInstance('AddonModLessonProvider');
|
this.logger = logger.getInstance('AddonModLessonProvider');
|
||||||
|
|
||||||
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
this.sitesProvider.registerSiteSchema(this.siteSchema);
|
||||||
|
@ -1087,7 +1090,17 @@ export class AddonModLessonProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.finishRetakeOnline(lesson.id, password, outOfTime, review, siteId);
|
return this.finishRetakeOnline(lesson.id, password, outOfTime, review, siteId).then((response) => {
|
||||||
|
this.eventsProvider.trigger(AddonModLessonProvider.DATA_SENT_EVENT, {
|
||||||
|
lessonId: lesson.id,
|
||||||
|
type: 'finish',
|
||||||
|
courseId: courseId,
|
||||||
|
outOfTime: outOfTime,
|
||||||
|
review: review
|
||||||
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1363,11 +1376,12 @@ export class AddonModLessonProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} cmid Course module ID.
|
* @param {number} cmid Course module ID.
|
||||||
* @param {boolean} [forceCache] Whether it should always return cached data.
|
* @param {boolean} [forceCache] Whether it should always return cached data.
|
||||||
|
* @param {boolean} [ignoreCache] Whether it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the lesson is retrieved.
|
* @return {Promise<any>} Promise resolved when the lesson is retrieved.
|
||||||
*/
|
*/
|
||||||
getLesson(courseId: number, cmId: number, forceCache?: boolean, siteId?: string): Promise<any> {
|
getLesson(courseId: number, cmId: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.getLessonByField(courseId, 'coursemodule', cmId, forceCache, siteId);
|
return this.getLessonByField(courseId, 'coursemodule', cmId, forceCache, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1377,10 +1391,12 @@ export class AddonModLessonProvider {
|
||||||
* @param {string} key Name of the property to check.
|
* @param {string} key Name of the property to check.
|
||||||
* @param {any} value Value to search.
|
* @param {any} value Value to search.
|
||||||
* @param {boolean} [forceCache] Whether it should always return cached data.
|
* @param {boolean} [forceCache] Whether it should always return cached data.
|
||||||
|
* @param {boolean} [ignoreCache] Whether it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the lesson is retrieved.
|
* @return {Promise<any>} Promise resolved when the lesson is retrieved.
|
||||||
*/
|
*/
|
||||||
protected getLessonByField(courseId: number, key: string, value: any, forceCache?: boolean, siteId?: string): Promise<any> {
|
protected getLessonByField(courseId: number, key: string, value: any, forceCache?: boolean, ignoreCache?: boolean,
|
||||||
|
siteId?: string): Promise<any> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -1392,6 +1408,9 @@ export class AddonModLessonProvider {
|
||||||
|
|
||||||
if (forceCache) {
|
if (forceCache) {
|
||||||
preSets.omitExpires = true;
|
preSets.omitExpires = true;
|
||||||
|
} else if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('mod_lesson_get_lessons_by_courses', params, preSets).then((response) => {
|
return site.read('mod_lesson_get_lessons_by_courses', params, preSets).then((response) => {
|
||||||
|
@ -1416,11 +1435,12 @@ export class AddonModLessonProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} id Lesson ID.
|
* @param {number} id Lesson ID.
|
||||||
* @param {boolean} [forceCache] Whether it should always return cached data.
|
* @param {boolean} [forceCache] Whether it should always return cached data.
|
||||||
|
* @param {boolean} [ignoreCache] Whether it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the lesson is retrieved.
|
* @return {Promise<any>} Promise resolved when the lesson is retrieved.
|
||||||
*/
|
*/
|
||||||
getLessonById(courseId: number, id: number, forceCache?: boolean, siteId?: string): Promise<any> {
|
getLessonById(courseId: number, id: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.getLessonByField(courseId, 'id', id, forceCache, siteId);
|
return this.getLessonByField(courseId, 'id', id, forceCache, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2758,7 +2778,14 @@ export class AddonModLessonProvider {
|
||||||
params.pageid = pageId;
|
params.pageid = pageId;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.write('mod_lesson_launch_attempt', params);
|
return site.write('mod_lesson_launch_attempt', params).then((response) => {
|
||||||
|
this.eventsProvider.trigger(AddonModLessonProvider.DATA_SENT_EVENT, {
|
||||||
|
lessonId: id,
|
||||||
|
type: 'launch'
|
||||||
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3028,7 +3055,17 @@ export class AddonModLessonProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.processPageOnline(lesson.id, pageId, data, password, review, siteId);
|
return this.processPageOnline(lesson.id, pageId, data, password, review, siteId).then((response) => {
|
||||||
|
this.eventsProvider.trigger(AddonModLessonProvider.DATA_SENT_EVENT, {
|
||||||
|
lessonId: lesson.id,
|
||||||
|
type: 'process',
|
||||||
|
courseId: courseId,
|
||||||
|
pageId: pageId,
|
||||||
|
review: review
|
||||||
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
|
||||||
|
return response;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -83,7 +83,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
password,
|
password,
|
||||||
result;
|
result;
|
||||||
|
|
||||||
return this.lessonProvider.getLesson(courseId, module.id, false, siteId).then((lessonData) => {
|
return this.lessonProvider.getLesson(courseId, module.id, false, false, siteId).then((lessonData) => {
|
||||||
lesson = lessonData;
|
lesson = lessonData;
|
||||||
|
|
||||||
// Get the lesson password if it's needed.
|
// Get the lesson password if it's needed.
|
||||||
|
@ -190,7 +190,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
// Invalidate data to determine if module is downloadable.
|
// Invalidate data to determine if module is downloadable.
|
||||||
return this.lessonProvider.getLesson(courseId, module.id, false, siteId).then((lesson) => {
|
return this.lessonProvider.getLesson(courseId, module.id, true, false, siteId).then((lesson) => {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
promises.push(this.lessonProvider.invalidateLessonData(courseId, siteId));
|
promises.push(this.lessonProvider.invalidateLessonData(courseId, siteId));
|
||||||
|
@ -210,7 +210,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
||||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
return this.lessonProvider.getLesson(courseId, module.id, false, siteId).then((lesson) => {
|
return this.lessonProvider.getLesson(courseId, module.id, false, false, siteId).then((lesson) => {
|
||||||
if (!this.lessonProvider.isLessonOffline(lesson)) {
|
if (!this.lessonProvider.isLessonOffline(lesson)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
password,
|
password,
|
||||||
accessInfo;
|
accessInfo;
|
||||||
|
|
||||||
return this.lessonProvider.getLesson(courseId, module.id, false, siteId).then((lessonData) => {
|
return this.lessonProvider.getLesson(courseId, module.id, false, true, siteId).then((lessonData) => {
|
||||||
lesson = lessonData;
|
lesson = lessonData;
|
||||||
|
|
||||||
// Get the lesson password if it's needed.
|
// Get the lesson password if it's needed.
|
||||||
|
@ -360,7 +360,8 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
|
|
||||||
if (accessInfo.canviewreports) {
|
if (accessInfo.canviewreports) {
|
||||||
// Prefetch reports data.
|
// Prefetch reports data.
|
||||||
promises.push(this.groupsProvider.getActivityAllowedGroupsIfEnabled(module.id, undefined, siteId).then((groups) => {
|
promises.push(this.groupsProvider.getActivityAllowedGroupsIfEnabled(module.id, undefined, siteId, true)
|
||||||
|
.then((groups) => {
|
||||||
const subPromises = [];
|
const subPromises = [];
|
||||||
|
|
||||||
groups.forEach((group) => {
|
groups.forEach((group) => {
|
||||||
|
|
|
@ -50,6 +50,21 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
|
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download the module.
|
||||||
|
*
|
||||||
|
* @param {any} module The module object returned by WS.
|
||||||
|
* @param {number} courseId Course ID.
|
||||||
|
* @param {string} [dirPath] Path of the directory where to store all the content files.
|
||||||
|
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
|
||||||
|
* @param {boolean} [canStart=true] If true, start a new attempt if needed.
|
||||||
|
* @return {Promise<any>} Promise resolved when all content is downloaded.
|
||||||
|
*/
|
||||||
|
download(module: any, courseId: number, dirPath?: string, single?: boolean, canStart: boolean = true): Promise<any> {
|
||||||
|
// Same implementation for download and prefetch.
|
||||||
|
return this.prefetch(module, courseId, single, dirPath, canStart);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get list of files. If not defined, we'll assume they're in module.contents.
|
* Get list of files. If not defined, we'll assume they're in module.contents.
|
||||||
*
|
*
|
||||||
|
@ -190,7 +205,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
|
|
||||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
return this.quizProvider.getQuiz(courseId, module.id, false, siteId).then((quiz) => {
|
return this.quizProvider.getQuiz(courseId, module.id, false, false, siteId).then((quiz) => {
|
||||||
if (quiz.allowofflineattempts !== 1 || quiz.hasquestions === 0) {
|
if (quiz.allowofflineattempts !== 1 || quiz.hasquestions === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -220,10 +235,11 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
* @param {number} courseId Course ID the module belongs to.
|
* @param {number} courseId Course ID the module belongs to.
|
||||||
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
|
* @param {boolean} [single] True if we're downloading a single module, false if we're downloading a whole section.
|
||||||
* @param {string} [dirPath] Path of the directory where to store all the content files.
|
* @param {string} [dirPath] Path of the directory where to store all the content files.
|
||||||
|
* @param {boolean} [canStart=true] If true, start a new attempt if needed.
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string): Promise<any> {
|
prefetch(module: any, courseId?: number, single?: boolean, dirPath?: string, canStart: boolean = true): Promise<any> {
|
||||||
return this.prefetchPackage(module, courseId, single, this.prefetchQuiz.bind(this));
|
return this.prefetchPackage(module, courseId, single, this.prefetchQuiz.bind(this), undefined, canStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,9 +249,10 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
* @param {number} courseId Course ID the module belongs to.
|
* @param {number} courseId Course ID the module belongs to.
|
||||||
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
|
* @param {boolean} single True if we're downloading a single module, false if we're downloading a whole section.
|
||||||
* @param {String} siteId Site ID.
|
* @param {String} siteId Site ID.
|
||||||
|
* @param {boolean} canStart If true, start a new attempt if needed.
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected prefetchQuiz(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
protected prefetchQuiz(module: any, courseId: number, single: boolean, siteId: string, canStart: boolean): Promise<any> {
|
||||||
let attempts: any[],
|
let attempts: any[],
|
||||||
startAttempt = false,
|
startAttempt = false,
|
||||||
quiz,
|
quiz,
|
||||||
|
@ -244,7 +261,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
preflightData;
|
preflightData;
|
||||||
|
|
||||||
// Get quiz.
|
// Get quiz.
|
||||||
return this.quizProvider.getQuiz(courseId, module.id, false, siteId).then((quizData) => {
|
return this.quizProvider.getQuiz(courseId, module.id, false, true, siteId).then((quizData) => {
|
||||||
quiz = quizData;
|
quiz = quizData;
|
||||||
|
|
||||||
const promises = [],
|
const promises = [],
|
||||||
|
@ -272,7 +289,13 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// Check if we need to start a new attempt.
|
// Check if we need to start a new attempt.
|
||||||
let attempt = attempts[attempts.length - 1];
|
let attempt = attempts[attempts.length - 1];
|
||||||
if (!attempt || this.quizProvider.isAttemptFinished(attempt.state)) {
|
|
||||||
|
if (!canStart && !attempt) {
|
||||||
|
// No attempts and we won't start a new one, so we don't need preflight data.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canStart && (!attempt || this.quizProvider.isAttemptFinished(attempt.state))) {
|
||||||
// Check if the user can attempt the quiz.
|
// Check if the user can attempt the quiz.
|
||||||
if (attemptAccessInfo.preventnewattemptreasons.length) {
|
if (attemptAccessInfo.preventnewattemptreasons.length) {
|
||||||
return Promise.reject(this.textUtils.buildMessage(attemptAccessInfo.preventnewattemptreasons));
|
return Promise.reject(this.textUtils.buildMessage(attemptAccessInfo.preventnewattemptreasons));
|
||||||
|
@ -331,6 +354,11 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
if (!canStart) {
|
||||||
|
// Nothing else to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If there's nothing to send, mark the quiz as synchronized.
|
// If there's nothing to send, mark the quiz as synchronized.
|
||||||
// We don't return the promises because it should be fast and we don't want to block the user for this.
|
// We don't return the promises because it should be fast and we don't want to block the user for this.
|
||||||
if (!this.syncProvider) {
|
if (!this.syncProvider) {
|
||||||
|
@ -477,14 +505,49 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
||||||
return this.prefetchAttempt(quiz, lastAttempt, preflightData, siteId);
|
return this.prefetchAttempt(quiz, lastAttempt, preflightData, siteId);
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// Prefetch finished, get current status to determine if we need to change it.
|
// Prefetch finished, set the right status.
|
||||||
|
return this.setStatusAfterPrefetch(quiz, attempts, true, false, siteId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the right status to a quiz after prefetching.
|
||||||
|
* If the last attempt is finished or there isn't one, set it as not downloaded to show download icon.
|
||||||
|
*
|
||||||
|
* @param {any} quiz Quiz.
|
||||||
|
* @param {any[]} [attempts] List of attempts. If not provided, they will be calculated.
|
||||||
|
* @param {boolean} [forceCache] Whether it should always return cached data. Only if attempts is undefined.
|
||||||
|
* @param {boolean} [ignoreCache] Whether it should ignore cached data (it will always fail in offline or server down). Only if
|
||||||
|
* attempts is undefined.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
|
*/
|
||||||
|
setStatusAfterPrefetch(quiz: any, attempts?: any[], forceCache?: boolean, ignoreCache?: boolean, siteId?: string)
|
||||||
|
: Promise<any> {
|
||||||
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
|
const promises = [];
|
||||||
|
let status;
|
||||||
|
|
||||||
|
if (!attempts) {
|
||||||
|
// Get the attempts.
|
||||||
|
promises.push(this.quizProvider.getUserAttempts(quiz.id, 'all', true, forceCache, ignoreCache, siteId).then((atts) => {
|
||||||
|
attempts = atts;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the current status of the quiz.
|
||||||
|
promises.push(this.filepoolProvider.getPackageStatus(siteId, this.component, quiz.coursemodule).then((stat) => {
|
||||||
|
status = stat;
|
||||||
|
}));
|
||||||
|
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
|
||||||
return this.filepoolProvider.getPackageStatus(siteId, this.component, quiz.coursemodule);
|
|
||||||
}).then((status) => {
|
|
||||||
if (status !== CoreConstants.NOT_DOWNLOADED) {
|
if (status !== CoreConstants.NOT_DOWNLOADED) {
|
||||||
// Quiz was downloaded, set the new status.
|
// Quiz was downloaded, set the new status.
|
||||||
// If no attempts or last is finished we'll mark it as not downloaded to show download icon.
|
// If no attempts or last is finished we'll mark it as not downloaded to show download icon.
|
||||||
const isLastFinished = !lastAttempt || this.quizProvider.isAttemptFinished(lastAttempt.state),
|
const lastAttempt = attempts[attempts.length - 1],
|
||||||
|
isLastFinished = !lastAttempt || this.quizProvider.isAttemptFinished(lastAttempt.state),
|
||||||
newStatus = isLastFinished ? CoreConstants.NOT_DOWNLOADED : CoreConstants.DOWNLOADED;
|
newStatus = isLastFinished ? CoreConstants.NOT_DOWNLOADED : CoreConstants.DOWNLOADED;
|
||||||
|
|
||||||
return this.filepoolProvider.storePackageStatus(siteId, newStatus, this.component, quiz.coursemodule);
|
return this.filepoolProvider.storePackageStatus(siteId, newStatus, this.component, quiz.coursemodule);
|
||||||
|
|
|
@ -23,9 +23,10 @@ import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
import { CoreQuestionProvider } from '@core/question/providers/question';
|
import { CoreQuestionProvider } from '@core/question/providers/question';
|
||||||
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
||||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
import { CoreCourseActivitySyncBaseProvider } from '@core/course/classes/activity-sync';
|
||||||
import { AddonModQuizProvider } from './quiz';
|
import { AddonModQuizProvider } from './quiz';
|
||||||
import { AddonModQuizOfflineProvider } from './quiz-offline';
|
import { AddonModQuizOfflineProvider } from './quiz-offline';
|
||||||
import { AddonModQuizPrefetchHandler } from './prefetch-handler';
|
import { AddonModQuizPrefetchHandler } from './prefetch-handler';
|
||||||
|
@ -51,7 +52,7 @@ export interface AddonModQuizSyncResult {
|
||||||
* Service to sync quizzes.
|
* Service to sync quizzes.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModQuizSyncProvider extends CoreSyncBaseProvider {
|
export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider {
|
||||||
|
|
||||||
static AUTO_SYNCED = 'addon_mod_quiz_autom_synced';
|
static AUTO_SYNCED = 'addon_mod_quiz_autom_synced';
|
||||||
|
|
||||||
|
@ -59,13 +60,14 @@ export class AddonModQuizSyncProvider extends CoreSyncBaseProvider {
|
||||||
|
|
||||||
constructor(loggerProvider: CoreLoggerProvider, sitesProvider: CoreSitesProvider, appProvider: CoreAppProvider,
|
constructor(loggerProvider: CoreLoggerProvider, sitesProvider: CoreSitesProvider, appProvider: CoreAppProvider,
|
||||||
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
||||||
courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider, timeUtils: CoreTimeUtilsProvider,
|
private eventsProvider: CoreEventsProvider, timeUtils: CoreTimeUtilsProvider,
|
||||||
private quizProvider: AddonModQuizProvider, private quizOfflineProvider: AddonModQuizOfflineProvider,
|
private quizProvider: AddonModQuizProvider, private quizOfflineProvider: AddonModQuizOfflineProvider,
|
||||||
private prefetchHandler: AddonModQuizPrefetchHandler, private questionProvider: CoreQuestionProvider,
|
protected prefetchHandler: AddonModQuizPrefetchHandler, private questionProvider: CoreQuestionProvider,
|
||||||
private questionDelegate: CoreQuestionDelegate, private logHelper: CoreCourseLogHelperProvider) {
|
private questionDelegate: CoreQuestionDelegate, private logHelper: CoreCourseLogHelperProvider,
|
||||||
|
prefetchDelegate: CoreCourseModulePrefetchDelegate, private courseProvider: CoreCourseProvider) {
|
||||||
|
|
||||||
super('AddonModQuizSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
super('AddonModQuizSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
||||||
timeUtils);
|
timeUtils, prefetchDelegate, prefetchHandler);
|
||||||
|
|
||||||
this.componentTranslate = courseProvider.translateModuleName('quiz');
|
this.componentTranslate = courseProvider.translateModuleName('quiz');
|
||||||
}
|
}
|
||||||
|
@ -97,7 +99,11 @@ export class AddonModQuizSyncProvider extends CoreSyncBaseProvider {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (updated) {
|
if (updated) {
|
||||||
// Data has been sent. Update prefetched data.
|
// Data has been sent. Update prefetched data.
|
||||||
return this.prefetchHandler.prefetchQuizAndLastAttempt(quiz, false, siteId);
|
return this.courseProvider.getModuleBasicInfoByInstance(quiz.id, 'quiz', siteId).then((module) => {
|
||||||
|
return this.prefetchAfterUpdateQuiz(module, quiz, courseId, undefined, siteId);
|
||||||
|
}).catch(() => {
|
||||||
|
// Ignore errors.
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
return this.setSyncTime(quiz.id, siteId).catch(() => {
|
return this.setSyncTime(quiz.id, siteId).catch(() => {
|
||||||
|
@ -145,6 +151,41 @@ export class AddonModQuizSyncProvider extends CoreSyncBaseProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conveniece function to prefetch data after an update.
|
||||||
|
*
|
||||||
|
* @param {any} module Module.
|
||||||
|
* @param {any} quiz Quiz.
|
||||||
|
* @param {number} courseId Course ID.
|
||||||
|
* @param {RegExp} [regex] If regex matches, don't download the data. Defaults to check files.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
|
*/
|
||||||
|
prefetchAfterUpdateQuiz(module: any, quiz: any, courseId: number, regex?: RegExp, siteId?: string): Promise<any> {
|
||||||
|
regex = regex || /^.*files$/;
|
||||||
|
|
||||||
|
let shouldDownload;
|
||||||
|
|
||||||
|
// Get the module updates to check if the data was updated or not.
|
||||||
|
return this.prefetchDelegate.getModuleUpdates(module, courseId, true, siteId).then((result) => {
|
||||||
|
|
||||||
|
if (result && result.updates && result.updates.length > 0) {
|
||||||
|
// Only prefetch if files haven't changed.
|
||||||
|
shouldDownload = !result.updates.find((entry) => {
|
||||||
|
return entry.name.match(regex);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldDownload) {
|
||||||
|
return this.prefetchHandler.download(module, courseId, undefined, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}).then(() => {
|
||||||
|
// Prefetch finished or not needed, set the right status.
|
||||||
|
return this.prefetchHandler.setStatusAfterPrefetch(quiz, undefined, shouldDownload, false, siteId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Try to synchronize all the quizzes in a certain site or in all sites.
|
* Try to synchronize all the quizzes in a certain site or in all sites.
|
||||||
*
|
*
|
||||||
|
@ -185,7 +226,7 @@ export class AddonModQuizSyncProvider extends CoreSyncBaseProvider {
|
||||||
if (!this.syncProvider.isBlocked(AddonModQuizProvider.COMPONENT, quiz.id, siteId)) {
|
if (!this.syncProvider.isBlocked(AddonModQuizProvider.COMPONENT, quiz.id, siteId)) {
|
||||||
|
|
||||||
// Quiz not blocked, try to synchronize it.
|
// Quiz not blocked, try to synchronize it.
|
||||||
promises.push(this.quizProvider.getQuizById(quiz.courseid, quiz.id, false, siteId).then((quiz) => {
|
promises.push(this.quizProvider.getQuizById(quiz.courseid, quiz.id, false, false, siteId).then((quiz) => {
|
||||||
return this.syncQuizIfNeeded(quiz, false, siteId).then((data) => {
|
return this.syncQuizIfNeeded(quiz, false, siteId).then((data) => {
|
||||||
if (data && data.warnings && data.warnings.length) {
|
if (data && data.warnings && data.warnings.length) {
|
||||||
// Store the warnings to show them when the user opens the quiz.
|
// Store the warnings to show them when the user opens the quiz.
|
||||||
|
|
|
@ -672,10 +672,13 @@ export class AddonModQuizProvider {
|
||||||
* @param {string} key Name of the property to check.
|
* @param {string} key Name of the property to check.
|
||||||
* @param {any} value Value to search.
|
* @param {any} value Value to search.
|
||||||
* @param {boolean} [forceCache] Whether it should always return cached data.
|
* @param {boolean} [forceCache] Whether it should always return cached data.
|
||||||
|
* @param {boolean} [ignoreCache] Whether it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the Quiz is retrieved.
|
* @return {Promise<any>} Promise resolved when the Quiz is retrieved.
|
||||||
*/
|
*/
|
||||||
protected getQuizByField(courseId: number, key: string, value: any, forceCache?: boolean, siteId?: string): Promise<any> {
|
protected getQuizByField(courseId: number, key: string, value: any, forceCache?: boolean, ignoreCache?: boolean,
|
||||||
|
siteId?: string): Promise<any> {
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
courseids: [courseId]
|
courseids: [courseId]
|
||||||
|
@ -686,6 +689,9 @@ export class AddonModQuizProvider {
|
||||||
|
|
||||||
if (forceCache) {
|
if (forceCache) {
|
||||||
preSets.omitExpires = true;
|
preSets.omitExpires = true;
|
||||||
|
} else if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return site.read('mod_quiz_get_quizzes_by_courses', params, preSets).then((response) => {
|
return site.read('mod_quiz_get_quizzes_by_courses', params, preSets).then((response) => {
|
||||||
|
@ -710,11 +716,12 @@ export class AddonModQuizProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} cmId Course module ID.
|
* @param {number} cmId Course module ID.
|
||||||
* @param {boolean} [forceCache] Whether it should always return cached data.
|
* @param {boolean} [forceCache] Whether it should always return cached data.
|
||||||
|
* @param {boolean} [ignoreCache] Whether it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the quiz is retrieved.
|
* @return {Promise<any>} Promise resolved when the quiz is retrieved.
|
||||||
*/
|
*/
|
||||||
getQuiz(courseId: number, cmId: number, forceCache?: boolean, siteId?: string): Promise<any> {
|
getQuiz(courseId: number, cmId: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.getQuizByField(courseId, 'coursemodule', cmId, forceCache, siteId);
|
return this.getQuizByField(courseId, 'coursemodule', cmId, forceCache, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -723,11 +730,12 @@ export class AddonModQuizProvider {
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} id Quiz ID.
|
* @param {number} id Quiz ID.
|
||||||
* @param {boolean} [forceCache] Whether it should always return cached data.
|
* @param {boolean} [forceCache] Whether it should always return cached data.
|
||||||
|
* @param {boolean} [ignoreCache] Whether it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the quiz is retrieved.
|
* @return {Promise<any>} Promise resolved when the quiz is retrieved.
|
||||||
*/
|
*/
|
||||||
getQuizById(courseId: number, id: number, forceCache?: boolean, siteId?: string): Promise<any> {
|
getQuizById(courseId: number, id: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.getQuizByField(courseId, 'id', id, forceCache, siteId);
|
return this.getQuizByField(courseId, 'id', id, forceCache, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1223,7 +1231,7 @@ export class AddonModQuizProvider {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
// Get required data to call the invalidate functions.
|
// Get required data to call the invalidate functions.
|
||||||
return this.getQuiz(courseId, moduleId, false, siteId).then((quiz) => {
|
return this.getQuiz(courseId, moduleId, true, false, siteId).then((quiz) => {
|
||||||
return this.getUserAttempts(quiz.id, 'all', true, false, false, siteId).then((attempts) => {
|
return this.getUserAttempts(quiz.id, 'all', true, false, false, siteId).then((attempts) => {
|
||||||
// Now invalidate it.
|
// Now invalidate it.
|
||||||
const lastAttemptId = attempts.length ? attempts[attempts.length - 1].id : undefined;
|
const lastAttemptId = attempts.length ? attempts[attempts.length - 1].id : undefined;
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
import { CoreCourseActivitySyncBaseProvider } from '@core/course/classes/activity-sync';
|
||||||
import { AddonModScormProvider, AddonModScormAttemptCountResult } from './scorm';
|
import { AddonModScormProvider, AddonModScormAttemptCountResult } from './scorm';
|
||||||
import { AddonModScormOfflineProvider } from './scorm-offline';
|
import { AddonModScormOfflineProvider } from './scorm-offline';
|
||||||
import { AddonModScormPrefetchHandler } from './prefetch-handler';
|
import { AddonModScormPrefetchHandler } from './prefetch-handler';
|
||||||
|
@ -57,7 +57,7 @@ export interface AddonModScormSyncResult {
|
||||||
* Service to sync SCORMs.
|
* Service to sync SCORMs.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModScormSyncProvider extends CoreSyncBaseProvider {
|
export class AddonModScormSyncProvider extends CoreCourseActivitySyncBaseProvider {
|
||||||
|
|
||||||
static AUTO_SYNCED = 'addon_mod_scorm_autom_synced';
|
static AUTO_SYNCED = 'addon_mod_scorm_autom_synced';
|
||||||
|
|
||||||
|
@ -67,12 +67,12 @@ export class AddonModScormSyncProvider extends CoreSyncBaseProvider {
|
||||||
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
||||||
private eventsProvider: CoreEventsProvider, timeUtils: CoreTimeUtilsProvider,
|
private eventsProvider: CoreEventsProvider, timeUtils: CoreTimeUtilsProvider,
|
||||||
private scormProvider: AddonModScormProvider, private scormOfflineProvider: AddonModScormOfflineProvider,
|
private scormProvider: AddonModScormProvider, private scormOfflineProvider: AddonModScormOfflineProvider,
|
||||||
private prefetchHandler: AddonModScormPrefetchHandler, private utils: CoreUtilsProvider,
|
prefetchHandler: AddonModScormPrefetchHandler, private utils: CoreUtilsProvider,
|
||||||
private prefetchDelegate: CoreCourseModulePrefetchDelegate, private courseProvider: CoreCourseProvider,
|
prefetchDelegate: CoreCourseModulePrefetchDelegate, private courseProvider: CoreCourseProvider,
|
||||||
private logHelper: CoreCourseLogHelperProvider) {
|
private logHelper: CoreCourseLogHelperProvider) {
|
||||||
|
|
||||||
super('AddonModScormSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
super('AddonModScormSyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
||||||
timeUtils);
|
timeUtils, prefetchDelegate, prefetchHandler);
|
||||||
|
|
||||||
this.componentTranslate = courseProvider.translateModuleName('scorm');
|
this.componentTranslate = courseProvider.translateModuleName('scorm');
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,7 @@ export class AddonModScormSyncProvider extends CoreSyncBaseProvider {
|
||||||
if (updated) {
|
if (updated) {
|
||||||
// Update downloaded data.
|
// Update downloaded data.
|
||||||
promise = this.courseProvider.getModuleBasicInfoByInstance(scorm.id, 'scorm', siteId).then((module) => {
|
promise = this.courseProvider.getModuleBasicInfoByInstance(scorm.id, 'scorm', siteId).then((module) => {
|
||||||
return this.prefetchAfterUpdate(module, scorm.course);
|
return this.prefetchAfterUpdate(module, scorm.course, undefined, siteId);
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
|
@ -361,31 +361,6 @@ export class AddonModScormSyncProvider extends CoreSyncBaseProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Prefetch data after an update. It won't prefetch the data if the package file was updated.
|
|
||||||
*
|
|
||||||
* @param {any} module Module.
|
|
||||||
* @param {number} courseId Course ID.
|
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
|
||||||
*/
|
|
||||||
prefetchAfterUpdate(module: any, courseId: number, siteId?: string): Promise<any> {
|
|
||||||
// Get the module updates to check if the package was updated or not.
|
|
||||||
return this.prefetchDelegate.getModuleUpdates(module, courseId, true, siteId).then((result) => {
|
|
||||||
|
|
||||||
if (result && result.updates) {
|
|
||||||
// Only prefetch if the package file hasn't changed.
|
|
||||||
const fileChanged = !!result.updates.find((entry) => {
|
|
||||||
return entry.name == 'packagefiles';
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!fileChanged) {
|
|
||||||
return this.prefetchHandler.download(module, courseId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save a snapshot from a synchronization.
|
* Save a snapshot from a synchronization.
|
||||||
*
|
*
|
||||||
|
|
|
@ -188,8 +188,20 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then(() => {
|
return this.surveyProvider.submitAnswers(this.survey.id, this.survey.name, this.courseId, answers).then((online) => {
|
||||||
return this.showLoadingAndRefresh(false);
|
if (online && this.isPrefetched()) {
|
||||||
|
// The survey is downloaded, update the data.
|
||||||
|
return this.surveySync.prefetchAfterUpdate(this.module, this.courseId).then(() => {
|
||||||
|
// Update the view.
|
||||||
|
this.showLoadingAndFetch(false, false);
|
||||||
|
}).catch((error) => {
|
||||||
|
// Prefetch failed, refresh the data.
|
||||||
|
return this.showLoadingAndRefresh(false);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Not downloaded, refresh the data.
|
||||||
|
return this.showLoadingAndRefresh(false);
|
||||||
|
}
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
modal.dismiss();
|
modal.dismiss();
|
||||||
});
|
});
|
||||||
|
|
|
@ -111,7 +111,7 @@ export class AddonModSurveyPrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
* @return {Promise<any>} Promise resolved when done.
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected prefetchSurvey(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
protected prefetchSurvey(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||||
return this.surveyProvider.getSurvey(courseId, module.id).then((survey) => {
|
return this.surveyProvider.getSurvey(courseId, module.id, true, siteId).then((survey) => {
|
||||||
const promises = [],
|
const promises = [],
|
||||||
files = this.getIntroFilesFromInstance(module, survey);
|
files = this.getIntroFilesFromInstance(module, survey);
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ export class AddonModSurveyPrefetchHandler extends CoreCourseActivityPrefetchHan
|
||||||
|
|
||||||
// If survey isn't answered, prefetch the questions.
|
// If survey isn't answered, prefetch the questions.
|
||||||
if (!survey.surveydone) {
|
if (!survey.surveydone) {
|
||||||
promises.push(this.surveyProvider.getQuestions(survey.id));
|
promises.push(this.surveyProvider.getQuestions(survey.id, true, siteId));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
import { AddonModSurveyOfflineProvider } from './offline';
|
import { AddonModSurveyOfflineProvider } from './offline';
|
||||||
|
import { CoreSiteWSPreSets } from '@classes/site';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service that provides some features for surveys.
|
* Service that provides some features for surveys.
|
||||||
|
@ -41,18 +42,24 @@ export class AddonModSurveyProvider {
|
||||||
* Get a survey's questions.
|
* Get a survey's questions.
|
||||||
*
|
*
|
||||||
* @param {number} surveyId Survey ID.
|
* @param {number} surveyId Survey ID.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the questions are retrieved.
|
* @return {Promise<any>} Promise resolved when the questions are retrieved.
|
||||||
*/
|
*/
|
||||||
getQuestions(surveyId: number, siteId?: string): Promise<any> {
|
getQuestions(surveyId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
surveyid: surveyId
|
surveyid: surveyId
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getQuestionsCacheKey(surveyId)
|
cacheKey: this.getQuestionsCacheKey(surveyId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_survey_get_questions', params, preSets).then((response) => {
|
return site.read('mod_survey_get_questions', params, preSets).then((response) => {
|
||||||
if (response.questions) {
|
if (response.questions) {
|
||||||
return response.questions;
|
return response.questions;
|
||||||
|
@ -87,20 +94,26 @@ export class AddonModSurveyProvider {
|
||||||
* Get a survey data.
|
* Get a survey data.
|
||||||
*
|
*
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {string} key Name of the property to check.
|
* @param {string} key Name of the property to check.
|
||||||
* @param {any} value Value to search.
|
* @param {any} value Value to search.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the survey is retrieved.
|
* @return {Promise<any>} Promise resolved when the survey is retrieved.
|
||||||
*/
|
*/
|
||||||
protected getSurveyDataByKey(courseId: number, key: string, value: any, siteId?: string): Promise<any> {
|
protected getSurveyDataByKey(courseId: number, key: string, value: any, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
const params = {
|
const params = {
|
||||||
courseids: [courseId]
|
courseids: [courseId]
|
||||||
},
|
},
|
||||||
preSets = {
|
preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getSurveyCacheKey(courseId)
|
cacheKey: this.getSurveyCacheKey(courseId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ignoreCache) {
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
return site.read('mod_survey_get_surveys_by_courses', params, preSets).then((response) => {
|
return site.read('mod_survey_get_surveys_by_courses', params, preSets).then((response) => {
|
||||||
if (response && response.surveys) {
|
if (response && response.surveys) {
|
||||||
const currentSurvey = response.surveys.find((survey) => {
|
const currentSurvey = response.surveys.find((survey) => {
|
||||||
|
@ -120,24 +133,26 @@ export class AddonModSurveyProvider {
|
||||||
* Get a survey by course module ID.
|
* Get a survey by course module ID.
|
||||||
*
|
*
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} cmId Course module ID.
|
* @param {number} cmId Course module ID.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the survey is retrieved.
|
* @return {Promise<any>} Promise resolved when the survey is retrieved.
|
||||||
*/
|
*/
|
||||||
getSurvey(courseId: number, cmId: number, siteId?: string): Promise<any> {
|
getSurvey(courseId: number, cmId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.getSurveyDataByKey(courseId, 'coursemodule', cmId, siteId);
|
return this.getSurveyDataByKey(courseId, 'coursemodule', cmId, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a survey by ID.
|
* Get a survey by ID.
|
||||||
*
|
*
|
||||||
* @param {number} courseId Course ID.
|
* @param {number} courseId Course ID.
|
||||||
* @param {number} id Survey ID.
|
* @param {number} id Survey ID.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @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 when the survey is retrieved.
|
* @return {Promise<any>} Promise resolved when the survey is retrieved.
|
||||||
*/
|
*/
|
||||||
getSurveyById(courseId: number, id: number, siteId?: string): Promise<any> {
|
getSurveyById(courseId: number, id: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||||
return this.getSurveyDataByKey(courseId, 'id', id, siteId);
|
return this.getSurveyDataByKey(courseId, 'id', id, ignoreCache, siteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { CoreLoggerProvider } from '@providers/logger';
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
|
||||||
import { CoreAppProvider } from '@providers/app';
|
import { CoreAppProvider } from '@providers/app';
|
||||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
|
@ -26,13 +25,16 @@ import { CoreEventsProvider } from '@providers/events';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||||
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
|
import { CoreCourseActivitySyncBaseProvider } from '@core/course/classes/activity-sync';
|
||||||
import { CoreSyncProvider } from '@providers/sync';
|
import { CoreSyncProvider } from '@providers/sync';
|
||||||
|
import { AddonModSurveyPrefetchHandler } from './prefetch-handler';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service to sync surveys.
|
* Service to sync surveys.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AddonModSurveySyncProvider extends CoreSyncBaseProvider {
|
export class AddonModSurveySyncProvider extends CoreCourseActivitySyncBaseProvider {
|
||||||
|
|
||||||
static AUTO_SYNCED = 'addon_mod_survey_autom_synced';
|
static AUTO_SYNCED = 'addon_mod_survey_autom_synced';
|
||||||
protected componentTranslate: string;
|
protected componentTranslate: string;
|
||||||
|
@ -41,10 +43,11 @@ export class AddonModSurveySyncProvider extends CoreSyncBaseProvider {
|
||||||
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
syncProvider: CoreSyncProvider, textUtils: CoreTextUtilsProvider, translate: TranslateService,
|
||||||
courseProvider: CoreCourseProvider, private surveyOffline: AddonModSurveyOfflineProvider,
|
courseProvider: CoreCourseProvider, private surveyOffline: AddonModSurveyOfflineProvider,
|
||||||
private eventsProvider: CoreEventsProvider, private surveyProvider: AddonModSurveyProvider,
|
private eventsProvider: CoreEventsProvider, private surveyProvider: AddonModSurveyProvider,
|
||||||
private utils: CoreUtilsProvider, timeUtils: CoreTimeUtilsProvider, private logHelper: CoreCourseLogHelperProvider) {
|
private utils: CoreUtilsProvider, timeUtils: CoreTimeUtilsProvider, private logHelper: CoreCourseLogHelperProvider,
|
||||||
|
prefetchDelegate: CoreCourseModulePrefetchDelegate, prefetchHandler: AddonModSurveyPrefetchHandler) {
|
||||||
|
|
||||||
super('AddonModSurveySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
super('AddonModSurveySyncProvider', loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate,
|
||||||
timeUtils);
|
timeUtils, prefetchDelegate, prefetchHandler);
|
||||||
|
|
||||||
this.componentTranslate = courseProvider.translateModuleName('survey');
|
this.componentTranslate = courseProvider.translateModuleName('survey');
|
||||||
}
|
}
|
||||||
|
@ -57,7 +60,7 @@ export class AddonModSurveySyncProvider extends CoreSyncBaseProvider {
|
||||||
* @return {string} Sync ID.
|
* @return {string} Sync ID.
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
getSyncId (surveyId: number, userId: number): string {
|
getSyncId(surveyId: number, userId: number): string {
|
||||||
return surveyId + '#' + userId;
|
return surveyId + '#' + userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,9 +195,7 @@ export class AddonModSurveySyncProvider extends CoreSyncBaseProvider {
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
if (courseId) {
|
if (courseId) {
|
||||||
// Data has been sent to server, update survey data.
|
// Data has been sent to server, update survey data.
|
||||||
return this.surveyProvider.invalidateSurveyData(courseId, siteId).then(() => {
|
return this.prefetchAfterUpdate(module, courseId, undefined, siteId).catch(() => {
|
||||||
return this.surveyProvider.getSurveyById(courseId, surveyId, siteId);
|
|
||||||
}).catch(() => {
|
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,4 +84,20 @@ export class AddonQtypeTrueFalseHandler implements CoreQuestionHandler {
|
||||||
isSameResponse(question: any, prevAnswers: any, newAnswers: any): boolean {
|
isSameResponse(question: any, prevAnswers: any, newAnswers: any): boolean {
|
||||||
return this.utils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
|
return this.utils.sameAtKeyMissingIsBlank(prevAnswers, newAnswers, 'answer');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare and add to answers the data to send to server based in the input. Return promise if async.
|
||||||
|
*
|
||||||
|
* @param {any} question Question.
|
||||||
|
* @param {any} answers The answers retrieved from the form. Prepared answers must be stored in this object.
|
||||||
|
* @param {boolean} [offline] Whether the data should be saved in offline.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {void|Promise<any>} Return a promise resolved when done if async, void if sync.
|
||||||
|
*/
|
||||||
|
prepareAnswers(question: any, answers: any, offline: boolean, siteId?: string): void | Promise<any> {
|
||||||
|
if (question && typeof answers[question.optionsName] != 'undefined' && !answers[question.optionsName]) {
|
||||||
|
// The user hasn't answered. Delete the answer to prevent marking one of the answers automatically.
|
||||||
|
delete answers[question.optionsName];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,9 +46,6 @@ export class CoreSyncBaseProvider {
|
||||||
// Store sync promises.
|
// Store sync promises.
|
||||||
protected syncPromises: { [siteId: string]: { [uniqueId: string]: Promise<any> } } = {};
|
protected syncPromises: { [siteId: string]: { [uniqueId: string]: Promise<any> } } = {};
|
||||||
|
|
||||||
// List of services that will be injected using injector.
|
|
||||||
// It's done like this so subclasses don't have to send all the services to the parent in the constructor.
|
|
||||||
|
|
||||||
constructor(component: string, loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
|
constructor(component: string, loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
|
||||||
protected appProvider: CoreAppProvider, protected syncProvider: CoreSyncProvider,
|
protected appProvider: CoreAppProvider, protected syncProvider: CoreSyncProvider,
|
||||||
protected textUtils: CoreTextUtilsProvider, protected translate: TranslateService,
|
protected textUtils: CoreTextUtilsProvider, protected translate: TranslateService,
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
// (C) Copyright 2015 Martin Dougiamas
|
||||||
|
//
|
||||||
|
// 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 { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
|
import { CoreSyncProvider } from '@providers/sync';
|
||||||
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
|
import { CoreAppProvider } from '@providers/app';
|
||||||
|
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||||
|
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||||
|
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
||||||
|
import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-prefetch-delegate';
|
||||||
|
import { CoreCourseModulePrefetchHandlerBase } from './module-prefetch-handler';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class to create activity sync providers. It provides some common functions.
|
||||||
|
*/
|
||||||
|
export class CoreCourseActivitySyncBaseProvider extends CoreSyncBaseProvider {
|
||||||
|
|
||||||
|
constructor(component: string, loggerProvider: CoreLoggerProvider, protected sitesProvider: CoreSitesProvider,
|
||||||
|
protected appProvider: CoreAppProvider, protected syncProvider: CoreSyncProvider,
|
||||||
|
protected textUtils: CoreTextUtilsProvider, protected translate: TranslateService,
|
||||||
|
protected timeUtils: CoreTimeUtilsProvider, protected prefetchDelegate: CoreCourseModulePrefetchDelegate,
|
||||||
|
protected prefetchHandler: CoreCourseModulePrefetchHandlerBase) {
|
||||||
|
|
||||||
|
super(component, loggerProvider, sitesProvider, appProvider, syncProvider, textUtils, translate, timeUtils);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conveniece function to prefetch data after an update.
|
||||||
|
*
|
||||||
|
* @param {any} module Module.
|
||||||
|
* @param {number} courseId Course ID.
|
||||||
|
* @param {RegExp} [regex] If regex matches, don't download the data. Defaults to check files.
|
||||||
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @return {Promise<any>} Promise resolved when done.
|
||||||
|
*/
|
||||||
|
prefetchAfterUpdate(module: any, courseId: number, regex?: RegExp, siteId?: string): Promise<any> {
|
||||||
|
regex = regex || /^.*files$/;
|
||||||
|
|
||||||
|
// Get the module updates to check if the data was updated or not.
|
||||||
|
return this.prefetchDelegate.getModuleUpdates(module, courseId, true, siteId).then((result) => {
|
||||||
|
|
||||||
|
if (result && result.updates && result.updates.length > 0) {
|
||||||
|
// Only prefetch if files haven't changed.
|
||||||
|
const shouldDownload = !result.updates.find((entry) => {
|
||||||
|
return entry.name.match(regex);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldDownload) {
|
||||||
|
return this.prefetchHandler.download(module, courseId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ import { CoreCourseModuleMainComponent, CoreCourseModuleDelegate } from '@core/c
|
||||||
import { CoreCourseSectionPage } from '@core/course/pages/section/section.ts';
|
import { CoreCourseSectionPage } from '@core/course/pages/section/section.ts';
|
||||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||||
import { AddonBlogProvider } from '@addon/blog/providers/blog';
|
import { AddonBlogProvider } from '@addon/blog/providers/blog';
|
||||||
|
import { CoreConstants } from '@core/constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template class to easily create CoreCourseModuleMainComponent of resources (or activities without syncing).
|
* Template class to easily create CoreCourseModuleMainComponent of resources (or activities without syncing).
|
||||||
|
@ -42,6 +43,7 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
||||||
description: string; // Module description.
|
description: string; // Module description.
|
||||||
refreshIcon: string; // Refresh icon, normally spinner or refresh.
|
refreshIcon: string; // Refresh icon, normally spinner or refresh.
|
||||||
prefetchStatusIcon: string; // Used when calling fillContextMenu.
|
prefetchStatusIcon: string; // Used when calling fillContextMenu.
|
||||||
|
prefetchStatus: string; // Used when calling fillContextMenu.
|
||||||
prefetchText: string; // Used when calling fillContextMenu.
|
prefetchText: string; // Used when calling fillContextMenu.
|
||||||
size: string; // Used when calling fillContextMenu.
|
size: string; // Used when calling fillContextMenu.
|
||||||
|
|
||||||
|
@ -222,6 +224,14 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
|
||||||
this.courseHelper.fillContextMenu(this, this.module, this.courseId, refresh, this.component);
|
this.courseHelper.fillContextMenu(this, this.module, this.courseId, refresh, this.component);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the module is prefetched or being prefetched. To make it faster, just use the data calculated by fillContextMenu.
|
||||||
|
* This means that you need to call fillContextMenu to make this work.
|
||||||
|
*/
|
||||||
|
protected isPrefetched(): boolean {
|
||||||
|
return this.prefetchStatus != CoreConstants.NOT_DOWNLOADABLE && this.prefetchStatus != CoreConstants.NOT_DOWNLOADED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand the description.
|
* Expand the description.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -745,6 +745,7 @@ export class CoreCourseHelperProvider {
|
||||||
return this.getModulePrefetchInfo(module, courseId, invalidateCache, component).then((moduleInfo) => {
|
return this.getModulePrefetchInfo(module, courseId, invalidateCache, component).then((moduleInfo) => {
|
||||||
instance.size = moduleInfo.size > 0 ? moduleInfo.sizeReadable : 0;
|
instance.size = moduleInfo.size > 0 ? moduleInfo.sizeReadable : 0;
|
||||||
instance.prefetchStatusIcon = moduleInfo.statusIcon;
|
instance.prefetchStatusIcon = moduleInfo.statusIcon;
|
||||||
|
instance.prefetchStatus = moduleInfo.status;
|
||||||
|
|
||||||
if (moduleInfo.status != CoreConstants.NOT_DOWNLOADABLE) {
|
if (moduleInfo.status != CoreConstants.NOT_DOWNLOADABLE) {
|
||||||
// Module is downloadable, get the text to display to prefetch.
|
// Module is downloadable, get the text to display to prefetch.
|
||||||
|
|
|
@ -124,16 +124,17 @@ export class CoreGroupsProvider {
|
||||||
* @param {number} cmId Course module ID.
|
* @param {number} cmId Course module ID.
|
||||||
* @param {number} [userId] User ID. If not defined, use current user.
|
* @param {number} [userId] User ID. If not defined, use current user.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<any[]>} Promise resolved when the groups are retrieved. If not allowed, empty array will be returned.
|
* @return {Promise<any[]>} Promise resolved when the groups are retrieved. If not allowed, empty array will be returned.
|
||||||
*/
|
*/
|
||||||
getActivityAllowedGroupsIfEnabled(cmId: number, userId?: number, siteId?: string): Promise<any[]> {
|
getActivityAllowedGroupsIfEnabled(cmId: number, userId?: number, siteId?: string, ignoreCache?: boolean): Promise<any[]> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
// Get real groupmode, in case it's forced by the course.
|
// Get real groupmode, in case it's forced by the course.
|
||||||
return this.activityHasGroups(cmId, siteId).then((hasGroups) => {
|
return this.activityHasGroups(cmId, siteId, ignoreCache).then((hasGroups) => {
|
||||||
if (hasGroups) {
|
if (hasGroups) {
|
||||||
// Get the groups available for the user.
|
// Get the groups available for the user.
|
||||||
return this.getActivityAllowedGroups(cmId, userId, siteId);
|
return this.getActivityAllowedGroups(cmId, userId, siteId, ignoreCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
|
@ -147,19 +148,22 @@ export class CoreGroupsProvider {
|
||||||
* @param {boolean} [addAllParts=true] Whether to add the all participants option. Always true for visible groups.
|
* @param {boolean} [addAllParts=true] Whether to add the all participants option. Always true for visible groups.
|
||||||
* @param {number} [userId] User ID. If not defined, use current user.
|
* @param {number} [userId] User ID. If not defined, use current user.
|
||||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||||
|
* @param {boolean} [ignoreCache] True if it should ignore cached data (it will always fail in offline or server down).
|
||||||
* @return {Promise<CoreGroupInfo>} Promise resolved with the group info.
|
* @return {Promise<CoreGroupInfo>} Promise resolved with the group info.
|
||||||
*/
|
*/
|
||||||
getActivityGroupInfo(cmId: number, addAllParts: boolean = true, userId?: number, siteId?: string): Promise<CoreGroupInfo> {
|
getActivityGroupInfo(cmId: number, addAllParts: boolean = true, userId?: number, siteId?: string, ignoreCache?: boolean)
|
||||||
|
: Promise<CoreGroupInfo> {
|
||||||
|
|
||||||
const groupInfo: CoreGroupInfo = {
|
const groupInfo: CoreGroupInfo = {
|
||||||
groups: []
|
groups: []
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.getActivityGroupMode(cmId, siteId).then((groupMode) => {
|
return this.getActivityGroupMode(cmId, siteId, ignoreCache).then((groupMode) => {
|
||||||
groupInfo.separateGroups = groupMode === CoreGroupsProvider.SEPARATEGROUPS;
|
groupInfo.separateGroups = groupMode === CoreGroupsProvider.SEPARATEGROUPS;
|
||||||
groupInfo.visibleGroups = groupMode === CoreGroupsProvider.VISIBLEGROUPS;
|
groupInfo.visibleGroups = groupMode === CoreGroupsProvider.VISIBLEGROUPS;
|
||||||
|
|
||||||
if (groupInfo.separateGroups || groupInfo.visibleGroups) {
|
if (groupInfo.separateGroups || groupInfo.visibleGroups) {
|
||||||
return this.getActivityAllowedGroups(cmId, userId, siteId);
|
return this.getActivityAllowedGroups(cmId, userId, siteId, ignoreCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
|
|
Loading…
Reference in New Issue