MOBILE-3413 h5pactivity: Prefetch attempts data
parent
b48a27e656
commit
dc85f96046
|
@ -1,7 +1,7 @@
|
|||
<!-- Buttons to add to the header. -->
|
||||
<core-navbar-buttons end>
|
||||
<core-context-menu>
|
||||
<core-context-menu-item *ngIf="h5pActivity && h5pActivity.enabletracking" [priority]="1000" [content]="'addon.mod_h5pactivity.review_my_attempts' | translate" (action)="viewMyAttempts()" [iconAction]="'stats'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="h5pActivity && h5pActivity.enabletracking && accessInfo && !accessInfo.canreviewattempts" [priority]="1000" [content]="'addon.mod_h5pactivity.review_my_attempts' | translate" (action)="viewMyAttempts()" [iconAction]="'stats'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
|
||||
|
|
|
@ -100,7 +100,7 @@ export class AddonModH5PActivityAttemptResultsPage implements OnInit {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchAttempt(): Promise<void> {
|
||||
this.attempt = await AddonModH5PActivity.instance.getResults(this.h5pActivityId, this.attemptId);
|
||||
this.attempt = await AddonModH5PActivity.instance.getAttemptResults(this.h5pActivityId, this.attemptId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -109,7 +109,11 @@ export class AddonModH5PActivityAttemptResultsPage implements OnInit {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchUserProfile(): Promise<void> {
|
||||
this.user = await CoreUser.instance.getProfile(this.attempt.userid, this.courseId, true);
|
||||
try {
|
||||
this.user = await CoreUser.instance.getProfile(this.attempt.userid, this.courseId, true);
|
||||
} catch (error) {
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -110,7 +110,11 @@ export class AddonModH5PActivityUserAttemptsPage implements OnInit {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchUserProfile(): Promise<void> {
|
||||
this.user = await CoreUser.instance.getProfile(this.userId, this.courseId, true);
|
||||
try {
|
||||
this.user = await CoreUser.instance.getProfile(this.userId, this.courseId, true);
|
||||
} catch (error) {
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,6 +17,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreSites } from '@providers/sites';
|
||||
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
|
||||
import { CoreTimeUtils } from '@providers/utils/time';
|
||||
import { CoreUtils } from '@providers/utils/utils';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreCourseLogHelper } from '@core/course/providers/log-helper';
|
||||
import { CoreH5P } from '@core/h5p/providers/h5p';
|
||||
|
@ -64,9 +65,9 @@ export class AddonModH5PActivityProvider {
|
|||
protected formatAttemptResults(attempt: AddonModH5PActivityWSAttemptResults): AddonModH5PActivityAttemptResults {
|
||||
const formattedAttempt: AddonModH5PActivityAttemptResults = this.formatAttempt(attempt);
|
||||
|
||||
for (const i in formattedAttempt.results) {
|
||||
formattedAttempt.results[i] = this.formatResult(formattedAttempt.results[i]);
|
||||
}
|
||||
formattedAttempt.results = formattedAttempt.results.map((result) => {
|
||||
return this.formatResult(result);
|
||||
});
|
||||
|
||||
return formattedAttempt;
|
||||
}
|
||||
|
@ -80,14 +81,15 @@ export class AddonModH5PActivityProvider {
|
|||
protected formatUserAttempts(data: AddonModH5PActivityWSUserAttempts): AddonModH5PActivityUserAttempts {
|
||||
const formatted: AddonModH5PActivityUserAttempts = data;
|
||||
|
||||
for (const i in formatted.attempts) {
|
||||
formatted.attempts[i] = this.formatAttempt(formatted.attempts[i]);
|
||||
}
|
||||
formatted.attempts = formatted.attempts.map((attempt) => {
|
||||
return this.formatAttempt(attempt);
|
||||
});
|
||||
|
||||
if (formatted.scored) {
|
||||
for (const i in formatted.scored.attempts) {
|
||||
formatted.scored.attempts[i] = this.formatAttempt(formatted.scored.attempts[i]);
|
||||
}
|
||||
|
||||
formatted.scored.attempts = formatted.scored.attempts.map((attempt) => {
|
||||
return this.formatAttempt(attempt);
|
||||
});
|
||||
}
|
||||
|
||||
return formatted;
|
||||
|
@ -137,6 +139,153 @@ export class AddonModH5PActivityProvider {
|
|||
return site.read('mod_h5pactivity_get_h5pactivity_access_information', params, preSets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attempt results for all user attempts.
|
||||
*
|
||||
* @param id Activity ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the results of the attempt.
|
||||
*/
|
||||
async getAllAttemptsResults(id: number, options?: AddonModH5PActivityGetAttemptResultsOptions)
|
||||
: Promise<AddonModH5PActivityAttemptsResults> {
|
||||
|
||||
const userAttempts = await AddonModH5PActivity.instance.getUserAttempts(id, options);
|
||||
|
||||
const attemptIds = userAttempts.attempts.map((attempt) => {
|
||||
return attempt.id;
|
||||
});
|
||||
|
||||
if (attemptIds.length) {
|
||||
// Get all the attempts with a single call.
|
||||
return AddonModH5PActivity.instance.getAttemptsResults(id, attemptIds, options);
|
||||
} else {
|
||||
// No attempts.
|
||||
return {
|
||||
activityid: id,
|
||||
attempts: [],
|
||||
warnings: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for results WS calls.
|
||||
*
|
||||
* @param id Instance ID.
|
||||
* @param attemptsIds Attempts IDs.
|
||||
* @return Cache key.
|
||||
*/
|
||||
protected getAttemptResultsCacheKey(id: number, attemptsIds: number[]): string {
|
||||
return this.getAttemptResultsCommonCacheKey(id) + ':' + JSON.stringify(attemptsIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get common cache key for results WS calls.
|
||||
*
|
||||
* @param id Instance ID.
|
||||
* @return Cache key.
|
||||
*/
|
||||
protected getAttemptResultsCommonCacheKey(id: number): string {
|
||||
return this.ROOT_CACHE_KEY + 'results:' + id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attempt results.
|
||||
*
|
||||
* @param id Activity ID.
|
||||
* @param attemptId Attempt ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the results of the attempt.
|
||||
*/
|
||||
async getAttemptResults(id: number, attemptId: number, options?: AddonModH5PActivityGetAttemptResultsOptions)
|
||||
: Promise<AddonModH5PActivityAttemptResults> {
|
||||
|
||||
options = options || {};
|
||||
|
||||
const site = await CoreSites.instance.getSite(options.siteId);
|
||||
|
||||
const params = {
|
||||
h5pactivityid: id,
|
||||
attemptids: [attemptId],
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAttemptResultsCacheKey(id, params.attemptids),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
};
|
||||
|
||||
if (options.forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (options.ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
try {
|
||||
const response: AddonModH5PActivityGetResultsResult = await site.read('mod_h5pactivity_get_results', params, preSets);
|
||||
|
||||
return this.formatAttemptResults(response.attempts[0]);
|
||||
} catch (error) {
|
||||
if (CoreUtils.instance.isWebServiceError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Check if the full list of results is cached. If so, get the results from there.
|
||||
options.forceCache = true;
|
||||
|
||||
const attemptsResults = await AddonModH5PActivity.instance.getAllAttemptsResults(id, options);
|
||||
|
||||
const attempt = attemptsResults.attempts.find((attempt) => {
|
||||
return attempt.id == attemptId;
|
||||
});
|
||||
|
||||
if (!attempt) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return attempt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attempts results.
|
||||
*
|
||||
* @param id Activity ID.
|
||||
* @param attemptsIds Attempts IDs.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with all the attempts.
|
||||
*/
|
||||
async getAttemptsResults(id: number, attemptsIds: number[], options?: AddonModH5PActivityGetAttemptResultsOptions)
|
||||
: Promise<AddonModH5PActivityAttemptsResults> {
|
||||
|
||||
options = options || {};
|
||||
|
||||
const site = await CoreSites.instance.getSite(options.siteId);
|
||||
|
||||
const params = {
|
||||
h5pactivityid: id,
|
||||
attemptids: attemptsIds,
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAttemptResultsCommonCacheKey(id),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
};
|
||||
|
||||
if (options.forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (options.ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
const response: AddonModH5PActivityGetResultsResult = await site.read('mod_h5pactivity_get_results', params, preSets);
|
||||
|
||||
response.attempts = response.attempts.map((attempt) => {
|
||||
return this.formatAttemptResults(attempt);
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get deployed file from an H5P activity instance.
|
||||
*
|
||||
|
@ -244,61 +393,6 @@ export class AddonModH5PActivityProvider {
|
|||
return this.getH5PActivityByField(courseId, 'id', id, forceCache, siteId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for results WS calls.
|
||||
*
|
||||
* @param id Instance ID.
|
||||
* @param attemptsIds Attempts IDs.
|
||||
* @return Cache key.
|
||||
*/
|
||||
protected getResultsCacheKey(id: number, attemptsIds: number[]): string {
|
||||
return this.getResultsCommonCacheKey(id) + ':' + JSON.stringify(attemptsIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get common cache key for results WS calls.
|
||||
*
|
||||
* @param id Instance ID.
|
||||
* @return Cache key.
|
||||
*/
|
||||
protected getResultsCommonCacheKey(id: number): string {
|
||||
return this.ROOT_CACHE_KEY + 'results:' + id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attempt results.
|
||||
*
|
||||
* @param id Activity ID.
|
||||
* @param attemptId Attempt ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the attempts of the user.
|
||||
*/
|
||||
async getResults(id: number, attemptId: number, options?: AddonModH5PActivityGetResultsOptions)
|
||||
: Promise<AddonModH5PActivityAttemptResults> {
|
||||
|
||||
options = options || {};
|
||||
|
||||
const site = await CoreSites.instance.getSite(options.siteId);
|
||||
|
||||
const params = {
|
||||
h5pactivityid: id,
|
||||
attemptids: [attemptId],
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getResultsCacheKey(id, params.attemptids),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
};
|
||||
|
||||
if (options.ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
const response: AddonModH5PActivityGetResultsResult = await site.read('mod_h5pactivity_get_results', params, preSets);
|
||||
|
||||
return this.formatAttemptResults(response.attempts[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for attemps WS calls.
|
||||
*
|
||||
|
@ -342,7 +436,9 @@ export class AddonModH5PActivityProvider {
|
|||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
};
|
||||
|
||||
if (options.ignoreCache) {
|
||||
if (options.forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (options.ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
@ -389,7 +485,7 @@ export class AddonModH5PActivityProvider {
|
|||
async invalidateAllResults(id: number, siteId?: string): Promise<void> {
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
await site.invalidateWsCacheForKey(this.getResultsCommonCacheKey(id));
|
||||
await site.invalidateWsCacheForKey(this.getAttemptResultsCommonCacheKey(id));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -403,7 +499,7 @@ export class AddonModH5PActivityProvider {
|
|||
async invalidateAttemptResults(id: number, attemptId: number, siteId?: string): Promise<void> {
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
|
||||
await site.invalidateWsCacheForKey(this.getResultsCacheKey(id, [attemptId]));
|
||||
await site.invalidateWsCacheForKey(this.getAttemptResultsCacheKey(id, [attemptId]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -633,6 +729,15 @@ export type AddonModH5PActivityUserAttempts = {
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempts results with some calculated data.
|
||||
*/
|
||||
export type AddonModH5PActivityAttemptsResults = {
|
||||
activityid: number; // Activity course module ID.
|
||||
attempts: AddonModH5PActivityAttemptResults[]; // The complete attempts list.
|
||||
warnings?: CoreWSExternalWarning[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt with some calculated data.
|
||||
*/
|
||||
|
@ -658,18 +763,16 @@ export type AddonModH5PActivityGetDeployedFileOptions = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Options to pass to getResults function.
|
||||
* Options to pass to getAttemptResults function.
|
||||
*/
|
||||
export type AddonModH5PActivityGetResultsOptions = {
|
||||
export type AddonModH5PActivityGetAttemptResultsOptions = {
|
||||
forceCache?: boolean; // Whether to force cache. If not cached, it will call the WS.
|
||||
ignoreCache?: boolean; // Whether to ignore cache. Will fail if offline or server down.
|
||||
siteId?: string; // Site ID. If not defined, current site.
|
||||
userId?: number; // User ID. If not defined, user of the site.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to getAttempts function.
|
||||
*/
|
||||
export type AddonModH5PActivityGetAttemptsOptions = {
|
||||
ignoreCache?: boolean; // Whether to ignore cache. Will fail if offline or server down.
|
||||
siteId?: string; // Site ID. If not defined, current site.
|
||||
userId?: number; // User ID. If not defined, user of the site.
|
||||
};
|
||||
export type AddonModH5PActivityGetAttemptsOptions = AddonModH5PActivityGetAttemptResultsOptions;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
|
@ -26,7 +26,7 @@ import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/acti
|
|||
import { CoreFilterHelperProvider } from '@core/filter/providers/helper';
|
||||
import { CoreH5PHelper } from '@core/h5p/classes/helper';
|
||||
import { CoreH5P } from '@core/h5p/providers/h5p';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreUser } from '@core/user/providers/user';
|
||||
import { AddonModH5PActivity, AddonModH5PActivityProvider, AddonModH5PActivityData } from './h5pactivity';
|
||||
|
||||
/**
|
||||
|
@ -47,9 +47,7 @@ export class AddonModH5PActivityPrefetchHandler extends CoreCourseActivityPrefet
|
|||
sitesProvider: CoreSitesProvider,
|
||||
domUtils: CoreDomUtilsProvider,
|
||||
filterHelper: CoreFilterHelperProvider,
|
||||
pluginFileDelegate: CorePluginFileDelegate,
|
||||
protected userProvider: CoreUserProvider,
|
||||
protected injector: Injector) {
|
||||
pluginFileDelegate: CorePluginFileDelegate) {
|
||||
|
||||
super(translate, appProvider, utils, courseProvider, filepoolProvider, sitesProvider, domUtils, filterHelper,
|
||||
pluginFileDelegate);
|
||||
|
@ -137,7 +135,7 @@ export class AddonModH5PActivityPrefetchHandler extends CoreCourseActivityPrefet
|
|||
const introFiles = this.getIntroFilesFromInstance(module, h5pActivity);
|
||||
|
||||
await Promise.all([
|
||||
AddonModH5PActivity.instance.getAccessInformation(h5pActivity.id, true, siteId),
|
||||
this.prefetchWSData(h5pActivity, siteId),
|
||||
this.filepoolProvider.addFilesToQueue(siteId, introFiles, AddonModH5PActivityProvider.COMPONENT, module.id),
|
||||
this.prefetchMainFile(module, h5pActivity, siteId),
|
||||
]);
|
||||
|
@ -163,4 +161,31 @@ export class AddonModH5PActivityPrefetchHandler extends CoreCourseActivityPrefet
|
|||
|
||||
await this.filepoolProvider.addFilesToQueue(siteId, [deployedFile], AddonModH5PActivityProvider.COMPONENT, module.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch all the WebService data.
|
||||
*
|
||||
* @param h5pActivity Activity instance.
|
||||
* @param siteId Site ID.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async prefetchWSData(h5pActivity: AddonModH5PActivityData, siteId: string): Promise<void> {
|
||||
|
||||
const accessInfo = await AddonModH5PActivity.instance.getAccessInformation(h5pActivity.id, true, siteId);
|
||||
|
||||
if (!accessInfo.canreviewattempts) {
|
||||
// Not a teacher, prefetch user attempts and the current user profile.
|
||||
const site = await this.sitesProvider.getSite(siteId);
|
||||
|
||||
const options = {
|
||||
ignoreCache: true,
|
||||
siteId: siteId,
|
||||
};
|
||||
|
||||
await Promise.all([
|
||||
AddonModH5PActivity.instance.getAllAttemptsResults(h5pActivity.id, options),
|
||||
CoreUser.instance.prefetchProfiles([site.getUserId()], h5pActivity.course, siteId),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue