commit
7d7316c6cd
|
@ -45,7 +45,6 @@
|
|||
"addon.block_myoverview.hiddencourses": "block_myoverview",
|
||||
"addon.block_myoverview.inprogress": "block_myoverview",
|
||||
"addon.block_myoverview.lastaccessed": "block_myoverview",
|
||||
"addon.block_myoverview.morecourses": "block_myoverview",
|
||||
"addon.block_myoverview.nocourses": "block_myoverview",
|
||||
"addon.block_myoverview.past": "block_myoverview",
|
||||
"addon.block_myoverview.pluginname": "block_myoverview",
|
||||
|
@ -1383,6 +1382,7 @@
|
|||
"core.choose": "moodle",
|
||||
"core.choosedots": "moodle",
|
||||
"core.clearsearch": "local_moodlemobileapp",
|
||||
"core.clearstoreddata": "local_moodlemobileapp",
|
||||
"core.clicktohideshow": "moodle",
|
||||
"core.clicktoseefull": "local_moodlemobileapp",
|
||||
"core.close": "repository",
|
||||
|
@ -1436,6 +1436,7 @@
|
|||
"core.course.availablespace": "local_moodlemobileapp",
|
||||
"core.course.cannotdeletewhiledownloading": "local_moodlemobileapp",
|
||||
"core.course.confirmdeletemodulefiles": "local_moodlemobileapp",
|
||||
"core.course.confirmdeletestoreddata": "local_moodlemobileapp",
|
||||
"core.course.confirmdownload": "local_moodlemobileapp",
|
||||
"core.course.confirmdownloadunknownsize": "local_moodlemobileapp",
|
||||
"core.course.confirmdownloadzerosize": "local_moodlemobileapp",
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
"hiddencourses": "Removed from view",
|
||||
"inprogress": "In progress",
|
||||
"lastaccessed": "Last accessed",
|
||||
"morecourses": "More courses",
|
||||
"nocourses": "No courses",
|
||||
"past": "Past",
|
||||
"pluginname": "Course overview",
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
this.hasOffline = hasOffline;
|
||||
|
||||
// Get assignment submissions.
|
||||
return this.assignProvider.getSubmissions(this.assign.id).then((data) => {
|
||||
return this.assignProvider.getSubmissions(this.assign.id, {cmId: this.module.id}).then((data) => {
|
||||
const time = this.timeUtils.timestamp();
|
||||
|
||||
this.canViewAllSubmissions = data.canviewsubmissions;
|
||||
|
@ -217,7 +217,7 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
}
|
||||
|
||||
// Check if the user can view their own submission.
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id).then(() => {
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id, {cmId: this.module.id}).then(() => {
|
||||
this.canViewOwnSubmission = true;
|
||||
}).catch((error) => {
|
||||
this.canViewOwnSubmission = false;
|
||||
|
@ -241,7 +241,10 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
setGroup(groupId: number): Promise<any> {
|
||||
this.group = groupId;
|
||||
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id, undefined, this.group).then((response) => {
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id, {
|
||||
groupId: this.group,
|
||||
cmId: this.module.id,
|
||||
}).then((response) => {
|
||||
this.summary = response.gradingsummary;
|
||||
if (typeof this.summary.warnofungroupedusers == 'boolean' && this.summary.warnofungroupedusers) {
|
||||
this.summary.warnofungroupedusers = 'ungroupedusers';
|
||||
|
|
|
@ -460,7 +460,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
|
|||
await Promise.all(promises);
|
||||
|
||||
// Get submission status.
|
||||
const response = await this.assignProvider.getSubmissionStatusWithRetry(this.assign, this.submitId, undefined, isBlind);
|
||||
const response = await this.assignProvider.getSubmissionStatusWithRetry(this.assign, {userId: this.submitId, isBlind});
|
||||
|
||||
promises = [];
|
||||
|
||||
|
@ -996,7 +996,9 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
|
|||
response.lastattempt.submissiongroupmemberswhoneedtosubmit.forEach((member) => {
|
||||
if (this.blindMarking) {
|
||||
// Users not blinded! (Moodle < 3.1.1, 3.2).
|
||||
promises.push(this.assignProvider.getAssignmentUserMappings(this.assign.id, member).then((blindId) => {
|
||||
promises.push(this.assignProvider.getAssignmentUserMappings(this.assign.id, member, {
|
||||
cmId: this.moduleId,
|
||||
}).then((blindId) => {
|
||||
this.membersToSubmit.push(blindId);
|
||||
}));
|
||||
} else {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/co
|
|||
import { IonicPage, NavController, NavParams } from 'ionic-angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreFileUploaderHelperProvider } from '@core/fileuploader/providers/helper';
|
||||
|
@ -125,11 +125,20 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
|
|||
}).then(() => {
|
||||
|
||||
// Get submission status. Ignore cache to get the latest data.
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, undefined, this.isBlind, false, true)
|
||||
.catch((err) => {
|
||||
const options = {
|
||||
userId: this.userId,
|
||||
isBlind: this.isBlind,
|
||||
cmId: this.assign.cmid,
|
||||
filter: false,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id, options).catch((err) => {
|
||||
// Cannot connect. Get cached data.
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, undefined, this.isBlind)
|
||||
.then((response) => {
|
||||
options.filter = true;
|
||||
options.readingStrategy = CoreSitesReadingStrategy.PreferCache;
|
||||
|
||||
return this.assignProvider.getSubmissionStatus(this.assign.id, options).then((response) => {
|
||||
const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, response.lastattempt);
|
||||
|
||||
// Check if the user can edit it in offline.
|
||||
|
|
|
@ -153,7 +153,7 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
// Get assignment submissions.
|
||||
this.submissionsData = await this.assignProvider.getSubmissions(this.assign.id);
|
||||
this.submissionsData = await this.assignProvider.getSubmissions(this.assign.id, {cmId: this.assign.cmid});
|
||||
|
||||
if (!this.submissionsData.canviewsubmissions) {
|
||||
// User shouldn't be able to reach here.
|
||||
|
@ -192,7 +192,8 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
|
|||
const promises = [
|
||||
this.assignHelper.getSubmissionsUserData(this.assign, this.submissionsData.submissions, this.groupId),
|
||||
// Get assignment grades only if workflow is not enabled to check grading date.
|
||||
!this.assign.markingworkflow ? this.assignProvider.getAssignmentGrades(this.assign.id) : Promise.resolve(null),
|
||||
!this.assign.markingworkflow ? this.assignProvider.getAssignmentGrades(this.assign.id, {cmId: this.assign.cmid}) :
|
||||
Promise.resolve(null),
|
||||
];
|
||||
|
||||
return Promise.all(promises).then(([submissions, grades]: [AddonModAssignSubmissionFormatted[], AddonModAssignGrade[]]) => {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
@ -251,7 +251,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
|
|||
|
||||
const courseId = submissions.length > 0 ? submissions[0].courseid : grades[0].courseid;
|
||||
|
||||
const assign = await this.assignProvider.getAssignmentById(courseId, assignId, false, siteId);
|
||||
const assign = await this.assignProvider.getAssignmentById(courseId, assignId, {siteId});
|
||||
|
||||
let promises = [];
|
||||
|
||||
|
@ -340,8 +340,14 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
|
|||
|
||||
const userId = offlineData.userid;
|
||||
const pluginData = {};
|
||||
const options = {
|
||||
userId,
|
||||
cmId: assign.cmid,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
const status = await this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId);
|
||||
const status = await this.assignProvider.getSubmissionStatus(assign.id, options);
|
||||
|
||||
const submission = this.assignProvider.getSubmissionObjectFromAttempt(assign, status.lastattempt);
|
||||
|
||||
|
@ -370,7 +376,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
|
|||
}
|
||||
|
||||
// Submission data sent, update cached data. No need to block the user for this.
|
||||
this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId);
|
||||
this.assignProvider.getSubmissionStatus(assign.id, options);
|
||||
} catch (error) {
|
||||
if (!error || !this.utils.isWebServiceError(error)) {
|
||||
// Local error, reject.
|
||||
|
@ -422,6 +428,12 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
|
|||
|
||||
const userId = offlineData.userid;
|
||||
const syncId = this.getGradeSyncId(assign.id, userId);
|
||||
const options = {
|
||||
userId,
|
||||
cmId: assign.cmid,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
// Check if this grade sync is blocked.
|
||||
if (this.syncProvider.isBlocked(AddonModAssignProvider.COMPONENT, syncId, siteId)) {
|
||||
|
@ -431,7 +443,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
|
|||
{$a: this.translate.instant('addon.mod_assign.syncblockedusercomponent')}));
|
||||
}
|
||||
|
||||
const status = await this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId);
|
||||
const status = await this.assignProvider.getSubmissionStatus(assign.id, options);
|
||||
|
||||
const timemodified = status.feedback && (status.feedback.gradeddate || status.feedback.grade.timemodified);
|
||||
|
||||
|
@ -483,7 +495,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
|
|||
}
|
||||
|
||||
// Update cached data.
|
||||
promises.push(this.assignProvider.getSubmissionStatus(assign.id, userId, undefined, false, true, true, siteId));
|
||||
promises.push(this.assignProvider.getSubmissionStatus(assign.id, options));
|
||||
|
||||
await Promise.all(promises);
|
||||
} catch (error) {
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
|
@ -25,9 +25,10 @@ import { CoreGradesProvider } from '@core/grades/providers/grades';
|
|||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { AddonModAssignSubmissionDelegate } from './submission-delegate';
|
||||
import { AddonModAssignOfflineProvider } from './assign-offline';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreInterceptor } from '@classes/interceptor';
|
||||
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Service that provides some functions for assign.
|
||||
|
@ -143,12 +144,11 @@ export class AddonModAssignProvider {
|
|||
*
|
||||
* @param courseId Course ID the assignment belongs to.
|
||||
* @param cmId Assignment module ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the assignment.
|
||||
*/
|
||||
getAssignment(courseId: number, cmId: number, ignoreCache?: boolean, siteId?: string): Promise<AddonModAssignAssign> {
|
||||
return this.getAssignmentByField(courseId, 'cmid', cmId, ignoreCache, siteId);
|
||||
getAssignment(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModAssignAssign> {
|
||||
return this.getAssignmentByField(courseId, 'cmid', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -157,27 +157,23 @@ export class AddonModAssignProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the assignment is retrieved.
|
||||
*/
|
||||
protected getAssignmentByField(courseId: number, key: string, value: any, ignoreCache?: boolean, siteId?: string)
|
||||
protected getAssignmentByField(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModAssignAssign> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId],
|
||||
includenotenrolledcourses: 1
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAssignmentCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
courseids: [courseId],
|
||||
includenotenrolledcourses: 1,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAssignmentCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModAssignProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_assign_get_assignments', params, preSets).catch(() => {
|
||||
// In 3.6 we added a new parameter includenotenrolledcourses that could cause offline data not to be found.
|
||||
|
@ -206,13 +202,12 @@ export class AddonModAssignProvider {
|
|||
* Get an assignment by instance ID.
|
||||
*
|
||||
* @param courseId Course ID the assignment belongs to.
|
||||
* @param cmId Assignment instance ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param id Assignment instance ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the assignment.
|
||||
*/
|
||||
getAssignmentById(courseId: number, id: number, ignoreCache?: boolean, siteId?: string): Promise<AddonModAssignAssign> {
|
||||
return this.getAssignmentByField(courseId, 'id', id, ignoreCache, siteId);
|
||||
getAssignmentById(courseId: number, id: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModAssignAssign> {
|
||||
return this.getAssignmentByField(courseId, 'id', id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,24 +225,22 @@ export class AddonModAssignProvider {
|
|||
*
|
||||
* @param assignId Assignment Id.
|
||||
* @param userId User Id to be blinded.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the user blind id.
|
||||
*/
|
||||
getAssignmentUserMappings(assignId: number, userId: number, ignoreCache?: boolean, siteId?: string): Promise<number> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
assignmentids: [assignId]
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAssignmentUserMappingsCacheKey(assignId),
|
||||
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
||||
};
|
||||
getAssignmentUserMappings(assignId: number, userId: number, options: CoreCourseCommonModWSOptions = {}): Promise<number> {
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
assignmentids: [assignId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAssignmentUserMappingsCacheKey(assignId),
|
||||
updateFrequency: CoreSite.FREQUENCY_OFTEN,
|
||||
component: AddonModAssignProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_assign_get_user_mappings', params, preSets)
|
||||
.then((response: AddonModAssignGetUserMappingsResult): any => {
|
||||
|
@ -293,23 +286,21 @@ export class AddonModAssignProvider {
|
|||
* Returns grade information from assign_grades for the requested assignment id
|
||||
*
|
||||
* @param assignId Assignment Id.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Resolved with requested info when done.
|
||||
*/
|
||||
getAssignmentGrades(assignId: number, ignoreCache?: boolean, siteId?: string): Promise<AddonModAssignGrade[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
assignmentids: [assignId]
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAssignmentGradesCacheKey(assignId)
|
||||
};
|
||||
getAssignmentGrades(assignId: number, options: CoreCourseCommonModWSOptions = {}): Promise<AddonModAssignGrade[]> {
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
assignmentids: [assignId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAssignmentGradesCacheKey(assignId),
|
||||
component: AddonModAssignProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_assign_get_grades', params, preSets).then((response: AddonModAssignGetGradesResult): any => {
|
||||
// Search the assignment.
|
||||
|
@ -455,26 +446,23 @@ export class AddonModAssignProvider {
|
|||
* Get an assignment submissions.
|
||||
*
|
||||
* @param assignId Assignment id.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
getSubmissions(assignId: number, ignoreCache?: boolean, siteId?: string)
|
||||
getSubmissions(assignId: number, options: CoreCourseCommonModWSOptions = {})
|
||||
: Promise<{canviewsubmissions: boolean, submissions?: AddonModAssignSubmission[]}> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
assignmentids: [assignId]
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getSubmissionsCacheKey(assignId),
|
||||
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
assignmentids: [assignId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getSubmissionsCacheKey(assignId),
|
||||
updateFrequency: CoreSite.FREQUENCY_OFTEN,
|
||||
component: AddonModAssignProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_assign_get_submissions', params, preSets)
|
||||
.then((response: AddonModAssignGetSubmissionsResult): any => {
|
||||
|
@ -510,46 +498,40 @@ export class AddonModAssignProvider {
|
|||
* Get information about an assignment submission status for a given user.
|
||||
*
|
||||
* @param assignId Assignment instance id.
|
||||
* @param userId User Id (empty for current user).
|
||||
* @param groupId Group Id (empty for all participants).
|
||||
* @param isBlind If blind marking is enabled or not.
|
||||
* @param filter True to filter WS response and rewrite URLs, false otherwise.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site id (empty for current site).
|
||||
* @param options Other options.
|
||||
* @return Promise always resolved with the user submission status.
|
||||
*/
|
||||
getSubmissionStatus(assignId: number, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true,
|
||||
ignoreCache?: boolean, siteId?: string): Promise<AddonModAssignGetSubmissionStatusResult> {
|
||||
getSubmissionStatus(assignId: number, options: AddonModAssignSubmissionStatusOptions = {})
|
||||
: Promise<AddonModAssignGetSubmissionStatusResult> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const fixedParams = this.fixSubmissionStatusParams(site, userId, groupId, isBlind);
|
||||
if (options.filter === undefined || options.filter === null) {
|
||||
options.filter = true;
|
||||
}
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const fixedParams = this.fixSubmissionStatusParams(site, options.userId, options.groupId, options.isBlind);
|
||||
|
||||
const params = {
|
||||
assignid: assignId,
|
||||
userid: fixedParams.userId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getSubmissionStatusCacheKey(assignId, fixedParams.userId, fixedParams.groupId,
|
||||
fixedParams.isBlind),
|
||||
getCacheUsingCacheKey: true, // We use the cache key to take isBlind into account.
|
||||
filter: filter,
|
||||
rewriteurls: filter
|
||||
};
|
||||
|
||||
assignid: assignId,
|
||||
userid: fixedParams.userId,
|
||||
};
|
||||
if (fixedParams.groupId) {
|
||||
params['groupid'] = fixedParams.groupId;
|
||||
}
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
if (!filter) {
|
||||
const preSets = {
|
||||
cacheKey: this.getSubmissionStatusCacheKey(assignId, fixedParams.userId, fixedParams.groupId,
|
||||
fixedParams.isBlind),
|
||||
getCacheUsingCacheKey: true, // We use the cache key to take isBlind into account.
|
||||
filter: options.filter,
|
||||
rewriteurls: options.filter,
|
||||
component: AddonModAssignProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
// Don't cache when getting text without filters.
|
||||
// @todo Change this to support offline editing.
|
||||
preSets.saveToCache = false;
|
||||
}
|
||||
saveToCache: options.filter,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_assign_get_submission_status', params, preSets);
|
||||
});
|
||||
|
@ -560,23 +542,24 @@ export class AddonModAssignProvider {
|
|||
* If the data doesn't include the user submission, retry ignoring cache.
|
||||
*
|
||||
* @param assign Assignment.
|
||||
* @param userId User id (empty for current user).
|
||||
* @param groupId Group Id (empty for all participants).
|
||||
* @param isBlind If blind marking is enabled or not.
|
||||
* @param filter True to filter WS response and rewrite URLs, false otherwise.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site id (empty for current site).
|
||||
* @param options Other options.
|
||||
* @return Promise always resolved with the user submission status.
|
||||
*/
|
||||
getSubmissionStatusWithRetry(assign: any, userId?: number, groupId?: number, isBlind?: boolean, filter: boolean = true,
|
||||
ignoreCache?: boolean, siteId?: string): Promise<AddonModAssignGetSubmissionStatusResult> {
|
||||
getSubmissionStatusWithRetry(assign: any, options: AddonModAssignSubmissionStatusOptions = {})
|
||||
: Promise<AddonModAssignGetSubmissionStatusResult> {
|
||||
options.cmId = options.cmId || assign.cmid;
|
||||
|
||||
return this.getSubmissionStatus(assign.id, userId, groupId, isBlind, filter, ignoreCache, siteId).then((response) => {
|
||||
return this.getSubmissionStatus(assign.id, options).then((response) => {
|
||||
const userSubmission = this.getSubmissionObjectFromAttempt(assign, response.lastattempt);
|
||||
|
||||
if (!userSubmission) {
|
||||
// Try again, ignoring cache.
|
||||
return this.getSubmissionStatus(assign.id, userId, groupId, isBlind, filter, true, siteId).catch(() => {
|
||||
const newOptions = {
|
||||
...options, // Include all the original options.
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
|
||||
return this.getSubmissionStatus(assign.id, newOptions).catch(() => {
|
||||
// Error, return the first result even if it doesn't have the user submission.
|
||||
return response;
|
||||
});
|
||||
|
@ -650,35 +633,32 @@ export class AddonModAssignProvider {
|
|||
*
|
||||
* @param assignId Assignment id.
|
||||
* @param groupId Group id. If not defined, 0.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the list of participants and summary of submissions.
|
||||
*/
|
||||
listParticipants(assignId: number, groupId?: number, ignoreCache?: boolean, siteId?: string)
|
||||
listParticipants(assignId: number, groupId?: number, options: CoreCourseCommonModWSOptions = {})
|
||||
: Promise<AddonModAssignParticipant[]> {
|
||||
|
||||
groupId = groupId || 0;
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
if (!site.wsAvailable('mod_assign_list_participants')) {
|
||||
// Silently fail if is not available. (needs Moodle version >= 3.2)
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
||||
const params = {
|
||||
assignid: assignId,
|
||||
groupid: groupId,
|
||||
filter: ''
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.listParticipantsCacheKey(assignId, groupId),
|
||||
updateFrequency: CoreSite.FREQUENCY_OFTEN
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
assignid: assignId,
|
||||
groupid: groupId,
|
||||
filter: '',
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.listParticipantsCacheKey(assignId, groupId),
|
||||
updateFrequency: CoreSite.FREQUENCY_OFTEN,
|
||||
component: AddonModAssignProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_assign_list_participants', params, preSets);
|
||||
});
|
||||
|
@ -769,7 +749,7 @@ export class AddonModAssignProvider {
|
|||
invalidateContent(moduleId: number, courseId: number, siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.getAssignment(courseId, moduleId, false, siteId).then((assign) => {
|
||||
return this.getAssignment(courseId, moduleId, {siteId}).then((assign) => {
|
||||
const promises = [];
|
||||
|
||||
// Do not invalidate assignment data before getting assignment info, we need it!
|
||||
|
@ -1014,7 +994,10 @@ export class AddonModAssignProvider {
|
|||
}
|
||||
|
||||
// We need more data to decide that.
|
||||
return this.getSubmissionStatus(assignId, submission.submitid, undefined, submission.blindid).then((response) => {
|
||||
return this.getSubmissionStatus(assignId, {
|
||||
userId: submission.submitid,
|
||||
isBlind: !!submission.blindid,
|
||||
}).then((response) => {
|
||||
if (!response.feedback || !response.feedback.gradeddate) {
|
||||
// Not graded.
|
||||
return true;
|
||||
|
@ -1304,6 +1287,16 @@ export class AddonModAssignProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to pass to get submission status.
|
||||
*/
|
||||
export type AddonModAssignSubmissionStatusOptions = CoreCourseCommonModWSOptions & {
|
||||
userId?: number; // User Id (empty for current user).
|
||||
groupId?: number; // Group Id (empty for all participants).
|
||||
isBlind?: boolean; // If blind marking is enabled or not.
|
||||
filter?: boolean; // True to filter WS response and rewrite URLs, false otherwise. Defaults to true.
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign data returned by mod_assign_get_assignments.
|
||||
*/
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreFileProvider } from '@providers/file';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
||||
import { AddonModAssignFeedbackDelegate } from './feedback-delegate';
|
||||
|
@ -209,29 +209,29 @@ export class AddonModAssignHelperProvider {
|
|||
*
|
||||
* @param assign Assignment object.
|
||||
* @param groupId Group Id.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the list of participants and summary of submissions.
|
||||
*/
|
||||
getParticipants(assign: AddonModAssignAssign, groupId?: number, ignoreCache?: boolean, siteId?: string)
|
||||
getParticipants(assign: AddonModAssignAssign, groupId?: number, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModAssignParticipant[]> {
|
||||
|
||||
groupId = groupId || 0;
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.assignProvider.listParticipants(assign.id, groupId, ignoreCache, siteId).then((participants) => {
|
||||
const modOptions = {cmId: assign.cmid, ...options}; // Create new options including all existing ones.
|
||||
|
||||
return this.assignProvider.listParticipants(assign.id, groupId, modOptions).then((participants) => {
|
||||
if (groupId || participants && participants.length > 0) {
|
||||
return participants;
|
||||
}
|
||||
|
||||
// If no participants returned and all groups specified, get participants by groups.
|
||||
return this.groupsProvider.getActivityGroupInfo(assign.cmid, false, undefined, siteId).then((info) => {
|
||||
return this.groupsProvider.getActivityGroupInfo(assign.cmid, false, undefined, modOptions.siteId).then((info) => {
|
||||
const promises = [],
|
||||
participants: {[id: number]: AddonModAssignParticipant} = {};
|
||||
|
||||
info.groups.forEach((userGroup) => {
|
||||
promises.push(this.assignProvider.listParticipants(assign.id, userGroup.id, ignoreCache, siteId)
|
||||
.then((parts) => {
|
||||
promises.push(this.assignProvider.listParticipants(assign.id, userGroup.id, modOptions).then((parts) => {
|
||||
// Do not get repeated users.
|
||||
parts.forEach((participant) => {
|
||||
participants[participant.id] = participant;
|
||||
|
@ -355,14 +355,15 @@ export class AddonModAssignHelperProvider {
|
|||
* @param assign Assignment object.
|
||||
* @param submissions Submissions to get the data for.
|
||||
* @param groupId Group Id.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site id (empty for current site).
|
||||
* @param options Other options.
|
||||
* @return Promise always resolved. Resolve param is the formatted submissions.
|
||||
*/
|
||||
getSubmissionsUserData(assign: AddonModAssignAssign, submissions: AddonModAssignSubmissionFormatted[], groupId?: number,
|
||||
ignoreCache?: boolean, siteId?: string): Promise<AddonModAssignSubmissionFormatted[]> {
|
||||
options: CoreSitesCommonWSOptions = {}): Promise<AddonModAssignSubmissionFormatted[]> {
|
||||
|
||||
return this.getParticipants(assign, groupId).then((parts) => {
|
||||
const modOptions = {cmId: assign.cmid, ...options}; // Create new options including all existing ones.
|
||||
|
||||
return this.getParticipants(assign, groupId, modOptions).then((parts) => {
|
||||
const blind = assign.blindmarking && !assign.revealidentities;
|
||||
const promises = [];
|
||||
const result: AddonModAssignSubmissionFormatted[] = [];
|
||||
|
@ -399,8 +400,8 @@ export class AddonModAssignHelperProvider {
|
|||
// Blind but not blinded! (Moodle < 3.1.1, 3.2).
|
||||
delete submission.userid;
|
||||
|
||||
promise = this.assignProvider.getAssignmentUserMappings(assign.id, submission.submitid, ignoreCache, siteId).
|
||||
then((blindId) => {
|
||||
promise = this.assignProvider.getAssignmentUserMappings(assign.id, submission.submitid, modOptions)
|
||||
.then((blindId) => {
|
||||
submission.blindid = blindId;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
|
@ -80,13 +80,13 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
canUseCheckUpdates(module: any, courseId: number): boolean | Promise<boolean> {
|
||||
// Teachers cannot use the WS because it doesn't check student submissions.
|
||||
return this.assignProvider.getAssignment(courseId, module.id).then((assign) => {
|
||||
return this.assignProvider.getSubmissions(assign.id).then((data) => {
|
||||
return this.assignProvider.getSubmissions(assign.id, {cmId: module.id}).then((data) => {
|
||||
if (data.canviewsubmissions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the user can view their own submission.
|
||||
return this.assignProvider.getSubmissionStatus(assign.id).then(() => {
|
||||
return this.assignProvider.getSubmissionStatus(assign.id, {cmId: module.id}).then(() => {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
@ -108,18 +108,18 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.assignProvider.getAssignment(courseId, module.id, false, siteId).then((assign) => {
|
||||
return this.assignProvider.getAssignment(courseId, module.id, {siteId}).then((assign) => {
|
||||
// Get intro files and attachments.
|
||||
let files = assign.introattachments || [];
|
||||
files = files.concat(this.getIntroFilesFromInstance(module, assign));
|
||||
|
||||
// Now get the files in the submissions.
|
||||
return this.assignProvider.getSubmissions(assign.id, false, siteId).then((data) => {
|
||||
return this.assignProvider.getSubmissions(assign.id, {cmId: module.id, siteId}).then((data) => {
|
||||
const blindMarking = assign.blindmarking && !assign.revealidentities;
|
||||
|
||||
if (data.canviewsubmissions) {
|
||||
// Teacher, get all submissions.
|
||||
return this.assignHelper.getSubmissionsUserData(assign, data.submissions, 0, false, siteId)
|
||||
return this.assignHelper.getSubmissionsUserData(assign, data.submissions, 0, {siteId})
|
||||
.then((submissions: AddonModAssignSubmissionFormatted[]) => {
|
||||
|
||||
const promises = [];
|
||||
|
@ -172,8 +172,11 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
protected getSubmissionFiles(assign: any, submitId: number, blindMarking: boolean, siteId?: string)
|
||||
: Promise<any[]> {
|
||||
|
||||
return this.assignProvider.getSubmissionStatusWithRetry(assign, submitId, undefined, blindMarking, true, false, siteId)
|
||||
.then((response) => {
|
||||
return this.assignProvider.getSubmissionStatusWithRetry(assign, {
|
||||
userId: submitId,
|
||||
isBlind: blindMarking,
|
||||
siteId,
|
||||
}).then((response) => {
|
||||
const promises = [];
|
||||
let userSubmission: AddonModAssignSubmission;
|
||||
|
||||
|
@ -261,20 +264,24 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected prefetchAssign(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
const userId = this.sitesProvider.getCurrentSiteUserId(),
|
||||
promises = [];
|
||||
const userId = this.sitesProvider.getCurrentSiteUserId();
|
||||
const promises = [];
|
||||
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const options = {
|
||||
cmId: module.id,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
// Get assignment to retrieve all its submissions.
|
||||
promises.push(this.assignProvider.getAssignment(courseId, module.id, true, siteId).then((assign) => {
|
||||
promises.push(this.assignProvider.getAssignment(courseId, module.id, options).then((assign) => {
|
||||
const subPromises = [],
|
||||
blindMarking = assign.blindmarking && !assign.revealidentities;
|
||||
|
||||
if (blindMarking) {
|
||||
subPromises.push(this.assignProvider.getAssignmentUserMappings(assign.id, undefined, true, siteId).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
subPromises.push(this.utils.ignoreErrors(this.assignProvider.getAssignmentUserMappings(assign.id, -1, options)));
|
||||
}
|
||||
|
||||
subPromises.push(this.prefetchSubmissions(assign, courseId, module.id, userId, siteId));
|
||||
|
@ -304,8 +311,14 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
* @return Promise resolved when prefetched, rejected otherwise.
|
||||
*/
|
||||
protected prefetchSubmissions(assign: any, courseId: number, moduleId: number, userId: number, siteId: string): Promise<any> {
|
||||
const options = {
|
||||
cmId: moduleId,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
// Get submissions.
|
||||
return this.assignProvider.getSubmissions(assign.id, true, siteId).then((data) => {
|
||||
return this.assignProvider.getSubmissions(assign.id, options).then((data) => {
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.groupsProvider.getActivityGroupInfo(assign.cmid, false, undefined, siteId).then((groupInfo) => {
|
||||
|
@ -317,14 +330,22 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
}
|
||||
|
||||
groupInfo.groups.forEach((group) => {
|
||||
groupProms.push(this.assignHelper.getSubmissionsUserData(assign, data.submissions, group.id, true, siteId)
|
||||
groupProms.push(this.assignHelper.getSubmissionsUserData(assign, data.submissions, group.id, options)
|
||||
.then((submissions: AddonModAssignSubmissionFormatted[]) => {
|
||||
|
||||
const subPromises = [];
|
||||
|
||||
submissions.forEach((submission) => {
|
||||
subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, submission.submitid,
|
||||
group.id, !!submission.blindid, true, true, siteId).then((subm) => {
|
||||
const submissionOptions = {
|
||||
userId: submission.submitid,
|
||||
groupId: group.id,
|
||||
isBlind: !!submission.blindid,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, submissionOptions)
|
||||
.then((subm) => {
|
||||
return this.prefetchSubmission(assign, courseId, moduleId, subm, submission.submitid, siteId);
|
||||
}).catch((error) => {
|
||||
if (error && error.errorcode == 'nopermission') {
|
||||
|
@ -338,14 +359,21 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
|
||||
if (!assign.markingworkflow) {
|
||||
// Get assignment grades only if workflow is not enabled to check grading date.
|
||||
subPromises.push(this.assignProvider.getAssignmentGrades(assign.id, true, siteId));
|
||||
subPromises.push(this.assignProvider.getAssignmentGrades(assign.id, options));
|
||||
}
|
||||
|
||||
// Prefetch the submission of the current user even if it does not exist, this will be create it.
|
||||
if (!data.submissions ||
|
||||
!data.submissions.find((subm: AddonModAssignSubmissionFormatted) => subm.submitid == userId)) {
|
||||
subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, userId, group.id,
|
||||
false, true, true, siteId).then((subm) => {
|
||||
const submissionOptions = {
|
||||
userId,
|
||||
groupId: group.id,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
subPromises.push(this.assignProvider.getSubmissionStatusWithRetry(assign, submissionOptions)
|
||||
.then((subm) => {
|
||||
return this.prefetchSubmission(assign, courseId, moduleId, subm, userId, siteId);
|
||||
}));
|
||||
}
|
||||
|
@ -353,7 +381,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
return Promise.all(subPromises);
|
||||
}).then(() => {
|
||||
// Participiants already fetched, we don't need to ignore cache now.
|
||||
return this.assignHelper.getParticipants(assign, group.id, false, siteId).then((participants) => {
|
||||
return this.assignHelper.getParticipants(assign, group.id, {siteId}).then((participants) => {
|
||||
return this.userProvider.prefetchUserAvatars(participants, 'profileimageurl', siteId);
|
||||
}).catch(() => {
|
||||
// Fail silently (Moodle < 3.2).
|
||||
|
@ -367,8 +395,11 @@ export class AddonModAssignPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
|
||||
// Prefetch own submission, we need to do this for teachers too so the response with error is cached.
|
||||
promises.push(
|
||||
this.assignProvider.getSubmissionStatusWithRetry(assign, userId, undefined, false, true, true, siteId)
|
||||
.then((subm) => {
|
||||
this.assignProvider.getSubmissionStatusWithRetry(assign, {
|
||||
userId,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
}).then((subm) => {
|
||||
return this.prefetchSubmission(assign, courseId, moduleId, subm, userId, siteId);
|
||||
}).catch((error) => {
|
||||
// Ignore if the user can't view their own submission.
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
|
||||
<core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { CoreFileProvider } from '@providers/file';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
|
@ -73,11 +73,11 @@ export class AddonModBookProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the book is retrieved.
|
||||
*/
|
||||
getBook(courseId: number, cmId: number, siteId?: string): Promise<AddonModBookBook> {
|
||||
return this.getBookByField(courseId, 'coursemodule', cmId, siteId);
|
||||
getBook(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModBookBook> {
|
||||
return this.getBookByField(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,15 +89,19 @@ export class AddonModBookProvider {
|
|||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Promise resolved when the book is retrieved.
|
||||
*/
|
||||
protected getBookByField(courseId: number, key: string, value: any, siteId?: string): Promise<AddonModBookBook> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
protected getBookByField(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModBookBook> {
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getBookDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
courseids: [courseId]
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getBookDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModBookProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_book_get_books_by_courses', params, preSets)
|
||||
.then((response: AddonModBookGetBooksByCoursesResult): any => {
|
||||
|
|
|
@ -127,7 +127,8 @@ export class AddonModChatChatPage {
|
|||
showChatUsers(): void {
|
||||
// Create the toc modal.
|
||||
const modal = this.modalCtrl.create('AddonModChatUsersPage', {
|
||||
sessionId: this.sessionId
|
||||
sessionId: this.sessionId,
|
||||
cmId: this.cmId,
|
||||
}, { cssClass: 'core-modal-lateral',
|
||||
showBackdrop: true,
|
||||
enableBackdropDismiss: true,
|
||||
|
@ -168,7 +169,7 @@ export class AddonModChatChatPage {
|
|||
return Promise.resolve(user.fullname);
|
||||
}
|
||||
|
||||
return this.chatProvider.getChatUsers(this.sessionId).then((data) => {
|
||||
return this.chatProvider.getChatUsers(this.sessionId, {cmId: this.cmId}).then((data) => {
|
||||
this.users = data.users;
|
||||
const user = this.users.find((user) => user.id == id);
|
||||
|
||||
|
|
|
@ -60,8 +60,8 @@ export class AddonModChatSessionMessagesPage {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected fetchMessages(): Promise<any> {
|
||||
return this.chatProvider.getSessionMessages(this.chatId, this.sessionStart, this.sessionEnd, this.groupId)
|
||||
.then((messages) => {
|
||||
return this.chatProvider.getSessionMessages(this.chatId, this.sessionStart, this.sessionEnd, this.groupId,
|
||||
{cmId: this.cmId}).then((messages) => {
|
||||
return this.chatProvider.getMessagesUserData(messages, this.courseId).then((messages) => {
|
||||
this.messages = <AddonModChatSessionMessageForView[]> messages;
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ export class AddonModChatSessionsPage {
|
|||
this.groupInfo = groupInfo;
|
||||
this.groupId = this.groupsProvider.validateGroupId(this.groupId, groupInfo);
|
||||
|
||||
return this.chatProvider.getSessions(this.chatId, this.groupId, this.showAll);
|
||||
return this.chatProvider.getSessions(this.chatId, this.groupId, this.showAll, {cmId: this.cmId});
|
||||
}).then((sessions: AddonModChatSessionFormatted[]) => {
|
||||
// Fetch user profiles.
|
||||
const promises = [];
|
||||
|
|
|
@ -36,6 +36,7 @@ export class AddonModChatUsersPage {
|
|||
isOnline: boolean;
|
||||
|
||||
protected sessionId: string;
|
||||
protected cmId: number;
|
||||
protected onlineObserver: any;
|
||||
|
||||
constructor(navParams: NavParams, network: Network, zone: NgZone, private appProvider: CoreAppProvider,
|
||||
|
@ -56,7 +57,7 @@ export class AddonModChatUsersPage {
|
|||
* View loaded.
|
||||
*/
|
||||
ionViewDidLoad(): void {
|
||||
this.chatProvider.getChatUsers(this.sessionId).then((data) => {
|
||||
this.chatProvider.getChatUsers(this.sessionId, {cmId: this.cmId}).then((data) => {
|
||||
this.users = data.users;
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'addon.mod_chat.errorwhilegettingchatusers', true);
|
||||
|
|
|
@ -14,13 +14,14 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
|
||||
import { AddonModChatMessageForView, AddonModChatSessionMessageForView } from './helper';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Service that provides some features for chats.
|
||||
|
@ -40,17 +41,19 @@ export class AddonModChatProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the chat is retrieved.
|
||||
*/
|
||||
getChat(courseId: number, cmId: number, siteId?: string): Promise<AddonModChatChat> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getChat(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModChatChat> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getChatsCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModChatProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_chat_get_chats_by_courses', params, preSets)
|
||||
|
@ -179,17 +182,25 @@ export class AddonModChatProvider {
|
|||
* Get the actives users of a current chat.
|
||||
*
|
||||
* @param sessionId Chat sessiond ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the WS is executed.
|
||||
*/
|
||||
getChatUsers(sessionId: string): Promise<AddonModChatGetChatUsersResult> {
|
||||
const params = {
|
||||
chatsid: sessionId
|
||||
};
|
||||
const preSets = {
|
||||
getFromCache: false
|
||||
};
|
||||
getChatUsers(sessionId: string, options: CoreCourseCommonModWSOptions = {}): Promise<AddonModChatGetChatUsersResult> {
|
||||
// By default, always try to get the latest data.
|
||||
options.readingStrategy = options.readingStrategy || CoreSitesReadingStrategy.PreferNetwork;
|
||||
|
||||
return this.sitesProvider.getCurrentSite().read('mod_chat_get_chat_users', params, preSets);
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
chatsid: sessionId,
|
||||
};
|
||||
const preSets = {
|
||||
component: AddonModChatProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_chat_get_chat_users', params, preSets);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,28 +221,26 @@ export class AddonModChatProvider {
|
|||
* @param chatId Chat ID.
|
||||
* @param groupId Group ID, 0 means that the function will determine the user group.
|
||||
* @param showAll Whether to include incomplete sessions or not.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the list of sessions.
|
||||
* @since 3.5
|
||||
*/
|
||||
getSessions(chatId: number, groupId: number = 0, showAll: boolean = false, ignoreCache: boolean = false, siteId?: string):
|
||||
getSessions(chatId: number, groupId: number = 0, showAll: boolean = false, options: CoreCourseCommonModWSOptions = {}):
|
||||
Promise<AddonModChatSession[]> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
chatid: chatId,
|
||||
groupid: groupId,
|
||||
showall: showAll ? 1 : 0
|
||||
showall: showAll ? 1 : 0,
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getSessionsCacheKey(chatId, groupId, showAll),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModChatProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
return site.read('mod_chat_get_sessions', params, preSets).then((response: AddonModChatGetSessionsResult): any => {
|
||||
if (!response || !response.sessions) {
|
||||
|
@ -250,29 +259,27 @@ export class AddonModChatProvider {
|
|||
* @param sessionStart Session start time.
|
||||
* @param sessionEnd Session end time.
|
||||
* @param groupId Group ID, 0 means that the function will determine the user group.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the list of messages.
|
||||
* @since 3.5
|
||||
*/
|
||||
getSessionMessages(chatId: number, sessionStart: number, sessionEnd: number, groupId: number = 0, ignoreCache: boolean = false,
|
||||
siteId?: string): Promise<AddonModChatSessionMessage[]> {
|
||||
getSessionMessages(chatId: number, sessionStart: number, sessionEnd: number, groupId: number = 0,
|
||||
options: CoreCourseCommonModWSOptions = {}): Promise<AddonModChatSessionMessage[]> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
chatid: chatId,
|
||||
sessionstart: sessionStart,
|
||||
sessionend: sessionEnd,
|
||||
groupid: groupId
|
||||
groupid: groupId,
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getSessionMessagesCacheKey(chatId, sessionStart, groupId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModChatProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
return site.read('mod_chat_get_session_messages', params, preSets)
|
||||
.then((response: AddonModChatGetSessionMessagesResult): any => {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreGroupsProvider, CoreGroupInfo } from '@providers/groups';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
|
@ -122,9 +122,14 @@ export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
protected prefetchChat(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
// Prefetch chat and group info.
|
||||
const promises: Promise<any>[] = [
|
||||
this.chatProvider.getChat(courseId, module.id, siteId),
|
||||
this.chatProvider.getChat(courseId, module.id, {readingStrategy: CoreSitesReadingStrategy.OnlyNetwork, siteId}),
|
||||
this.groupsProvider.getActivityGroupInfo(module.id, false, undefined, siteId)
|
||||
];
|
||||
const options = {
|
||||
cmId: module.id,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
return Promise.all(promises).then(([chat, groupInfo]: [AddonModChatChat, CoreGroupInfo]) => {
|
||||
const promises = [];
|
||||
|
@ -136,7 +141,7 @@ export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
|
||||
groupIds.forEach((groupId) => {
|
||||
// Prefetch complete sessions.
|
||||
promises.push(this.chatProvider.getSessions(chat.id, groupId, false, true, siteId).catch((error) => {
|
||||
promises.push(this.chatProvider.getSessions(chat.id, groupId, false, options).catch((error) => {
|
||||
// Ignore group error.
|
||||
if (error.errorcode != 'notingroup') {
|
||||
return Promise.reject(error);
|
||||
|
@ -144,8 +149,9 @@ export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
}));
|
||||
|
||||
// Prefetch all sessions.
|
||||
promises.push(this.chatProvider.getSessions(chat.id, groupId, true, true, siteId).then((sessions) => {
|
||||
const promises = sessions.map((session) => this.prefetchSession(chat.id, session, 0, courseId, siteId));
|
||||
promises.push(this.chatProvider.getSessions(chat.id, groupId, true, options).then((sessions) => {
|
||||
const promises = sessions.map((session) => this.prefetchSession(chat.id, session, 0, courseId, module.id,
|
||||
siteId));
|
||||
|
||||
return Promise.all(promises);
|
||||
}).catch((error) => {
|
||||
|
@ -170,9 +176,13 @@ export class AddonModChatPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
* @param siteId Site ID.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected prefetchSession(chatId: number, session: any, groupId: number, courseId: number, siteId: string): Promise<any> {
|
||||
return this.chatProvider.getSessionMessages(chatId, session.sessionstart, session.sessionend, groupId, true, siteId)
|
||||
.then((messages) => {
|
||||
protected prefetchSession(chatId: number, session: any, groupId: number, courseId: number, cmId: number, siteId: string)
|
||||
: Promise<any> {
|
||||
return this.chatProvider.getSessionMessages(chatId, session.sessionstart, session.sessionend, groupId, {
|
||||
cmId,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
}).then((messages) => {
|
||||
const users = {};
|
||||
session.sessionusers.forEach((user) => {
|
||||
users[user.userid] = true;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected fetchOptions(hasOffline: boolean): Promise<any> {
|
||||
return this.choiceProvider.getOptions(this.choice.id).then((options) => {
|
||||
return this.choiceProvider.getOptions(this.choice.id, {cmId: this.module.id}).then((options) => {
|
||||
let promise;
|
||||
|
||||
// Check if the user has answered (synced) to allow show results.
|
||||
|
@ -294,7 +294,7 @@ export class AddonModChoiceIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return this.choiceProvider.getResults(this.choice.id).then((results) => {
|
||||
return this.choiceProvider.getResults(this.choice.id, {cmId: this.module.id}).then((results) => {
|
||||
let hasVotes = false;
|
||||
this.data = [];
|
||||
this.labels = [];
|
||||
|
|
|
@ -13,14 +13,15 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { AddonModChoiceOfflineProvider } from './offline';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Service that provides some features for choices.
|
||||
|
@ -173,34 +174,26 @@ export class AddonModChoiceProvider {
|
|||
/**
|
||||
* Get a choice with key=value. If more than one is found, only the first will be returned.
|
||||
*
|
||||
* @param siteId Site ID.
|
||||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the choice is retrieved.
|
||||
*/
|
||||
protected getChoiceByDataKey(siteId: string, courseId: number, key: string, value: any, forceCache?: boolean,
|
||||
ignoreCache?: boolean): Promise<AddonModChoiceChoice> {
|
||||
protected getChoiceByDataKey(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModChoiceChoice> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getChoiceDataCacheKey(courseId),
|
||||
omitExpires: forceCache,
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModChoiceProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
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: AddonModChoiceGetChoicesByCoursesResult): any => {
|
||||
|
||||
|
@ -221,14 +214,11 @@ export class AddonModChoiceProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the choice is retrieved.
|
||||
*/
|
||||
getChoice(courseId: number, cmId: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean)
|
||||
: Promise<AddonModChoiceChoice> {
|
||||
return this.getChoiceByDataKey(siteId, courseId, 'coursemodule', cmId, forceCache, ignoreCache);
|
||||
getChoice(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModChoiceChoice> {
|
||||
return this.getChoiceByDataKey(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,39 +226,33 @@ export class AddonModChoiceProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param choiceId Choice ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the choice is retrieved.
|
||||
*/
|
||||
getChoiceById(courseId: number, choiceId: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean)
|
||||
: Promise<AddonModChoiceChoice> {
|
||||
return this.getChoiceByDataKey(siteId, courseId, 'id', choiceId, forceCache, ignoreCache);
|
||||
getChoiceById(courseId: number, choiceId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModChoiceChoice> {
|
||||
return this.getChoiceByDataKey(courseId, 'id', choiceId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get choice options.
|
||||
*
|
||||
* @param choiceId Choice ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with choice options.
|
||||
*/
|
||||
getOptions(choiceId: number, ignoreCache?: boolean, siteId?: string): Promise<AddonModChoiceOption[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getOptions(choiceId: number, options: CoreCourseCommonModWSOptions = {}): Promise<AddonModChoiceOption[]> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
choiceid: choiceId
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getChoiceOptionsCacheKey(choiceId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModChoiceProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
return site.read('mod_choice_get_choice_options', params, preSets)
|
||||
.then((response: AddonModChoiceGetChoiceOptionsResult): any => {
|
||||
|
||||
|
@ -285,24 +269,21 @@ export class AddonModChoiceProvider {
|
|||
* Get choice results.
|
||||
*
|
||||
* @param choiceId Choice ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with choice results.
|
||||
*/
|
||||
getResults(choiceId: number, ignoreCache?: boolean, siteId?: string): Promise<AddonModChoiceResult[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getResults(choiceId: number, options: CoreCourseCommonModWSOptions = {}): Promise<AddonModChoiceResult[]> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
choiceid: choiceId
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getChoiceResultsCacheKey(choiceId)
|
||||
const preSets = {
|
||||
cacheKey: this.getChoiceOptionsCacheKey(choiceId),
|
||||
component: AddonModChoiceProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
return site.read('mod_choice_get_choice_results', params, preSets)
|
||||
.then((response: AddonModChoiceGetChoiceResults): any => {
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable, Injector } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
|
@ -79,12 +79,21 @@ export class AddonModChoicePrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected prefetchChoice(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
return this.choiceProvider.getChoice(courseId, module.id, siteId, false, true).then((choice) => {
|
||||
const commonOptions = {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
const modOptions = {
|
||||
cmId: module.id,
|
||||
...commonOptions, // Include all common options.
|
||||
};
|
||||
|
||||
return this.choiceProvider.getChoice(courseId, module.id, commonOptions).then((choice) => {
|
||||
const promises = [];
|
||||
|
||||
// Get the options and results.
|
||||
promises.push(this.choiceProvider.getOptions(choice.id, true, siteId));
|
||||
promises.push(this.choiceProvider.getResults(choice.id, true, siteId).then((options) => {
|
||||
promises.push(this.choiceProvider.getOptions(choice.id, modOptions));
|
||||
promises.push(this.choiceProvider.getResults(choice.id, modOptions).then((options) => {
|
||||
// If we can see the users that answered, prefetch their profile and avatar.
|
||||
const subPromises = [];
|
||||
options.forEach((option) => {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<core-context-menu-item [priority]="500" *ngIf="canAdd" [content]="'addon.mod_data.addentries' | translate" [iconAction]="'add'" (action)="gotoAddEntries($event)"></core-context-menu-item>
|
||||
<core-context-menu-item [priority]="400" *ngIf="firstEntry" [content]="'addon.mod_data.single' | translate" [iconAction]="'document'" (action)="gotoEntry(firstEntry)"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="300" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="200" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="200" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -198,7 +198,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
});
|
||||
}
|
||||
}).then(() => {
|
||||
return this.dataProvider.getDatabaseAccessInformation(this.data.id);
|
||||
return this.dataProvider.getDatabaseAccessInformation(this.data.id, {cmId: this.module.id});
|
||||
}).then((accessData) => {
|
||||
this.access = accessData;
|
||||
|
||||
|
@ -226,7 +226,7 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
this.selectedGroup = this.groupsProvider.validateGroupId(this.selectedGroup, groupInfo);
|
||||
});
|
||||
}).then(() => {
|
||||
return this.dataProvider.getFields(this.data.id).then((fields) => {
|
||||
return this.dataProvider.getFields(this.data.id, {cmId: this.module.id}).then((fields) => {
|
||||
if (fields.length == 0) {
|
||||
canSearch = false;
|
||||
canAdd = false;
|
||||
|
@ -252,15 +252,24 @@ export class AddonModDataIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
*/
|
||||
protected fetchEntriesData(): Promise<any> {
|
||||
|
||||
return this.dataProvider.getDatabaseAccessInformation(this.data.id, this.selectedGroup).then((accessData) => {
|
||||
return this.dataProvider.getDatabaseAccessInformation(this.data.id, {
|
||||
groupId: this.selectedGroup,
|
||||
cmId: this.module.id,
|
||||
}).then((accessData) => {
|
||||
// Update values for current group.
|
||||
this.access.canaddentry = accessData.canaddentry;
|
||||
|
||||
const search = this.search.searching && !this.search.searchingAdvanced ? this.search.text : undefined;
|
||||
const advSearch = this.search.searching && this.search.searchingAdvanced ? this.search.advanced : undefined;
|
||||
|
||||
return this.dataHelper.fetchEntries(this.data, this.fieldsArray, this.selectedGroup, search, advSearch,
|
||||
this.search.sortBy, this.search.sortDirection, this.search.page);
|
||||
return this.dataHelper.fetchEntries(this.data, this.fieldsArray, {
|
||||
groupId: this.selectedGroup,
|
||||
search,
|
||||
advSearch,
|
||||
sort: Number(this.search.sortBy),
|
||||
order: this.search.sortDirection,
|
||||
page: this.search.page,
|
||||
});
|
||||
}).then((entries) => {
|
||||
const numEntries = entries.entries.length;
|
||||
const numOfflineEntries = entries.offlineEntries.length;
|
||||
|
|
|
@ -128,7 +128,7 @@ export class AddonModDataEditPage {
|
|||
this.data = data;
|
||||
this.cssClass = 'addon-data-entries-' + data.id;
|
||||
|
||||
return this.dataProvider.getDatabaseAccessInformation(data.id);
|
||||
return this.dataProvider.getDatabaseAccessInformation(data.id, {cmId: this.module.id});
|
||||
}).then((accessData) => {
|
||||
if (this.entryId) {
|
||||
return this.groupsProvider.getActivityGroupInfo(this.data.coursemodule).then((groupInfo) => {
|
||||
|
@ -137,7 +137,7 @@ export class AddonModDataEditPage {
|
|||
});
|
||||
}
|
||||
}).then(() => {
|
||||
return this.dataProvider.getFields(this.data.id);
|
||||
return this.dataProvider.getFields(this.data.id, {cmId: this.module.id});
|
||||
}).then((fieldsData) => {
|
||||
this.fieldsArray = fieldsData;
|
||||
this.fields = this.utils.arrayToObject(fieldsData, 'id');
|
||||
|
|
|
@ -142,13 +142,13 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
this.title = data.name || this.title;
|
||||
this.data = data;
|
||||
|
||||
return this.dataProvider.getFields(this.data.id).then((fieldsData) => {
|
||||
return this.dataProvider.getFields(this.data.id, {cmId: this.module.id}).then((fieldsData) => {
|
||||
this.fields = this.utils.arrayToObject(fieldsData, 'id');
|
||||
this.fieldsArray = fieldsData;
|
||||
});
|
||||
}).then(() => {
|
||||
return this.setEntryFromOffset().then(() => {
|
||||
return this.dataProvider.getDatabaseAccessInformation(this.data.id);
|
||||
return this.dataProvider.getDatabaseAccessInformation(this.data.id, {cmId: this.module.id});
|
||||
});
|
||||
}).then((accessData) => {
|
||||
this.access = accessData;
|
||||
|
@ -290,8 +290,13 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
const perPage = AddonModDataProvider.PER_PAGE;
|
||||
const page = !emptyOffset && this.offset >= 0 ? Math.floor(this.offset / perPage) : 0;
|
||||
|
||||
return this.dataHelper.fetchEntries(this.data, this.fieldsArray, this.selectedGroup, undefined, undefined, '0', 'DESC',
|
||||
page, perPage).then((entries) => {
|
||||
return this.dataHelper.fetchEntries(this.data, this.fieldsArray, {
|
||||
groupId: this.selectedGroup,
|
||||
sort: 0,
|
||||
order: 'DESC',
|
||||
page,
|
||||
perPage,
|
||||
}).then((entries) => {
|
||||
|
||||
const pageEntries = entries.offlineEntries.concat(entries.entries);
|
||||
let pageIndex; // Index of the entry when concatenating offline and online page entries.
|
||||
|
@ -321,8 +326,11 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
this.nextOffset = null;
|
||||
} else {
|
||||
// Last entry of the page, check if there are more pages.
|
||||
promise = this.dataProvider.getEntries(this.data.id, this.selectedGroup, '0', 'DESC', page + 1, perPage)
|
||||
.then((entries) => {
|
||||
promise = this.dataProvider.getEntries(this.data.id, {
|
||||
groupId: this.selectedGroup,
|
||||
page: page + 1,
|
||||
perPage: perPage,
|
||||
}).then((entries) => {
|
||||
this.nextOffset = entries && entries.entries && entries.entries.length > 0 ? this.offset + 1 : null;
|
||||
});
|
||||
}
|
||||
|
@ -330,7 +338,7 @@ export class AddonModDataEntryPage implements OnDestroy {
|
|||
return Promise.resolve(promise).then(() => {
|
||||
if (this.entryId > 0) {
|
||||
// Online entry, we need to fetch the the rating info.
|
||||
return this.dataProvider.getEntry(this.data.id, this.entryId).then((entry) => {
|
||||
return this.dataProvider.getEntry(this.data.id, this.entryId, {cmId: this.module.id}).then((entry) => {
|
||||
this.ratingInfo = entry.ratinginfo;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
|
@ -23,6 +23,7 @@ import { AddonModDataOfflineProvider } from './offline';
|
|||
import { AddonModDataFieldsDelegate } from './fields-delegate';
|
||||
import { CoreRatingInfo } from '@core/rating/providers/rating';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Database entry (online or offline).
|
||||
|
@ -482,49 +483,34 @@ export class AddonModDataProvider {
|
|||
* Performs the whole fetch of the entries in the database.
|
||||
*
|
||||
* @param dataId Data ID.
|
||||
* @param groupId Group ID.
|
||||
* @param sort Sort the records by this field id. See AddonModDataProvider#getEntries for more info.
|
||||
* @param order The direction of the sorting. See AddonModDataProvider#getEntries for more info.
|
||||
* @param perPage Records per page to fetch. It has to match with the prefetch.
|
||||
* Default on AddonModDataProvider.PER_PAGE.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
fetchAllEntries(dataId: number, groupId: number = 0, sort: string = '0', order: string = 'DESC',
|
||||
perPage: number = AddonModDataProvider.PER_PAGE, forceCache: boolean = false, ignoreCache: boolean = false,
|
||||
siteId?: string): Promise<AddonModDataEntry[]> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
fetchAllEntries(dataId: number, options: AddonModDataGetEntriesOptions = {}): Promise<AddonModDataEntry[]> {
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
options.page = 0;
|
||||
|
||||
return this.fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, [], 0, siteId);
|
||||
return this.fetchEntriesRecursive(dataId, [], options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursive call on fetch all entries.
|
||||
*
|
||||
* @param dataId Data ID.
|
||||
* @param groupId Group ID.
|
||||
* @param sort Sort the records by this field id. See AddonModDataProvider#getEntries for more info.
|
||||
* @param order The direction of the sorting. See AddonModDataProvider#getEntries for more info.
|
||||
* @param perPage Records per page to fetch. It has to match with the prefetch.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param entries Entries already fetch (just to concatenate them).
|
||||
* @param page Page of records to return.
|
||||
* @param siteId Site ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected fetchEntriesRecursive(dataId: number, groupId: number, sort: string, order: string, perPage: number,
|
||||
forceCache: boolean, ignoreCache: boolean, entries: any, page: number, siteId: string): Promise<AddonModDataEntry[]> {
|
||||
return this.getEntries(dataId, groupId, sort, order, page, perPage, forceCache, ignoreCache, siteId)
|
||||
.then((result) => {
|
||||
protected fetchEntriesRecursive(dataId: number, entries: any, options: AddonModDataGetEntriesOptions = {})
|
||||
: Promise<AddonModDataEntry[]> {
|
||||
return this.getEntries(dataId, options).then((result) => {
|
||||
entries = entries.concat(result.entries);
|
||||
|
||||
const canLoadMore = perPage > 0 && ((page + 1) * perPage) < result.totalcount;
|
||||
const canLoadMore = options.perPage > 0 && ((options.page + 1) * options.perPage) < result.totalcount;
|
||||
if (canLoadMore) {
|
||||
return this.fetchEntriesRecursive(dataId, groupId, sort, order, perPage, forceCache, ignoreCache, entries, page + 1,
|
||||
siteId);
|
||||
options.page++;
|
||||
|
||||
return this.fetchEntriesRecursive(dataId, entries, options);
|
||||
}
|
||||
|
||||
return entries;
|
||||
|
@ -557,23 +543,21 @@ export class AddonModDataProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the data is retrieved.
|
||||
*/
|
||||
protected getDatabaseByKey(courseId: number, key: string, value: any, siteId?: string, forceCache: boolean = false):
|
||||
protected getDatabaseByKey(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {}):
|
||||
Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getDatabaseDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
if (forceCache) {
|
||||
preSets['omitExpires'] = true;
|
||||
}
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getDatabaseDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModDataProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_data_get_databases_by_courses', params, preSets).then((response) => {
|
||||
if (response && response.databases) {
|
||||
|
@ -593,12 +577,11 @@ export class AddonModDataProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the data is retrieved.
|
||||
*/
|
||||
getDatabase(courseId: number, cmId: number, siteId?: string, forceCache: boolean = false): Promise<any> {
|
||||
return this.getDatabaseByKey(courseId, 'coursemodule', cmId, siteId, forceCache);
|
||||
getDatabase(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getDatabaseByKey(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -606,12 +589,11 @@ export class AddonModDataProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param id Data ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the data is retrieved.
|
||||
*/
|
||||
getDatabaseById(courseId: number, id: number, siteId?: string, forceCache: boolean = false): Promise<any> {
|
||||
return this.getDatabaseByKey(courseId, 'id', id, siteId, forceCache);
|
||||
getDatabaseById(courseId: number, id: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getDatabaseByKey(courseId, 'id', id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -639,31 +621,23 @@ export class AddonModDataProvider {
|
|||
* Get access information for a given database.
|
||||
*
|
||||
* @param dataId Data ID.
|
||||
* @param groupId Group ID.
|
||||
* @param offline True if it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache True if it should ignore cached data (it'll always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the database is retrieved.
|
||||
*/
|
||||
getDatabaseAccessInformation(dataId: number, groupId?: number, offline: boolean = false, ignoreCache: boolean = false,
|
||||
siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getDatabaseAccessInformation(dataId: number, options: AddonModDataAccessInfoOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
databaseid: dataId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getDatabaseAccessInformationDataCacheKey(dataId, groupId)
|
||||
};
|
||||
databaseid: dataId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getDatabaseAccessInformationDataCacheKey(dataId, options.groupId),
|
||||
component: AddonModDataProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
if (typeof groupId !== 'undefined') {
|
||||
params['groupid'] = groupId;
|
||||
}
|
||||
|
||||
if (offline) {
|
||||
preSets['omitExpires'] = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets['getFromCache'] = false;
|
||||
preSets['emergencyCache'] = false;
|
||||
if (typeof options.groupId !== 'undefined') {
|
||||
params['groupid'] = options.groupId;
|
||||
}
|
||||
|
||||
return site.read('mod_data_get_data_access_information', params, preSets);
|
||||
|
@ -674,48 +648,34 @@ export class AddonModDataProvider {
|
|||
* Get entries for a specific database and group.
|
||||
*
|
||||
* @param dataId Data ID.
|
||||
* @param groupId Group ID.
|
||||
* @param sort Sort the records by this field id, reserved ids are:
|
||||
* 0: timeadded
|
||||
* -1: firstname
|
||||
* -2: lastname
|
||||
* -3: approved
|
||||
* -4: timemodified.
|
||||
* Empty for using the default database setting.
|
||||
* @param order The direction of the sorting: 'ASC' or 'DESC'.
|
||||
* Empty for using the default database setting.
|
||||
* @param page Page of records to return.
|
||||
* @param perPage Records per page to return. Default on PER_PAGE.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it'll always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the database is retrieved.
|
||||
*/
|
||||
getEntries(dataId: number, groupId: number = 0, sort: string = '0', order: string = 'DESC', page: number = 0,
|
||||
perPage: number = AddonModDataProvider.PER_PAGE, forceCache: boolean = false, ignoreCache: boolean = false,
|
||||
siteId?: string): Promise<AddonModDataEntries> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getEntries(dataId: number, options: AddonModDataGetEntriesOptions = {}): Promise<AddonModDataEntries> {
|
||||
options.groupId = options.groupId || 0;
|
||||
options.sort = options.sort || 0;
|
||||
options.order || options.order || 'DESC';
|
||||
options.page = options.page || 0;
|
||||
options.perPage = options.perPage || AddonModDataProvider.PER_PAGE;
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
// Always use sort and order params to improve cache usage (entries are identified by params).
|
||||
const params = {
|
||||
databaseid: dataId,
|
||||
returncontents: 1,
|
||||
page: page,
|
||||
perpage: perPage,
|
||||
groupid: groupId,
|
||||
sort: sort,
|
||||
order: order
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getEntriesCacheKey(dataId, groupId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (forceCache) {
|
||||
preSets['omitExpires'] = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets['getFromCache'] = false;
|
||||
preSets['emergencyCache'] = false;
|
||||
}
|
||||
databaseid: dataId,
|
||||
returncontents: 1,
|
||||
page: options.page,
|
||||
perpage: options.perPage,
|
||||
groupid: options.groupId,
|
||||
sort: options.sort,
|
||||
order: options.order,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntriesCacheKey(dataId, options.groupId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModDataProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_data_get_entries', params, preSets).then((response) => {
|
||||
response.entries.forEach((entry) => {
|
||||
|
@ -753,26 +713,23 @@ export class AddonModDataProvider {
|
|||
*
|
||||
* @param dataId Data ID for caching purposes.
|
||||
* @param entryId Entry ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it'll always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the entry is retrieved.
|
||||
*/
|
||||
getEntry(dataId: number, entryId: number, ignoreCache: boolean = false, siteId?: string):
|
||||
getEntry(dataId: number, entryId: number, options: CoreCourseCommonModWSOptions = {}):
|
||||
Promise<{entry: AddonModDataEntry, ratinginfo: CoreRatingInfo}> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
entryid: entryId,
|
||||
returncontents: 1
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getEntryCacheKey(dataId, entryId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets['getFromCache'] = false;
|
||||
preSets['emergencyCache'] = false;
|
||||
}
|
||||
entryid: entryId,
|
||||
returncontents: 1,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntryCacheKey(dataId, entryId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModDataProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_data_get_entry', params, preSets).then((response) => {
|
||||
response.entry.contents = this.utils.arrayToObject(response.entry.contents, 'fieldid');
|
||||
|
@ -797,27 +754,21 @@ export class AddonModDataProvider {
|
|||
* Get the list of configured fields for the given database.
|
||||
*
|
||||
* @param dataId Data ID.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the fields are retrieved.
|
||||
*/
|
||||
getFields(dataId: number, forceCache: boolean = false, ignoreCache: boolean = false, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getFields(dataId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
databaseid: dataId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getFieldsCacheKey(dataId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
if (forceCache) {
|
||||
preSets['omitExpires'] = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets['getFromCache'] = false;
|
||||
preSets['emergencyCache'] = false;
|
||||
}
|
||||
databaseid: dataId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getFieldsCacheKey(dataId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModDataProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_data_get_fields', params, preSets).then((response) => {
|
||||
if (response && response.fields) {
|
||||
|
@ -993,46 +944,45 @@ export class AddonModDataProvider {
|
|||
* Performs search over a database.
|
||||
*
|
||||
* @param dataId The data instance id.
|
||||
* @param groupId Group id, 0 means that the function will determine the user group.
|
||||
* @param search Search text. It will be used if advSearch is not defined.
|
||||
* @param advSearch Advanced search data.
|
||||
* @param sort Sort by this field.
|
||||
* @param order The direction of the sorting.
|
||||
* @param page Page of records to return.
|
||||
* @param perPage Records per page to return. Default on AddonModDataProvider.PER_PAGE.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the action is done.
|
||||
*/
|
||||
searchEntries(dataId: number, groupId: number = 0, search?: string, advSearch?: any, sort?: string, order?: string,
|
||||
page: number = 0, perPage: number = AddonModDataProvider.PER_PAGE, siteId?: string): Promise<AddonModDataEntries> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
searchEntries(dataId: number, options?: AddonModDataSearchEntriesOptions): Promise<AddonModDataEntries> {
|
||||
options.groupId = options.groupId || 0;
|
||||
options.sort = options.sort || 0;
|
||||
options.order || options.order || 'DESC';
|
||||
options.page = options.page || 0;
|
||||
options.perPage = options.perPage || AddonModDataProvider.PER_PAGE;
|
||||
options.readingStrategy = options.readingStrategy || CoreSitesReadingStrategy.PreferNetwork;
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
databaseid: dataId,
|
||||
groupid: groupId,
|
||||
returncontents: 1,
|
||||
page: page,
|
||||
perpage: perPage
|
||||
},
|
||||
preSets = {
|
||||
getFromCache: false,
|
||||
saveToCache: true,
|
||||
emergencyCache: true
|
||||
};
|
||||
databaseid: dataId,
|
||||
groupid: options.groupId,
|
||||
returncontents: 1,
|
||||
page: options.page,
|
||||
perpage: options.perPage,
|
||||
};
|
||||
const preSets = {
|
||||
component: AddonModDataProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
if (typeof sort != 'undefined') {
|
||||
params['sort'] = sort;
|
||||
if (typeof options.sort != 'undefined') {
|
||||
params['sort'] = options.sort;
|
||||
}
|
||||
|
||||
if (typeof order !== 'undefined') {
|
||||
params['order'] = order;
|
||||
if (typeof options.order !== 'undefined') {
|
||||
params['order'] = options.order;
|
||||
}
|
||||
|
||||
if (typeof search !== 'undefined') {
|
||||
params['search'] = search;
|
||||
if (typeof options.search !== 'undefined') {
|
||||
params['search'] = options.search;
|
||||
}
|
||||
|
||||
if (typeof advSearch !== 'undefined') {
|
||||
params['advsearch'] = advSearch;
|
||||
if (typeof options.advSearch !== 'undefined') {
|
||||
params['advsearch'] = options.advSearch;
|
||||
}
|
||||
|
||||
return site.read('mod_data_search_entries', params, preSets).then((response) => {
|
||||
|
@ -1045,3 +995,34 @@ export class AddonModDataProvider {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to pass to get access info.
|
||||
*/
|
||||
export type AddonModDataAccessInfoOptions = CoreCourseCommonModWSOptions & {
|
||||
groupId?: number; // Group Id.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to get entries.
|
||||
*/
|
||||
export type AddonModDataGetEntriesOptions = CoreCourseCommonModWSOptions & {
|
||||
groupId?: number; // Group Id.
|
||||
sort?: number; // Sort the records by this field id, defaults to 0. Reserved ids are:
|
||||
// 0: timeadded
|
||||
// -1: firstname
|
||||
// -2: lastname
|
||||
// -3: approved
|
||||
// -4: timemodified
|
||||
order?: string; // The direction of the sorting: 'ASC' or 'DESC'. Defaults to 'DESC'.
|
||||
page?: number; // Page of records to return. Defaults to 0.
|
||||
perPage?: number; // Records per page to return. Defaults to AddonModDataProvider.PER_PAGE.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to search entries.
|
||||
*/
|
||||
export type AddonModDataSearchEntriesOptions = AddonModDataGetEntriesOptions & {
|
||||
search?: string; // Search text. It will be used if advSearch is not defined.
|
||||
advSearch?: any; // Advanced search data.
|
||||
};
|
||||
|
|
|
@ -23,7 +23,9 @@ import { CoreCourseProvider } from '@core/course/providers/course';
|
|||
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
||||
import { AddonModDataFieldsDelegate } from './fields-delegate';
|
||||
import { AddonModDataOfflineProvider, AddonModDataOfflineAction } from './offline';
|
||||
import { AddonModDataProvider, AddonModDataEntry, AddonModDataEntryFields, AddonModDataEntries } from './data';
|
||||
import {
|
||||
AddonModDataProvider, AddonModDataEntry, AddonModDataEntryFields, AddonModDataEntries, AddonModDataSearchEntriesOptions
|
||||
} from './data';
|
||||
import { CoreRatingInfo } from '@core/rating/providers/rating';
|
||||
import { CoreRatingOfflineProvider } from '@core/rating/providers/offline';
|
||||
|
||||
|
@ -210,33 +212,21 @@ export class AddonModDataHelperProvider {
|
|||
*
|
||||
* @param data Database object.
|
||||
* @param fields The fields that define the contents.
|
||||
* @param groupId Group ID.
|
||||
* @param search Search text. It will be used if advSearch is not defined.
|
||||
* @param advSearch Advanced search data.
|
||||
* @param sort Sort the records by this field id, reserved ids are:
|
||||
* 0: timeadded
|
||||
* -1: firstname
|
||||
* -2: lastname
|
||||
* -3: approved
|
||||
* -4: timemodified.
|
||||
* Empty for using the default database setting.
|
||||
* @param order The direction of the sorting: 'ASC' or 'DESC'.
|
||||
* Empty for using the default database setting.
|
||||
* @param page Page of records to return.
|
||||
* @param perPage Records per page to return. Default on PER_PAGE.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the database is retrieved.
|
||||
*/
|
||||
fetchEntries(data: any, fields: any[], groupId: number = 0, search?: string, advSearch?: any[], sort: string = '0',
|
||||
order: string = 'DESC', page: number = 0, perPage: number = AddonModDataProvider.PER_PAGE, siteId?: string):
|
||||
Promise<AddonModDataEntries> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
fetchEntries(data: any, fields: any[], options: AddonModDataSearchEntriesOptions = {}): Promise<AddonModDataEntries> {
|
||||
options.groupId = options.groupId || 0;
|
||||
options.page = options.page || 0;
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const offlineActions = {};
|
||||
const result: AddonModDataEntries = {
|
||||
entries: [],
|
||||
totalcount: 0,
|
||||
offlineEntries: []
|
||||
};
|
||||
options.siteId = site.id;
|
||||
|
||||
const offlinePromise = this.dataOffline.getDatabaseEntries(data.id, site.id).then((actions) => {
|
||||
result.hasOfflineActions = !!actions.length;
|
||||
|
@ -248,8 +238,8 @@ export class AddonModDataHelperProvider {
|
|||
offlineActions[action.entryid].push(action);
|
||||
|
||||
// We only display new entries in the first page when not searching.
|
||||
if (action.action == 'add' && page == 0 && !search && !advSearch &&
|
||||
(!action.groupid || !groupId || action.groupid == groupId)) {
|
||||
if (action.action == 'add' && options.page == 0 && !options.search && !options.advSearch &&
|
||||
(!action.groupid || !options.groupId || action.groupid == options.groupId)) {
|
||||
result.offlineEntries.push({
|
||||
id: action.entryid,
|
||||
canmanageentry: true,
|
||||
|
@ -275,16 +265,14 @@ export class AddonModDataHelperProvider {
|
|||
});
|
||||
|
||||
let fetchPromise: Promise<void>;
|
||||
if (search || advSearch) {
|
||||
fetchPromise = this.dataProvider.searchEntries(data.id, groupId, search, advSearch, sort, order, page, perPage,
|
||||
site.id).then((fetchResult) => {
|
||||
if (options.search || options.advSearch) {
|
||||
fetchPromise = this.dataProvider.searchEntries(data.id, options).then((fetchResult) => {
|
||||
result.entries = fetchResult.entries;
|
||||
result.totalcount = fetchResult.totalcount;
|
||||
result.maxcount = fetchResult.maxcount;
|
||||
});
|
||||
} else {
|
||||
fetchPromise = this.dataProvider.getEntries(data.id, groupId, sort, order, page, perPage, false, false, site.id)
|
||||
.then((fetchResult) => {
|
||||
fetchPromise = this.dataProvider.getEntries(data.id, options).then((fetchResult) => {
|
||||
result.entries = fetchResult.entries;
|
||||
result.totalcount = fetchResult.totalcount;
|
||||
});
|
||||
|
@ -324,7 +312,7 @@ export class AddonModDataHelperProvider {
|
|||
|
||||
if (entryId > 0) {
|
||||
// Online entry.
|
||||
promise = this.dataProvider.getEntry(data.id, entryId, false, site.id);
|
||||
promise = this.dataProvider.getEntry(data.id, entryId, {cmId: data.coursemodule, siteId: site.id});
|
||||
} else {
|
||||
// Offline entry or new entry.
|
||||
promise = Promise.resolve({
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
|
@ -65,16 +65,17 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
*
|
||||
* @param dataId Database Id.
|
||||
* @param groups Array of groups in the activity.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID.
|
||||
* @param options Other options.
|
||||
* @return All unique entries.
|
||||
*/
|
||||
protected getAllUniqueEntries(dataId: number, groups: any[], forceCache: boolean = false, ignoreCache: boolean = false,
|
||||
siteId?: string): Promise<AddonModDataEntry[]> {
|
||||
protected getAllUniqueEntries(dataId: number, groups: any[], options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModDataEntry[]> {
|
||||
|
||||
const promises = groups.map((group) => {
|
||||
return this.dataProvider.fetchAllEntries(dataId, group.id, undefined, undefined, undefined, forceCache, ignoreCache,
|
||||
siteId);
|
||||
return this.dataProvider.fetchAllEntries(dataId, {
|
||||
groupId: group.id,
|
||||
...options, // Include all options.
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(promises).then((responses) => {
|
||||
|
@ -96,31 +97,29 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
* @param module Module to get the files.
|
||||
* @param courseId Course ID the module belongs to.
|
||||
* @param omitFail True to always return even if fails. Default false.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the info fetched.
|
||||
*/
|
||||
protected getDatabaseInfoHelper(module: any, courseId: number, omitFail: boolean = false, forceCache: boolean = false,
|
||||
ignoreCache: boolean = false, siteId?: string): Promise<any> {
|
||||
protected getDatabaseInfoHelper(module: any, courseId: number, omitFail: boolean, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<any> {
|
||||
let database,
|
||||
groups = [],
|
||||
entries = [],
|
||||
files = [];
|
||||
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.dataProvider.getDatabase(courseId, module.id, siteId, forceCache).then((data) => {
|
||||
return this.dataProvider.getDatabase(courseId, module.id, options).then((data) => {
|
||||
files = this.getIntroFilesFromInstance(module, data);
|
||||
database = data;
|
||||
|
||||
return this.groupsProvider.getActivityGroupInfo(module.id, false, undefined, siteId).then((groupInfo) => {
|
||||
return this.groupsProvider.getActivityGroupInfo(module.id, false, undefined, options.siteId).then((groupInfo) => {
|
||||
if (!groupInfo.groups || groupInfo.groups.length == 0) {
|
||||
groupInfo.groups = [{id: 0}];
|
||||
}
|
||||
groups = groupInfo.groups;
|
||||
|
||||
return this.getAllUniqueEntries(database.id, groups, forceCache, ignoreCache, siteId);
|
||||
return this.getAllUniqueEntries(database.id, groups, options);
|
||||
});
|
||||
}).then((uniqueEntries) => {
|
||||
entries = uniqueEntries;
|
||||
|
@ -229,8 +228,10 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
* @return Promise resolved with true if downloadable, resolved with false otherwise.
|
||||
*/
|
||||
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
||||
return this.dataProvider.getDatabase(courseId, module.id, undefined, true).then((database) => {
|
||||
return this.dataProvider.getDatabaseAccessInformation(database.id).then((accessData) => {
|
||||
return this.dataProvider.getDatabase(courseId, module.id, {
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
}).then((database) => {
|
||||
return this.dataProvider.getDatabaseAccessInformation(database.id, {cmId: module.id}).then((accessData) => {
|
||||
// Check if database is restricted by time.
|
||||
if (!accessData.timeavailable) {
|
||||
const time = this.timeUtils.timestamp();
|
||||
|
@ -281,23 +282,31 @@ export class AddonModDataPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected prefetchDatabase(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
const options = {
|
||||
cmId: module.id,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
return this.getDatabaseInfoHelper(module, courseId, false, false, true, siteId).then((info) => {
|
||||
return this.getDatabaseInfoHelper(module, courseId, false, options).then((info) => {
|
||||
// Prefetch the database data.
|
||||
const database = info.database,
|
||||
commentsEnabled = !this.commentsProvider.areCommentsDisabledInSite(),
|
||||
promises = [];
|
||||
|
||||
promises.push(this.dataProvider.getFields(database.id, false, true, siteId));
|
||||
promises.push(this.dataProvider.getFields(database.id, options));
|
||||
|
||||
promises.push(this.filepoolProvider.addFilesToQueue(siteId, info.files, this.component, module.id));
|
||||
|
||||
info.groups.forEach((group) => {
|
||||
promises.push(this.dataProvider.getDatabaseAccessInformation(database.id, group.id, false, true, siteId));
|
||||
promises.push(this.dataProvider.getDatabaseAccessInformation(database.id, {
|
||||
groupId: group.id,
|
||||
...options, // Include all options.
|
||||
}));
|
||||
});
|
||||
|
||||
info.entries.forEach((entry) => {
|
||||
promises.push(this.dataProvider.getEntry(database.id, entry.id, true, siteId));
|
||||
promises.push(this.dataProvider.getEntry(database.id, entry.id, options));
|
||||
|
||||
if (commentsEnabled && database.comments) {
|
||||
promises.push(this.commentsProvider.getComments('module', database.coursemodule, 'mod_data', entry.id,
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncBaseProvider } from '@classes/base-sync';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
|
@ -188,7 +188,7 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
|
|||
courseId = offlineActions[0].courseid;
|
||||
|
||||
// Send the answers.
|
||||
return this.dataProvider.getDatabaseById(courseId, dataId, siteId).then((database) => {
|
||||
return this.dataProvider.getDatabaseById(courseId, dataId, {siteId}).then((database) => {
|
||||
data = database;
|
||||
|
||||
const offlineEntries = {};
|
||||
|
@ -233,18 +233,23 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
|
|||
* @return Promise resolved if success, rejected otherwise.
|
||||
*/
|
||||
protected syncEntry(data: any, entryActions: AddonModDataOfflineAction[], result: any, siteId?: string): Promise<any> {
|
||||
let discardError,
|
||||
timePromise,
|
||||
entryId = entryActions[0].entryid,
|
||||
offlineId,
|
||||
deleted = false;
|
||||
let discardError;
|
||||
let timePromise;
|
||||
let entryId = entryActions[0].entryid;
|
||||
let offlineId;
|
||||
let deleted = false;
|
||||
|
||||
const editAction = entryActions.find((action) => action.action == 'add' || action.action == 'edit');
|
||||
const approveAction = entryActions.find((action) => action.action == 'approve' || action.action == 'disapprove');
|
||||
const deleteAction = entryActions.find((action) => action.action == 'delete');
|
||||
const options = {
|
||||
cmId: data.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
if (entryId > 0) {
|
||||
timePromise = this.dataProvider.getEntry(data.id, entryId, true, siteId).then((entry) => {
|
||||
timePromise = this.dataProvider.getEntry(data.id, entryId, options).then((entry) => {
|
||||
return entry.entry.timemodified;
|
||||
}).catch((error) => {
|
||||
if (error && this.utils.isWebServiceError(error)) {
|
||||
|
@ -402,7 +407,7 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider {
|
|||
const promises = [];
|
||||
|
||||
results.forEach((result) => {
|
||||
promises.push(this.dataProvider.getDatabase(result.itemSet.courseId, result.itemSet.instanceId, siteId)
|
||||
promises.push(this.dataProvider.getDatabase(result.itemSet.courseId, result.itemSet.instanceId, {siteId})
|
||||
.then((data) => {
|
||||
const promises = [];
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
|||
}
|
||||
}).then(() => {
|
||||
// Check if there are answers stored in offline.
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(this.feedback.id);
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(this.feedback.id, {cmId: this.module.id});
|
||||
}).then((accessData) => {
|
||||
this.access = accessData;
|
||||
this.showTabs = (accessData.canviewreports || accessData.canviewanalysis) && !accessData.isempty;
|
||||
|
@ -220,7 +220,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
|||
const promises = [];
|
||||
|
||||
if (accessData.cancomplete && accessData.cansubmit && accessData.isopen) {
|
||||
promises.push(this.feedbackProvider.getResumePage(this.feedback.id).then((goPage) => {
|
||||
promises.push(this.feedbackProvider.getResumePage(this.feedback.id, {cmId: this.module.id}).then((goPage) => {
|
||||
this.goPage = goPage > 0 ? goPage : false;
|
||||
}));
|
||||
}
|
||||
|
@ -421,7 +421,7 @@ export class AddonModFeedbackIndexComponent extends CoreCourseModuleMainActivity
|
|||
setGroup(groupId: number): Promise<any> {
|
||||
this.group = groupId;
|
||||
|
||||
return this.feedbackProvider.getAnalysis(this.feedback.id, groupId).then((analysis) => {
|
||||
return this.feedbackProvider.getAnalysis(this.feedback.id, {groupId, cmId: this.module.id}).then((analysis) => {
|
||||
this.feedback.completedCount = analysis.completedcount;
|
||||
this.feedback.itemsCount = analysis.itemscount;
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ export class AddonModFeedbackAttemptPage {
|
|||
return this.feedbackProvider.getFeedbackById(this.courseId, this.feedbackId).then((feedback) => {
|
||||
this.feedback = feedback;
|
||||
|
||||
return this.feedbackProvider.getItems(this.feedbackId);
|
||||
return this.feedbackProvider.getItems(this.feedbackId, {cmId: this.feedback.coursemodule});
|
||||
}).then((items) => {
|
||||
// Add responses and format items.
|
||||
this.items = items.items.map((item) => {
|
||||
|
|
|
@ -27,7 +27,7 @@ import { CoreCourseProvider } from '@core/course/providers/course';
|
|||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
||||
import { CoreLoginHelperProvider } from '@core/login/providers/helper';
|
||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
|
||||
/**
|
||||
* Page that displays feedback form.
|
||||
|
@ -141,6 +141,10 @@ export class AddonModFeedbackFormPage implements OnDestroy {
|
|||
*/
|
||||
protected fetchData(): Promise<any> {
|
||||
this.offline = !this.appProvider.isOnline();
|
||||
const options = {
|
||||
cmId: this.module.id,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
|
||||
return this.feedbackProvider.getFeedback(this.courseId, this.module.id).then((feedbackData) => {
|
||||
this.feedback = feedbackData;
|
||||
|
@ -151,8 +155,7 @@ export class AddonModFeedbackFormPage implements OnDestroy {
|
|||
}).then((accessData) => {
|
||||
if (!this.preview && accessData.cansubmit && !accessData.isempty) {
|
||||
return typeof this.currentPage == 'undefined' ?
|
||||
this.feedbackProvider.getResumePage(this.feedback.id, this.offline, true) :
|
||||
Promise.resolve(this.currentPage);
|
||||
this.feedbackProvider.getResumePage(this.feedback.id, options) : Promise.resolve(this.currentPage);
|
||||
} else {
|
||||
this.preview = true;
|
||||
|
||||
|
@ -162,8 +165,9 @@ export class AddonModFeedbackFormPage implements OnDestroy {
|
|||
if (!this.offline && !this.utils.isWebServiceError(error)) {
|
||||
// If it fails, go offline.
|
||||
this.offline = true;
|
||||
options.readingStrategy = CoreSitesReadingStrategy.PreferCache;
|
||||
|
||||
return this.feedbackProvider.getResumePage(this.feedback.id, true);
|
||||
return this.feedbackProvider.getResumePage(this.feedback.id, options);
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
|
@ -186,12 +190,18 @@ export class AddonModFeedbackFormPage implements OnDestroy {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected fetchAccessData(): Promise<any> {
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(this.feedback.id, this.offline, true).catch((error) => {
|
||||
const options = {
|
||||
cmId: this.module.id,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(this.feedback.id, options).catch((error) => {
|
||||
if (!this.offline && !this.utils.isWebServiceError(error)) {
|
||||
// If it fails, go offline.
|
||||
this.offline = true;
|
||||
options.readingStrategy = CoreSitesReadingStrategy.PreferCache;
|
||||
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(this.feedback.id, true);
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(this.feedback.id, options);
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
|
@ -203,20 +213,25 @@ export class AddonModFeedbackFormPage implements OnDestroy {
|
|||
}
|
||||
|
||||
protected fetchFeedbackPageData(page: number = 0): Promise<void> {
|
||||
const options = {
|
||||
cmId: this.module.id,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
let promise;
|
||||
this.items = [];
|
||||
|
||||
if (this.preview) {
|
||||
promise = this.feedbackProvider.getItems(this.feedback.id);
|
||||
promise = this.feedbackProvider.getItems(this.feedback.id, {cmId: this.module.id});
|
||||
} else {
|
||||
this.currentPage = page;
|
||||
|
||||
promise = this.feedbackProvider.getPageItemsWithValues(this.feedback.id, page, this.offline, true).catch((error) => {
|
||||
promise = this.feedbackProvider.getPageItemsWithValues(this.feedback.id, page, options).catch((error) => {
|
||||
if (!this.offline && !this.utils.isWebServiceError(error)) {
|
||||
// If it fails, go offline.
|
||||
this.offline = true;
|
||||
options.readingStrategy = CoreSitesReadingStrategy.PreferCache;
|
||||
|
||||
return this.feedbackProvider.getPageItemsWithValues(this.feedback.id, page, true);
|
||||
return this.feedbackProvider.getPageItemsWithValues(this.feedback.id, page, options);
|
||||
}
|
||||
|
||||
return Promise.reject(error);
|
||||
|
@ -262,8 +277,12 @@ export class AddonModFeedbackFormPage implements OnDestroy {
|
|||
return this.feedbackSync.syncFeedback(this.feedback.id).catch(() => {
|
||||
// Ignore errors.
|
||||
}).then(() => {
|
||||
return this.feedbackProvider.processPage(this.feedback.id, this.currentPage, responses, goPrevious, formHasErrors,
|
||||
this.courseId).then((response) => {
|
||||
return this.feedbackProvider.processPage(this.feedback.id, this.currentPage, responses, {
|
||||
goPrevious,
|
||||
formHasErrors,
|
||||
courseId: this.courseId,
|
||||
cmId: this.module.id,
|
||||
}).then((response) => {
|
||||
const jumpTo = parseInt(response.jumpto, 10);
|
||||
|
||||
if (response.completed) {
|
||||
|
|
|
@ -111,7 +111,11 @@ export class AddonModFeedbackNonRespondentsPage {
|
|||
this.feedbackLoaded = false;
|
||||
}
|
||||
|
||||
return this.feedbackHelper.getNonRespondents(this.feedbackId, this.selectedGroup, this.page).then((response) => {
|
||||
return this.feedbackHelper.getNonRespondents(this.feedbackId, {
|
||||
groupId: this.selectedGroup,
|
||||
page: this.page,
|
||||
cmId: this.moduleId,
|
||||
}).then((response) => {
|
||||
this.total = response.total;
|
||||
|
||||
if (this.users.length < response.total) {
|
||||
|
|
|
@ -134,7 +134,11 @@ export class AddonModFeedbackRespondentsPage {
|
|||
this.feedbackLoaded = false;
|
||||
}
|
||||
|
||||
return this.feedbackHelper.getResponsesAnalysis(this.feedbackId, this.selectedGroup, this.page).then((responses) => {
|
||||
return this.feedbackHelper.getResponsesAnalysis(this.feedbackId, {
|
||||
groupId: this.selectedGroup,
|
||||
page: this.page,
|
||||
cmId: this.moduleId,
|
||||
}).then((responses) => {
|
||||
this.responses.total = responses.totalattempts;
|
||||
this.anonResponses.total = responses.totalanonattempts;
|
||||
|
||||
|
|
|
@ -14,13 +14,14 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { AddonModFeedbackOfflineProvider } from './offline';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Service that provides some features for feedbacks.
|
||||
|
@ -35,7 +36,7 @@ export class AddonModFeedbackProvider {
|
|||
static MULTICHOICE_HIDENOSELECT = 'h';
|
||||
static MULTICHOICERATED_VALUE_SEP = '####';
|
||||
|
||||
protected ROOT_CACHE_KEY = this.ROOT_CACHE_KEY + '';
|
||||
protected ROOT_CACHE_KEY = '';
|
||||
protected logger;
|
||||
|
||||
constructor(logger: CoreLoggerProvider, private sitesProvider: CoreSitesProvider, private utils: CoreUtilsProvider,
|
||||
|
@ -130,13 +131,11 @@ export class AddonModFeedbackProvider {
|
|||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param items Item to fill the value.
|
||||
* @param offline True if it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID.
|
||||
* @param options Other options.
|
||||
* @return Resolved with values when done.
|
||||
*/
|
||||
protected fillValues(feedbackId: number, items: any[], offline: boolean, ignoreCache: boolean, siteId: string): Promise<any> {
|
||||
return this.getCurrentValues(feedbackId, offline, ignoreCache, siteId).then((valuesArray) => {
|
||||
protected fillValues(feedbackId: number, items: any[], options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.getCurrentValues(feedbackId, options).then((valuesArray) => {
|
||||
const values = {};
|
||||
|
||||
valuesArray.forEach((value) => {
|
||||
|
@ -152,7 +151,7 @@ export class AddonModFeedbackProvider {
|
|||
// Ignore errors.
|
||||
}).then(() => {
|
||||
// Merge with offline data.
|
||||
return this.feedbackOffline.getFeedbackResponses(feedbackId, siteId).then((offlineValuesArray) => {
|
||||
return this.feedbackOffline.getFeedbackResponses(feedbackId, options.siteId).then((offlineValuesArray) => {
|
||||
const offlineValues = {};
|
||||
|
||||
// Merge all values into one array.
|
||||
|
@ -203,24 +202,22 @@ export class AddonModFeedbackProvider {
|
|||
* Returns all the feedback non respondents users.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param groupId Group id, 0 means that the function will determine the user group.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @param previous Only for recurrent use. Object with the previous fetched info.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getAllNonRespondents(feedbackId: number, groupId: number, ignoreCache?: boolean, siteId?: string, previous?: any)
|
||||
: Promise<any> {
|
||||
getAllNonRespondents(feedbackId: number, options: AddonModFeedbackGroupOptions = {}, previous?: any): Promise<any> {
|
||||
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (typeof previous == 'undefined') {
|
||||
previous = {
|
||||
page: 0,
|
||||
users: []
|
||||
};
|
||||
}
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
previous = previous || {
|
||||
page: 0,
|
||||
users: []
|
||||
};
|
||||
|
||||
return this.getNonRespondents(feedbackId, groupId, previous.page, ignoreCache, siteId).then((response) => {
|
||||
return this.getNonRespondents(feedbackId, {
|
||||
page: previous.page,
|
||||
...options, // Include all options.
|
||||
}).then((response) => {
|
||||
if (previous.users.length < response.total) {
|
||||
previous.users = previous.users.concat(response.users);
|
||||
}
|
||||
|
@ -229,7 +226,7 @@ export class AddonModFeedbackProvider {
|
|||
// Can load more.
|
||||
previous.page++;
|
||||
|
||||
return this.getAllNonRespondents(feedbackId, groupId, ignoreCache, siteId, previous);
|
||||
return this.getAllNonRespondents(feedbackId, options, previous);
|
||||
}
|
||||
previous.total = response.total;
|
||||
|
||||
|
@ -241,25 +238,23 @@ export class AddonModFeedbackProvider {
|
|||
* Returns all the feedback user responses.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param groupId Group id, 0 means that the function will determine the user group.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @param previous Only for recurrent use. Object with the previous fetched info.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getAllResponsesAnalysis(feedbackId: number, groupId: number, ignoreCache?: boolean, siteId?: string, previous?: any)
|
||||
: Promise<any> {
|
||||
getAllResponsesAnalysis(feedbackId: number, options: AddonModFeedbackGroupOptions = {}, previous?: any): Promise<any> {
|
||||
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (typeof previous == 'undefined') {
|
||||
previous = {
|
||||
page: 0,
|
||||
attempts: [],
|
||||
anonattempts: []
|
||||
};
|
||||
}
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
previous = previous || {
|
||||
page: 0,
|
||||
attempts: [],
|
||||
anonattempts: []
|
||||
};
|
||||
|
||||
return this.getResponsesAnalysis(feedbackId, groupId, previous.page, ignoreCache, siteId).then((responses) => {
|
||||
return this.getResponsesAnalysis(feedbackId, {
|
||||
page: previous.page,
|
||||
...options, // Include all options.
|
||||
}).then((responses) => {
|
||||
if (previous.anonattempts.length < responses.totalanonattempts) {
|
||||
previous.anonattempts = previous.anonattempts.concat(responses.anonattempts);
|
||||
}
|
||||
|
@ -272,7 +267,7 @@ export class AddonModFeedbackProvider {
|
|||
// Can load more.
|
||||
previous.page++;
|
||||
|
||||
return this.getAllResponsesAnalysis(feedbackId, groupId, ignoreCache, siteId, previous);
|
||||
return this.getAllResponsesAnalysis(feedbackId, options, previous);
|
||||
}
|
||||
|
||||
previous.totalattempts = responses.totalattempts;
|
||||
|
@ -286,27 +281,23 @@ export class AddonModFeedbackProvider {
|
|||
* Get analysis information for a given feedback.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param groupId Group ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the feedback is retrieved.
|
||||
*/
|
||||
getAnalysis(feedbackId: number, groupId?: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getAnalysis(feedbackId: number, options: AddonModFeedbackGroupOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAnalysisDataCacheKey(feedbackId, groupId)
|
||||
};
|
||||
feedbackid: feedbackId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAnalysisDataCacheKey(feedbackId, options.groupId),
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
if (groupId) {
|
||||
params['groupid'] = groupId;
|
||||
}
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
if (options.groupId) {
|
||||
params['groupid'] = options.groupId;
|
||||
}
|
||||
|
||||
return site.read('mod_feedback_get_analysis', params, preSets);
|
||||
|
@ -339,22 +330,23 @@ export class AddonModFeedbackProvider {
|
|||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param attemptId Attempt id to find.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @param previous Only for recurrent use. Object with the previous fetched info.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getAttempt(feedbackId: number, attemptId: number, ignoreCache?: boolean, siteId?: string, previous?: any): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
if (typeof previous == 'undefined') {
|
||||
previous = {
|
||||
page: 0,
|
||||
attemptsLoaded: 0,
|
||||
anonAttemptsLoaded: 0
|
||||
};
|
||||
}
|
||||
getAttempt(feedbackId: number, attemptId: number, options: CoreCourseCommonModWSOptions = {}, previous?: any): Promise<any> {
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
previous = previous || {
|
||||
page: 0,
|
||||
attemptsLoaded: 0,
|
||||
anonAttemptsLoaded: 0
|
||||
};
|
||||
|
||||
return this.getResponsesAnalysis(feedbackId, 0, previous.page, ignoreCache, siteId).then((responses) => {
|
||||
return this.getResponsesAnalysis(feedbackId, {
|
||||
page: previous.page,
|
||||
groupId: 0,
|
||||
...options, // Include all options.
|
||||
}).then((responses) => {
|
||||
let attempt;
|
||||
|
||||
attempt = responses.attempts.find((attempt) => {
|
||||
|
@ -385,7 +377,7 @@ export class AddonModFeedbackProvider {
|
|||
// Can load more. Check there.
|
||||
previous.page++;
|
||||
|
||||
return this.getAttempt(feedbackId, attemptId, ignoreCache, siteId, previous);
|
||||
return this.getAttempt(feedbackId, attemptId, options, previous);
|
||||
}
|
||||
|
||||
// Not found and all loaded. Reject.
|
||||
|
@ -407,23 +399,20 @@ export class AddonModFeedbackProvider {
|
|||
* Returns the temporary completion timemodified for the current user.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getCurrentCompletedTimeModified(feedbackId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getCurrentCompletedTimeModified(feedbackId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getCurrentCompletedTimeModifiedDataCacheKey(feedbackId)
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
feedbackid: feedbackId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getCurrentCompletedTimeModifiedDataCacheKey(feedbackId),
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_get_current_completed_tmp', params, preSets).then((response) => {
|
||||
if (response && typeof response.feedback != 'undefined' && typeof response.feedback.timemodified != 'undefined') {
|
||||
|
@ -452,26 +441,20 @@ export class AddonModFeedbackProvider {
|
|||
* Returns the temporary responses or responses of the last submission for the current user.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param offline True if it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache True if it should ignore cached data (it always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getCurrentValues(feedbackId: number, offline: boolean = false, ignoreCache: boolean = false, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getCurrentValues(feedbackId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getCurrentValuesDataCacheKey(feedbackId)
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets['omitExpires'] = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets['getFromCache'] = false;
|
||||
preSets['emergencyCache'] = false;
|
||||
}
|
||||
feedbackid: feedbackId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getCurrentValuesDataCacheKey(feedbackId),
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_get_unfinished_responses', params, preSets).then((response) => {
|
||||
if (!response || typeof response.responses == 'undefined') {
|
||||
|
@ -508,27 +491,20 @@ export class AddonModFeedbackProvider {
|
|||
* Get access information for a given feedback.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param offline True if it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache True if it should ignore cached data (it always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the feedback is retrieved.
|
||||
*/
|
||||
getFeedbackAccessInformation(feedbackId: number, offline: boolean = false, ignoreCache: boolean = false, siteId?: string):
|
||||
Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getFeedbackAccessInformation(feedbackId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getFeedbackAccessInformationDataCacheKey(feedbackId)
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets['omitExpires'] = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets['getFromCache'] = false;
|
||||
preSets['emergencyCache'] = false;
|
||||
}
|
||||
feedbackid: feedbackId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getFeedbackAccessInformationDataCacheKey(feedbackId),
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_get_feedback_access_information', params, preSets);
|
||||
});
|
||||
|
@ -570,29 +546,22 @@ export class AddonModFeedbackProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the feedback is retrieved.
|
||||
*/
|
||||
protected getFeedbackDataByKey(courseId: number, key: string, value: any, siteId?: string, forceCache?: boolean,
|
||||
ignoreCache?: boolean): Promise<any> {
|
||||
protected getFeedbackDataByKey(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<any> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getFeedbackCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
if (forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getFeedbackCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_get_feedbacks_by_courses', params, preSets).then((response) => {
|
||||
if (response && response.feedbacks) {
|
||||
|
@ -614,13 +583,11 @@ export class AddonModFeedbackProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the feedback is retrieved.
|
||||
*/
|
||||
getFeedback(courseId: number, cmId: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean): Promise<any> {
|
||||
return this.getFeedbackDataByKey(courseId, 'coursemodule', cmId, siteId, forceCache, ignoreCache);
|
||||
getFeedback(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getFeedbackDataByKey(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -628,37 +595,32 @@ export class AddonModFeedbackProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param id Feedback ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param forceCache True to always get the value from cache, false otherwise. Default false.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the feedback is retrieved.
|
||||
*/
|
||||
getFeedbackById(courseId: number, id: number, siteId?: string, forceCache?: boolean, ignoreCache?: boolean): Promise<any> {
|
||||
return this.getFeedbackDataByKey(courseId, 'id', id, siteId, forceCache, ignoreCache);
|
||||
getFeedbackById(courseId: number, id: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getFeedbackDataByKey(courseId, 'id', id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the items (questions) in the given feedback.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getItems(feedbackId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getItems(feedbackId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getItemsDataCacheKey(feedbackId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
feedbackid: feedbackId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getItemsDataCacheKey(feedbackId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_get_items', params, preSets);
|
||||
});
|
||||
|
@ -678,29 +640,25 @@ export class AddonModFeedbackProvider {
|
|||
* Retrieves a list of students who didn't submit the feedback.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param groupId Group id, 0 means that the function will determine the user group.
|
||||
* @param page The page of records to return.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getNonRespondents(feedbackId: number, groupId: number = 0, page: number = 0, ignoreCache?: boolean, siteId?: string)
|
||||
: Promise<any> {
|
||||
getNonRespondents(feedbackId: number, options: AddonModFeedbackGroupPaginatedOptions = {}): Promise<any> {
|
||||
options.groupId = options.groupId || 0;
|
||||
options.page = options.page || 0;
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId,
|
||||
groupid: groupId,
|
||||
page: page
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getNonRespondentsDataCacheKey(feedbackId, groupId)
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
feedbackid: feedbackId,
|
||||
groupid: options.groupId,
|
||||
page: options.page,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getNonRespondentsDataCacheKey(feedbackId, options.groupId),
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_get_non_respondents', params, preSets);
|
||||
});
|
||||
|
@ -751,25 +709,22 @@ export class AddonModFeedbackProvider {
|
|||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param page The page to get.
|
||||
* @param offline True if it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getPageItemsWithValues(feedbackId: number, page: number, offline: boolean = false, ignoreCache: boolean = false,
|
||||
siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
getPageItemsWithValues(feedbackId: number, page: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.getPageItems(feedbackId, page, siteId).then((response) => {
|
||||
return this.fillValues(feedbackId, response.items, offline, ignoreCache, siteId).then((items) => {
|
||||
return this.getPageItems(feedbackId, page, options.siteId).then((response) => {
|
||||
return this.fillValues(feedbackId, response.items, options).then((items) => {
|
||||
response.items = items;
|
||||
|
||||
return response;
|
||||
});
|
||||
}).catch(() => {
|
||||
// If getPageItems fail we should calculate it using getItems.
|
||||
return this.getItems(feedbackId, false, siteId).then((response) => {
|
||||
return this.fillValues(feedbackId, response.items, offline, ignoreCache, siteId).then((items) => {
|
||||
return this.getItems(feedbackId, options).then((response) => {
|
||||
return this.fillValues(feedbackId, response.items, options).then((items) => {
|
||||
// Separate items by pages.
|
||||
let currentPage = 0;
|
||||
const previousPageItems = [];
|
||||
|
@ -819,11 +774,17 @@ export class AddonModFeedbackProvider {
|
|||
* @param feedbackId Feedback ID.
|
||||
* @param page Page where we want to jump.
|
||||
* @param changePage If page change is forward (1) or backward (-1).
|
||||
* @param siteId Site ID.
|
||||
* @param options Other options.
|
||||
* @return Page number where to jump. Or false if completed or first page.
|
||||
*/
|
||||
protected getPageJumpTo(feedbackId: number, page: number, changePage: number, siteId: string): Promise<number | false> {
|
||||
return this.getPageItemsWithValues(feedbackId, page, true, false, siteId).then((resp) => {
|
||||
protected getPageJumpTo(feedbackId: number, page: number, changePage: number, options: {cmId?: number, siteId?: string})
|
||||
: Promise<number | false> {
|
||||
|
||||
return this.getPageItemsWithValues(feedbackId, page, {
|
||||
cmId: options.cmId,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId: options.siteId,
|
||||
}).then((resp) => {
|
||||
// The page we are going has items.
|
||||
if (resp.items.length > 0) {
|
||||
return page;
|
||||
|
@ -831,7 +792,7 @@ export class AddonModFeedbackProvider {
|
|||
|
||||
// Check we can jump futher.
|
||||
if ((changePage == 1 && resp.hasnextpage) || (changePage == -1 && resp.hasprevpage)) {
|
||||
return this.getPageJumpTo(feedbackId, page + changePage, changePage, siteId);
|
||||
return this.getPageJumpTo(feedbackId, page + changePage, changePage, options);
|
||||
}
|
||||
|
||||
// Completed or first page.
|
||||
|
@ -843,27 +804,25 @@ export class AddonModFeedbackProvider {
|
|||
* Returns the feedback user responses.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param groupId Group id, 0 means that the function will determine the user group.
|
||||
* @param page The page of records to return.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getResponsesAnalysis(feedbackId: number, groupId: number, page: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId,
|
||||
groupid: groupId || 0,
|
||||
page: page || 0
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getResponsesAnalysisDataCacheKey(feedbackId, groupId)
|
||||
};
|
||||
getResponsesAnalysis(feedbackId: number, options: AddonModFeedbackGroupPaginatedOptions = {}): Promise<any> {
|
||||
options.groupId = options.groupId || 0;
|
||||
options.page = options.page || 0;
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId,
|
||||
groupid: options.groupId,
|
||||
page: options.page,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getResponsesAnalysisDataCacheKey(feedbackId, options.groupId),
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_get_responses_analysis', params, preSets);
|
||||
});
|
||||
|
@ -894,26 +853,20 @@ export class AddonModFeedbackProvider {
|
|||
* Gets the resume page information.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param offline True if it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache True if it should ignore cached data (it always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getResumePage(feedbackId: number, offline: boolean = false, ignoreCache: boolean = false, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getResumePage(feedbackId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getResumePageDataCacheKey(feedbackId)
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets['omitExpires'] = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets['getFromCache'] = false;
|
||||
preSets['emergencyCache'] = false;
|
||||
}
|
||||
feedbackid: feedbackId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getResumePageDataCacheKey(feedbackId),
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_feedback_launch_feedback', params, preSets).then((response) => {
|
||||
if (response && typeof response.gopage != 'undefined') {
|
||||
|
@ -964,7 +917,7 @@ export class AddonModFeedbackProvider {
|
|||
|
||||
/**
|
||||
* Invalidate the prefetched content.
|
||||
* To invalidate files, use AddonFeedbackProvider#invalidateFiles.
|
||||
* To invalidate files, use AddonModFeedbackProvider#invalidateFiles.
|
||||
*
|
||||
* @param moduleId The module ID.
|
||||
* @param courseId Course ID of the module.
|
||||
|
@ -976,7 +929,7 @@ export class AddonModFeedbackProvider {
|
|||
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.getFeedback(courseId, moduleId, siteId).then((feedback) => {
|
||||
promises.push(this.getFeedback(courseId, moduleId, {siteId}).then((feedback) => {
|
||||
const ps = [];
|
||||
|
||||
// Do not invalidate module data before getting module info, we need it!
|
||||
|
@ -1086,23 +1039,20 @@ export class AddonModFeedbackProvider {
|
|||
* Returns if feedback has been completed
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
isCompleted(feedbackId: number, ignoreCache?: boolean, siteId?: string): Promise<boolean> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
isCompleted(feedbackId: number, options: CoreCourseCommonModWSOptions = {}): Promise<boolean> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
feedbackid: feedbackId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getCompletedDataCacheKey(feedbackId)
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
feedbackid: feedbackId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getCompletedDataCacheKey(feedbackId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModFeedbackProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return this.utils.promiseWorks(site.read('mod_feedback_get_last_completed', params, preSets));
|
||||
});
|
||||
|
@ -1147,19 +1097,15 @@ export class AddonModFeedbackProvider {
|
|||
* @param feedbackId Feedback ID.
|
||||
* @param page The page being processed.
|
||||
* @param responses The data to be processed the key is the field name (usually type[index]_id).
|
||||
* @param goPrevious Whether we want to jump to previous page.
|
||||
* @param formHasErrors Whether the form we sent has required but empty fields (only used in offline).
|
||||
* @param courseId Course ID the feedback belongs to.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
processPage(feedbackId: number, page: number, responses: any, goPrevious: boolean, formHasErrors: boolean, courseId: number,
|
||||
siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
processPage(feedbackId: number, page: number, responses: any, options: AddonModFeedbackProcessPageOptions = {}): Promise<any> {
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
// Convenience function to store a message to be synchronized later.
|
||||
const storeOffline = (): Promise<any> => {
|
||||
return this.feedbackOffline.saveResponses(feedbackId, page, responses, courseId, siteId).then(() => {
|
||||
return this.feedbackOffline.saveResponses(feedbackId, page, responses, options.courseId, options.siteId).then(() => {
|
||||
// Simulate process_page response.
|
||||
const response = {
|
||||
jumpto: page,
|
||||
|
@ -1168,11 +1114,11 @@ export class AddonModFeedbackProvider {
|
|||
};
|
||||
let changePage = 0;
|
||||
|
||||
if (goPrevious) {
|
||||
if (options.goPrevious) {
|
||||
if (page > 0) {
|
||||
changePage = -1;
|
||||
}
|
||||
} else if (!formHasErrors) {
|
||||
} else if (!options.formHasErrors) {
|
||||
// We can only go next if it has no errors.
|
||||
changePage = 1;
|
||||
}
|
||||
|
@ -1181,7 +1127,11 @@ export class AddonModFeedbackProvider {
|
|||
return response;
|
||||
}
|
||||
|
||||
return this.getPageItemsWithValues(feedbackId, page, true, false, siteId).then((resp) => {
|
||||
return this.getPageItemsWithValues(feedbackId, page, {
|
||||
cmId: options.cmId,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId: options.siteId,
|
||||
}).then((resp) => {
|
||||
// Check completion.
|
||||
if (changePage == 1 && !resp.hasnextpage) {
|
||||
response.completed = true;
|
||||
|
@ -1189,7 +1139,7 @@ export class AddonModFeedbackProvider {
|
|||
return response;
|
||||
}
|
||||
|
||||
return this.getPageJumpTo(feedbackId, page + changePage, changePage, siteId).then((loadPage) => {
|
||||
return this.getPageJumpTo(feedbackId, page + changePage, changePage, options).then((loadPage) => {
|
||||
if (loadPage === false) {
|
||||
// Completed or first page.
|
||||
if (changePage == -1) {
|
||||
|
@ -1215,8 +1165,8 @@ export class AddonModFeedbackProvider {
|
|||
}
|
||||
|
||||
// If there's already a response to be sent to the server, discard it first.
|
||||
return this.feedbackOffline.deleteFeedbackPageResponses(feedbackId, page, siteId).then(() => {
|
||||
return this.processPageOnline(feedbackId, page, responses, goPrevious, siteId).catch((error) => {
|
||||
return this.feedbackOffline.deleteFeedbackPageResponses(feedbackId, page, options.siteId).then(() => {
|
||||
return this.processPageOnline(feedbackId, page, responses, options.goPrevious, options.siteId).catch((error) => {
|
||||
if (this.utils.isWebServiceError(error)) {
|
||||
// The WebService has thrown an error, this means that responses cannot be submitted.
|
||||
return Promise.reject(error);
|
||||
|
@ -1252,7 +1202,7 @@ export class AddonModFeedbackProvider {
|
|||
}).then((response) => {
|
||||
// Invalidate and update current values because they will change.
|
||||
return this.invalidateCurrentValuesData(feedbackId, site.getId()).then(() => {
|
||||
return this.getCurrentValues(feedbackId, false, false, site.getId());
|
||||
return this.getCurrentValues(feedbackId, {siteId: site.getId()});
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
}).then(() => {
|
||||
|
@ -1262,3 +1212,28 @@ export class AddonModFeedbackProvider {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Common options with a group ID.
|
||||
*/
|
||||
export type AddonModFeedbackGroupOptions = CoreCourseCommonModWSOptions & {
|
||||
groupId?: number; // Group id, 0 means that the function will determine the user group. Defaults to 0.
|
||||
};
|
||||
|
||||
/**
|
||||
* Common options with a group ID and page.
|
||||
*/
|
||||
export type AddonModFeedbackGroupPaginatedOptions = AddonModFeedbackGroupOptions & {
|
||||
page?: number; // The page of records to return. The page of records to return.
|
||||
};
|
||||
|
||||
/**
|
||||
* Common options with a group ID and page.
|
||||
*/
|
||||
export type AddonModFeedbackProcessPageOptions = {
|
||||
goPrevious?: boolean; // Whether we want to jump to previous page.
|
||||
formHasErrors?: boolean; // Whether the form we sent has required but empty fields (only used in offline).
|
||||
cmId?: number; // Module ID.
|
||||
courseId?: number; // Course ID the feedback belongs to.
|
||||
siteId?: string; // Site ID. If not defined, current site.;
|
||||
};
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NavController, ViewController } from 'ionic-angular';
|
||||
import { AddonModFeedbackProvider } from './feedback';
|
||||
import { AddonModFeedbackProvider, AddonModFeedbackGroupPaginatedOptions } from './feedback';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreContentLinksHelperProvider } from '@core/contentlinks/providers/helper';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
@ -86,12 +86,11 @@ export class AddonModFeedbackHelperProvider {
|
|||
* Retrieves a list of students who didn't submit the feedback with extra info.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param groupId Group id, 0 means that the function will determine the user group.
|
||||
* @param page The page of records to return.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getNonRespondents(feedbackId: number, groupId: number, page: number): Promise<any> {
|
||||
return this.feedbackProvider.getNonRespondents(feedbackId, groupId, page).then((responses) => {
|
||||
getNonRespondents(feedbackId: number, options: AddonModFeedbackGroupPaginatedOptions = {}): Promise<any> {
|
||||
return this.feedbackProvider.getNonRespondents(feedbackId, options).then((responses) => {
|
||||
return this.addImageProfileToAttempts(responses.users).then((users) => {
|
||||
responses.users = users;
|
||||
|
||||
|
@ -186,12 +185,11 @@ export class AddonModFeedbackHelperProvider {
|
|||
* Returns the feedback user responses with extra info.
|
||||
*
|
||||
* @param feedbackId Feedback ID.
|
||||
* @param groupId Group id, 0 means that the function will determine the user group.
|
||||
* @param page The page of records to return.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the info is retrieved.
|
||||
*/
|
||||
getResponsesAnalysis(feedbackId: number, groupId: number, page: number): Promise<any> {
|
||||
return this.feedbackProvider.getResponsesAnalysis(feedbackId, groupId, page).then((responses) => {
|
||||
getResponsesAnalysis(feedbackId: number, options: AddonModFeedbackGroupPaginatedOptions = {}): Promise<any> {
|
||||
return this.feedbackProvider.getResponsesAnalysis(feedbackId, options).then((responses) => {
|
||||
return this.addImageProfileToAttempts(responses.attempts).then((attempts) => {
|
||||
responses.attempts = attempts;
|
||||
|
||||
|
@ -227,7 +225,11 @@ export class AddonModFeedbackHelperProvider {
|
|||
return this.linkHelper.goInSite(navCtrl, 'AddonModFeedbackRespondentsPage', stateParams, siteId);
|
||||
}
|
||||
|
||||
return this.feedbackProvider.getAttempt(module.instance, params.showcompleted, true, siteId).then((attempt) => {
|
||||
return this.feedbackProvider.getAttempt(module.instance, params.showcompleted, {
|
||||
cmId: moduleId,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
}).then((attempt) => {
|
||||
stateParams = {
|
||||
moduleId: module.id,
|
||||
attempt: attempt,
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable, Injector } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
|
@ -143,7 +143,9 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
* @return Promise resolved with true if downloadable, resolved with false otherwise.
|
||||
*/
|
||||
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
||||
return this.feedbackProvider.getFeedback(courseId, module.id, undefined, true).then((feedback) => {
|
||||
return this.feedbackProvider.getFeedback(courseId, module.id, {
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
}).then((feedback) => {
|
||||
const now = this.timeUtils.timestamp();
|
||||
|
||||
// Check time first if available.
|
||||
|
@ -154,7 +156,7 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
return false;
|
||||
}
|
||||
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(feedback.id).then((accessData) => {
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(feedback.id, {cmId: module.id}).then((accessData) => {
|
||||
return accessData.isopen;
|
||||
});
|
||||
});
|
||||
|
@ -192,15 +194,24 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected prefetchFeedback(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
const commonOptions = {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
const modOptions = {
|
||||
cmId: module.id,
|
||||
...commonOptions, // Include all common options.
|
||||
};
|
||||
|
||||
// Prefetch the feedback data.
|
||||
return this.feedbackProvider.getFeedback(courseId, module.id, siteId, false, true).then((feedback) => {
|
||||
return this.feedbackProvider.getFeedback(courseId, module.id, commonOptions).then((feedback) => {
|
||||
let files = (feedback.pageaftersubmitfiles || []).concat(this.getIntroFilesFromInstance(module, feedback));
|
||||
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(feedback.id, false, true, siteId).then((accessData) => {
|
||||
return this.feedbackProvider.getFeedbackAccessInformation(feedback.id, modOptions).then((accessData) => {
|
||||
const p2 = [];
|
||||
if (accessData.canedititems || accessData.canviewreports) {
|
||||
// Get all groups analysis.
|
||||
p2.push(this.feedbackProvider.getAnalysis(feedback.id, undefined, true, siteId));
|
||||
p2.push(this.feedbackProvider.getAnalysis(feedback.id, modOptions));
|
||||
p2.push(this.groupsProvider.getActivityGroupInfo(feedback.coursemodule, true, undefined, siteId, true)
|
||||
.then((groupInfo) => {
|
||||
const p3 = [];
|
||||
|
@ -209,11 +220,16 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
groupInfo.groups = [{id: 0}];
|
||||
}
|
||||
groupInfo.groups.forEach((group) => {
|
||||
p3.push(this.feedbackProvider.getAnalysis(feedback.id, group.id, true, siteId));
|
||||
p3.push(this.feedbackProvider.getAllResponsesAnalysis(feedback.id, group.id, true, siteId));
|
||||
const groupOptions = {
|
||||
groupId: group.id,
|
||||
...modOptions, // Include all mod options.
|
||||
};
|
||||
|
||||
p3.push(this.feedbackProvider.getAnalysis(feedback.id, groupOptions));
|
||||
p3.push(this.feedbackProvider.getAllResponsesAnalysis(feedback.id, groupOptions));
|
||||
|
||||
if (!accessData.isanonymous) {
|
||||
p3.push(this.feedbackProvider.getAllNonRespondents(feedback.id, group.id, true, siteId));
|
||||
p3.push(this.feedbackProvider.getAllNonRespondents(feedback.id, groupOptions));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -221,7 +237,7 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
}));
|
||||
}
|
||||
|
||||
p2.push(this.feedbackProvider.getItems(feedback.id, true, siteId).then((response) => {
|
||||
p2.push(this.feedbackProvider.getItems(feedback.id, commonOptions).then((response) => {
|
||||
response.items.forEach((item) => {
|
||||
files = files.concat(item.itemfiles);
|
||||
});
|
||||
|
@ -234,8 +250,8 @@ export class AddonModFeedbackPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
p2.push(this.feedbackProvider.processPageOnline(feedback.id, 0, {}, undefined, siteId).finally(() => {
|
||||
const p4 = [];
|
||||
|
||||
p4.push(this.feedbackProvider.getCurrentValues(feedback.id, false, true, siteId));
|
||||
p4.push(this.feedbackProvider.getResumePage(feedback.id, false, true, siteId));
|
||||
p4.push(this.feedbackProvider.getCurrentValues(feedback.id, modOptions));
|
||||
p4.push(this.feedbackProvider.getResumePage(feedback.id, modOptions));
|
||||
|
||||
return Promise.all(p4);
|
||||
}));
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
|
@ -192,12 +192,12 @@ export class AddonModFeedbackSyncProvider extends CoreCourseActivitySyncBaseProv
|
|||
|
||||
courseId = responses[0].courseid;
|
||||
|
||||
return this.feedbackProvider.getFeedbackById(courseId, feedbackId, siteId).then((feedbackData) => {
|
||||
return this.feedbackProvider.getFeedbackById(courseId, feedbackId, {siteId}).then((feedbackData) => {
|
||||
feedback = feedbackData;
|
||||
|
||||
if (!feedback.multiple_submit) {
|
||||
// If it does not admit multiple submits, check if it is completed to know if we can submit.
|
||||
return this.feedbackProvider.isCompleted(feedbackId);
|
||||
return this.feedbackProvider.isCompleted(feedbackId, {cmId: feedback.coursemodule, siteId});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -220,7 +220,10 @@ export class AddonModFeedbackSyncProvider extends CoreCourseActivitySyncBaseProv
|
|||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
return this.feedbackProvider.getCurrentCompletedTimeModified(feedbackId, true, siteId).then((timemodified) => {
|
||||
return this.feedbackProvider.getCurrentCompletedTimeModified(feedbackId, {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
}).then((timemodified) => {
|
||||
// Sort by page.
|
||||
responses.sort((a, b) => {
|
||||
return a.page - b.page;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="!subfolder" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
|
@ -41,11 +41,11 @@ export class AddonModFolderProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the book is retrieved.
|
||||
*/
|
||||
getFolder(courseId: number, cmId: number, siteId?: string): Promise<AddonModFolderFolder> {
|
||||
return this.getFolderByKey(courseId, 'coursemodule', cmId, siteId);
|
||||
getFolder(courseId: number, cmId: number, options?: CoreSitesCommonWSOptions): Promise<AddonModFolderFolder> {
|
||||
return this.getFolderByKey(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,18 +54,21 @@ export class AddonModFolderProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the book is retrieved.
|
||||
*/
|
||||
protected getFolderByKey(courseId: number, key: string, value: any, siteId?: string): Promise<AddonModFolderFolder> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
protected getFolderByKey(courseId: number, key: string, value: any, options?: CoreSitesCommonWSOptions)
|
||||
: Promise<AddonModFolderFolder> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getFolderCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getFolderCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModFolderProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_folder_get_folders_by_courses', params, preSets)
|
||||
.then((response: AddonModFolderGetFoldersByCoursesResult): any => {
|
||||
|
|
|
@ -49,7 +49,7 @@ export class AddonForumDiscussionOptionsMenuComponent implements OnInit {
|
|||
ngOnInit(): void {
|
||||
if (this.forumProvider.isSetPinStateAvailableForSite()) {
|
||||
// Use the canAddDiscussion WS to check if the user can pin discussions.
|
||||
this.forumProvider.canAddDiscussionToAll(this.forumId).then((response) => {
|
||||
this.forumProvider.canAddDiscussionToAll(this.forumId, {cmId: this.cmId}).then((response) => {
|
||||
this.canPin = !!response.canpindiscussions;
|
||||
}).catch(() => {
|
||||
this.canPin = false;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !(hasOffline || hasOfflineRatings) && isOnline" [priority]="700" [content]="'addon.mod_forum.refreshdiscussions' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && (hasOffline || hasOfflineRatings) && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="sortingAvailable" [priority]="300" [content]="'core.sort' | translate" (action)="showSortOrderSelector($event)" iconAction="fa-sort"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
|
|
@ -250,7 +250,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
promises.push(this.groupsProvider.getActivityGroupMode(this.forum.cmid).then((mode) => {
|
||||
this.usesGroups = (mode === CoreGroupsProvider.SEPARATEGROUPS || mode === CoreGroupsProvider.VISIBLEGROUPS);
|
||||
}));
|
||||
promises.push(this.forumProvider.getAccessInformation(this.forum.id).then((accessInfo) => {
|
||||
promises.push(this.forumProvider.getAccessInformation(this.forum.id, {cmId: this.module.id}).then((accessInfo) => {
|
||||
// Disallow adding discussions if cut-off date is reached and the user has not the capability to override it.
|
||||
// Just in case the forum was fetched from WS when the cut-off date was not reached but it is now.
|
||||
const cutoffDateReached = this.forumHelper.isCutoffDateReached(this.forum) && !accessInfo.cancanoverridecutoff;
|
||||
|
@ -259,7 +259,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
|
||||
if (this.forumProvider.isSetPinStateAvailableForSite()) {
|
||||
// Use the canAddDiscussion WS to check if the user can pin discussions.
|
||||
promises.push(this.forumProvider.canAddDiscussionToAll(this.forum.id).then((response) => {
|
||||
promises.push(this.forumProvider.canAddDiscussionToAll(this.forum.id, {cmId: this.module.id}).then((response) => {
|
||||
this.canPin = !!response.canpindiscussions;
|
||||
}).catch(() => {
|
||||
this.canPin = false;
|
||||
|
@ -354,8 +354,11 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
this.page = 0;
|
||||
}
|
||||
|
||||
return this.forumProvider.getDiscussions(this.forum.id, this.forum.cmid,
|
||||
this.selectedSortOrder.value, this.page).then((response) => {
|
||||
return this.forumProvider.getDiscussions(this.forum.id, {
|
||||
cmId: this.forum.cmid,
|
||||
sortOrder: this.selectedSortOrder.value,
|
||||
page: this.page,
|
||||
}).then((response) => {
|
||||
let promise;
|
||||
if (this.usesGroups) {
|
||||
promise = this.forumProvider.formatDiscussionsGroups(this.forum.cmid, response.discussions);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { NavParams, ViewController } from 'ionic-angular';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { AddonModForumProvider } from '../../providers/forum';
|
||||
|
||||
|
@ -35,6 +35,8 @@ export class AddonForumPostOptionsMenuComponent implements OnInit {
|
|||
loaded = false;
|
||||
url: string;
|
||||
|
||||
protected cmId: number;
|
||||
|
||||
constructor(navParams: NavParams,
|
||||
protected viewCtrl: ViewController,
|
||||
protected domUtils: CoreDomUtilsProvider,
|
||||
|
@ -42,6 +44,7 @@ export class AddonForumPostOptionsMenuComponent implements OnInit {
|
|||
protected sitesProvider: CoreSitesProvider) {
|
||||
this.post = navParams.get('post');
|
||||
this.forumId = navParams.get('forumId');
|
||||
this.cmId = navParams.get('cmId');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,7 +67,10 @@ export class AddonForumPostOptionsMenuComponent implements OnInit {
|
|||
if (this.forumId) {
|
||||
try {
|
||||
this.post =
|
||||
await this.forumProvider.getDiscussionPost(this.forumId, this.post.discussionid, this.post.id, true);
|
||||
await this.forumProvider.getDiscussionPost(this.forumId, this.post.discussionid, this.post.id, {
|
||||
cmId: this.cmId,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
});
|
||||
} catch (error) {
|
||||
this.domUtils.showErrorModalDefault(error, 'Error getting discussion post.');
|
||||
}
|
||||
|
|
|
@ -193,7 +193,8 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
|
|||
|
||||
const popover = this.popoverCtrl.create(AddonForumPostOptionsMenuComponent, {
|
||||
post: this.post,
|
||||
forumId: this.forum.id
|
||||
forumId: this.forum.id,
|
||||
cmId: this.forum.cmid,
|
||||
});
|
||||
popover.onDidDismiss((data) => {
|
||||
if (data && data.action) {
|
||||
|
|
|
@ -329,7 +329,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
let ratingInfo;
|
||||
|
||||
return syncPromise.then(() => {
|
||||
return this.forumProvider.getDiscussionPosts(this.discussionId, this.cmId).then((response) => {
|
||||
return this.forumProvider.getDiscussionPosts(this.discussionId, {cmId: this.cmId}).then((response) => {
|
||||
onlinePosts = response.posts;
|
||||
ratingInfo = response.ratinginfo;
|
||||
this.courseId = response.courseid || this.courseId;
|
||||
|
@ -403,7 +403,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.forumProvider.getAccessInformation(this.forumId).then((accessInfo) => {
|
||||
promises.push(this.forumProvider.getAccessInformation(this.forumId, {cmId: this.cmId}).then((accessInfo) => {
|
||||
this.accessInfo = accessInfo;
|
||||
|
||||
// Disallow replying if cut-off date is reached and the user has not the capability to override it.
|
||||
|
@ -448,7 +448,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
}).then(() => {
|
||||
if (this.forumProvider.isSetPinStateAvailableForSite()) {
|
||||
// Use the canAddDiscussion WS to check if the user can pin discussions.
|
||||
return this.forumProvider.canAddDiscussionToAll(this.forumId).then((response) => {
|
||||
return this.forumProvider.canAddDiscussionToAll(this.forumId, {cmId: this.cmId}).then((response) => {
|
||||
this.canPin = !!response.canpindiscussions;
|
||||
}).catch(() => {
|
||||
this.canPin = false;
|
||||
|
|
|
@ -176,7 +176,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy {
|
|||
this.newDiscussion.postToAllGroups = false;
|
||||
|
||||
// Use the canAddDiscussion WS to check if the user can add attachments and pin discussions.
|
||||
promises.push(this.forumProvider.canAddDiscussionToAll(this.forumId).then((response) => {
|
||||
promises.push(this.forumProvider.canAddDiscussionToAll(this.forumId, {cmId: this.cmId}).then((response) => {
|
||||
this.canPin = !!response.canpindiscussions;
|
||||
this.canCreateAttachments = !!response.cancreateattachment;
|
||||
}).catch(() => {
|
||||
|
@ -190,7 +190,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy {
|
|||
}));
|
||||
|
||||
// Get access information.
|
||||
promises.push(this.forumProvider.getAccessInformation(this.forumId).then((accessInfo) => {
|
||||
promises.push(this.forumProvider.getAccessInformation(this.forumId, {cmId: this.cmId}).then((accessInfo) => {
|
||||
this.accessInfo = accessInfo;
|
||||
}));
|
||||
|
||||
|
@ -265,7 +265,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy {
|
|||
*/
|
||||
protected validateVisibleGroups(forumGroups: any[]): Promise<any[]> {
|
||||
// We first check if the user can post to all the groups.
|
||||
return this.forumProvider.canAddDiscussionToAll(this.forumId).catch(() => {
|
||||
return this.forumProvider.canAddDiscussionToAll(this.forumId, {cmId: this.cmId}).catch(() => {
|
||||
// The call failed, let's assume he can't.
|
||||
return {
|
||||
status: false,
|
||||
|
@ -285,7 +285,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy {
|
|||
const filtered = [];
|
||||
|
||||
forumGroups.forEach((group) => {
|
||||
promises.push(this.forumProvider.canAddDiscussion(this.forumId, group.id).catch(() => {
|
||||
promises.push(this.forumProvider.canAddDiscussion(this.forumId, group.id, {cmId: this.cmId}).catch(() => {
|
||||
/* The call failed, let's return true so the group is shown. If the user can't post to
|
||||
it an error will be shown when he tries to add the discussion. */
|
||||
return {
|
||||
|
@ -342,7 +342,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy {
|
|||
|
||||
if (check) {
|
||||
// We need to check if the user can add a discussion to all participants.
|
||||
promise = this.forumProvider.canAddDiscussionToAll(this.forumId).then((response) => {
|
||||
promise = this.forumProvider.canAddDiscussionToAll(this.forumId, {cmId: this.cmId}).then((response) => {
|
||||
this.canPin = !!response.canpindiscussions;
|
||||
this.canCreateAttachments = !!response.cancreateattachment;
|
||||
|
||||
|
|
|
@ -14,16 +14,17 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { AddonModForumOfflineProvider } from './offline';
|
||||
import { CoreRatingInfo } from '@core/rating/providers/rating';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Service that provides some features for forums.
|
||||
|
@ -206,26 +207,29 @@ export class AddonModForumProvider {
|
|||
*
|
||||
* @param forumId Forum ID.
|
||||
* @param groupId Group ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with an object with the following properties:
|
||||
* - status (boolean)
|
||||
* - canpindiscussions (boolean)
|
||||
* - cancreateattachment (boolean)
|
||||
*/
|
||||
canAddDiscussion(forumId: number, groupId: number, siteId?: string): Promise<any> {
|
||||
canAddDiscussion(forumId: number, groupId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
const params = {
|
||||
forumid: forumId,
|
||||
groupid: groupId
|
||||
groupid: groupId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getCanAddDiscussionCacheKey(forumId, groupId)
|
||||
cacheKey: this.getCanAddDiscussionCacheKey(forumId, groupId),
|
||||
component: AddonModForumProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
return site.read('mod_forum_can_add_discussion', params, preSets).then((result) => {
|
||||
if (result) {
|
||||
if (typeof result.canpindiscussions == 'undefined') {
|
||||
// WS doesn't support it yet, default it to false to prevent students from seing the option.
|
||||
// WS doesn't support it yet, default it to false to prevent students from seeing the option.
|
||||
result.canpindiscussions = false;
|
||||
}
|
||||
if (typeof result.cancreateattachment == 'undefined') {
|
||||
|
@ -245,14 +249,14 @@ export class AddonModForumProvider {
|
|||
* Check if a user can post to all groups.
|
||||
*
|
||||
* @param forumId Forum ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with an object with the following properties:
|
||||
* - status (boolean)
|
||||
* - canpindiscussions (boolean)
|
||||
* - cancreateattachment (boolean)
|
||||
*/
|
||||
canAddDiscussionToAll(forumId: number, siteId?: string): Promise<any> {
|
||||
return this.canAddDiscussion(forumId, AddonModForumProvider.ALL_PARTICIPANTS, siteId);
|
||||
canAddDiscussionToAll(forumId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.canAddDiscussion(forumId, AddonModForumProvider.ALL_PARTICIPANTS, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -382,17 +386,19 @@ export class AddonModForumProvider {
|
|||
* Get all course forums.
|
||||
*
|
||||
* @param courseId Course ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the forums are retrieved.
|
||||
*/
|
||||
getCourseForums(courseId: number, siteId?: string): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getCourseForums(courseId: number, options: CoreSitesCommonWSOptions = {}): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getForumDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModForumProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_forum_get_forums_by_courses', params, preSets);
|
||||
|
@ -405,24 +411,23 @@ export class AddonModForumProvider {
|
|||
* @param forumId Forum ID.
|
||||
* @param discussionId Discussion ID.
|
||||
* @param postId Post ID.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the post is retrieved.
|
||||
*/
|
||||
getDiscussionPost(forumId: number, discussionId: number, postId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
postid: postId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getDiscussionPostDataCacheKey(forumId, discussionId, postId),
|
||||
updateFrequency: CoreSite.FREQUENCY_USUALLY
|
||||
};
|
||||
getDiscussionPost(forumId: number, discussionId: number, postId: number, options: CoreCourseCommonModWSOptions = {})
|
||||
: Promise<any> {
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
postid: postId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getDiscussionPostDataCacheKey(forumId, discussionId, postId),
|
||||
updateFrequency: CoreSite.FREQUENCY_USUALLY,
|
||||
component: AddonModForumProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_forum_get_discussion_post', params, preSets).then((response) => {
|
||||
if (response.post) {
|
||||
|
@ -439,11 +444,11 @@ export class AddonModForumProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the forum is retrieved.
|
||||
*/
|
||||
getForum(courseId: number, cmId: number, siteId?: string): Promise<any> {
|
||||
return this.getCourseForums(courseId, siteId).then((forums) => {
|
||||
getForum(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getCourseForums(courseId, options).then((forums) => {
|
||||
const forum = forums.find((forum) => forum.cmid == cmId);
|
||||
if (forum) {
|
||||
return forum;
|
||||
|
@ -458,11 +463,11 @@ export class AddonModForumProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param forumId Forum ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the forum is retrieved.
|
||||
*/
|
||||
getForumById(courseId: number, forumId: number, siteId?: string): Promise<any> {
|
||||
return this.getCourseForums(courseId, siteId).then((forums) => {
|
||||
getForumById(courseId: number, forumId: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getCourseForums(courseId, options).then((forums) => {
|
||||
const forum = forums.find((forum) => forum.id == forumId);
|
||||
if (forum) {
|
||||
return forum;
|
||||
|
@ -476,24 +481,25 @@ export class AddonModForumProvider {
|
|||
* Get access information for a given forum.
|
||||
*
|
||||
* @param forumId Forum ID.
|
||||
* @param forceCache True to always get the value from cache. false otherwise.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Object with access information.
|
||||
* @since 3.7
|
||||
*/
|
||||
getAccessInformation(forumId: number, forceCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getAccessInformation(forumId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
if (!site.wsAvailable('mod_forum_get_forum_access_information')) {
|
||||
// Access information not available for 3.6 or older sites.
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
const params = {
|
||||
forumid: forumId
|
||||
forumid: forumId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAccessInformationCacheKey(forumId),
|
||||
omitExpires: forceCache
|
||||
component: AddonModForumProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_forum_get_forum_access_information', params, preSets);
|
||||
|
@ -504,11 +510,10 @@ export class AddonModForumProvider {
|
|||
* Get forum discussion posts.
|
||||
*
|
||||
* @param discussionId Discussion ID.
|
||||
* @param cmId Forum cmid.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with forum posts and rating info.
|
||||
*/
|
||||
getDiscussionPosts(discussionId: number, cmId: number, siteId?: string): Promise<{posts: any[], courseid?: number,
|
||||
getDiscussionPosts(discussionId: number, options: CoreCourseCommonModWSOptions = {}): Promise<{posts: any[], courseid?: number,
|
||||
forumid?: number, ratinginfo?: CoreRatingInfo}> {
|
||||
|
||||
// Convenience function to translate legacy data to new format.
|
||||
|
@ -546,15 +551,16 @@ export class AddonModForumProvider {
|
|||
};
|
||||
|
||||
const params = {
|
||||
discussionid: discussionId
|
||||
discussionid: discussionId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getDiscussionPostsCacheKey(discussionId),
|
||||
component: AddonModForumProvider.COMPONENT,
|
||||
componentId: cmId
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const wsName = this.isGetDiscussionPostsAvailable(site) ? 'mod_forum_get_discussion_posts' :
|
||||
'mod_forum_get_forum_discussion_posts';
|
||||
|
||||
|
@ -650,34 +656,30 @@ export class AddonModForumProvider {
|
|||
* Get forum discussions.
|
||||
*
|
||||
* @param forumId Forum ID.
|
||||
* @param cmId Forum cmid
|
||||
* @param sortOrder Sort order.
|
||||
* @param page Page.
|
||||
* @param forceCache True to always get the value from cache. false otherwise.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with an object with:
|
||||
* - discussions: List of discussions. Note that for every discussion in the list discussion.id is the main post ID but
|
||||
* discussion ID is discussion.discussion.
|
||||
* - canLoadMore: True if there may be more discussions to load.
|
||||
*/
|
||||
getDiscussions(forumId: number, cmId: number, sortOrder?: number, page: number = 0,
|
||||
forceCache?: boolean, siteId?: string): Promise<any> {
|
||||
sortOrder = sortOrder || AddonModForumProvider.SORTORDER_LASTPOST_DESC;
|
||||
getDiscussions(forumId: number, options: AddonModForumGetDiscussionsOptions = {}): Promise<any> {
|
||||
options.sortOrder = options.sortOrder || AddonModForumProvider.SORTORDER_LASTPOST_DESC;
|
||||
options.page = options.page || 0;
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
let method = 'mod_forum_get_forum_discussions_paginated';
|
||||
const params: any = {
|
||||
forumid: forumId,
|
||||
page: page,
|
||||
perpage: AddonModForumProvider.DISCUSSIONS_PER_PAGE
|
||||
page: options.page,
|
||||
perpage: AddonModForumProvider.DISCUSSIONS_PER_PAGE,
|
||||
};
|
||||
|
||||
if (site.wsAvailable('mod_forum_get_forum_discussions')) {
|
||||
// Since Moodle 3.7.
|
||||
method = 'mod_forum_get_forum_discussions';
|
||||
params.sortorder = sortOrder;
|
||||
params.sortorder = options.sortOrder;
|
||||
} else {
|
||||
if (sortOrder == AddonModForumProvider.SORTORDER_LASTPOST_DESC) {
|
||||
if (options.sortOrder == AddonModForumProvider.SORTORDER_LASTPOST_DESC) {
|
||||
params.sortby = 'timemodified';
|
||||
params.sortdirection = 'DESC';
|
||||
} else {
|
||||
|
@ -685,31 +687,27 @@ export class AddonModForumProvider {
|
|||
return Promise.reject(null);
|
||||
}
|
||||
}
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getDiscussionsListCacheKey(forumId, sortOrder),
|
||||
|
||||
const preSets = {
|
||||
cacheKey: this.getDiscussionsListCacheKey(forumId, options.sortOrder),
|
||||
component: AddonModForumProvider.COMPONENT,
|
||||
componentId: cmId
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
if (forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
}
|
||||
|
||||
return site.read(method, params, preSets).catch((error) => {
|
||||
// Try to get the data from cache stored with the old WS method.
|
||||
if (!this.appProvider.isOnline() && method == 'mod_forum_get_forum_discussion' &&
|
||||
sortOrder == AddonModForumProvider.SORTORDER_LASTPOST_DESC) {
|
||||
options.sortOrder == AddonModForumProvider.SORTORDER_LASTPOST_DESC) {
|
||||
|
||||
const params = {
|
||||
forumid: forumId,
|
||||
page: page,
|
||||
page: options.page,
|
||||
perpage: AddonModForumProvider.DISCUSSIONS_PER_PAGE,
|
||||
sortby: 'timemodified',
|
||||
sortdirection: 'DESC'
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getDiscussionsListCacheKey(forumId, sortOrder),
|
||||
omitExpires: true
|
||||
};
|
||||
Object.assign(preSets, this.sitesProvider.getReadingStrategyPreSets(CoreSitesReadingStrategy.PreferCache));
|
||||
|
||||
return site.read('mod_forum_get_forum_discussions_paginated', params, preSets);
|
||||
}
|
||||
|
@ -745,17 +743,14 @@ export class AddonModForumProvider {
|
|||
* - discussions: List of discussions.
|
||||
* - error: True if an error occurred, false otherwise.
|
||||
*/
|
||||
getDiscussionsInPages(forumId: number, cmId: number, sortOrder?: number, forceCache?: boolean,
|
||||
numPages?: number, startPage?: number, siteId?: string): Promise<any> {
|
||||
if (typeof numPages == 'undefined') {
|
||||
numPages = -1;
|
||||
}
|
||||
startPage = startPage || 0;
|
||||
getDiscussionsInPages(forumId: number, options: AddonModForumGetDiscussionsInPagesOptions = {}): Promise<any> {
|
||||
options.page = options.page || 0;
|
||||
|
||||
const result = {
|
||||
discussions: [],
|
||||
error: false
|
||||
};
|
||||
let numPages = typeof options.numPages == 'undefined' ? -1 : options.numPages;
|
||||
|
||||
if (!numPages) {
|
||||
return Promise.resolve(result);
|
||||
|
@ -763,7 +758,7 @@ export class AddonModForumProvider {
|
|||
|
||||
const getPage = (page: number): Promise<any> => {
|
||||
// Get page discussions.
|
||||
return this.getDiscussions(forumId, cmId, sortOrder, page, forceCache, siteId).then((response) => {
|
||||
return this.getDiscussions(forumId, options).then((response) => {
|
||||
result.discussions = result.discussions.concat(response.discussions);
|
||||
numPages--;
|
||||
|
||||
|
@ -780,7 +775,7 @@ export class AddonModForumProvider {
|
|||
});
|
||||
};
|
||||
|
||||
return getPage(startPage);
|
||||
return getPage(options.page);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -816,7 +811,11 @@ export class AddonModForumProvider {
|
|||
|
||||
this.getAvailableSortOrders().forEach((sortOrder) => {
|
||||
// We need to get the list of discussions to be able to invalidate their posts.
|
||||
promises.push(this.getDiscussionsInPages(forum.id, forum.cmid, sortOrder.value, true).then((response) => {
|
||||
promises.push(this.getDiscussionsInPages(forum.id, {
|
||||
cmId: forum.cmid,
|
||||
sortOrder: sortOrder.value,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
}).then((response) => {
|
||||
// Now invalidate the WS calls.
|
||||
const promises = [];
|
||||
|
||||
|
@ -1164,3 +1163,18 @@ export class AddonModForumProvider {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to pass to get discussions.
|
||||
*/
|
||||
export type AddonModForumGetDiscussionsOptions = CoreCourseCommonModWSOptions & {
|
||||
sortOrder?: number; // Sort order.
|
||||
page?: number; // Page. Defaults to 0.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to get discussions in pages.
|
||||
*/
|
||||
export type AddonModForumGetDiscussionsInPagesOptions = AddonModForumGetDiscussionsOptions & {
|
||||
numPages?: number; // Number of pages to get. If not defined, all pages.
|
||||
};
|
||||
|
|
|
@ -279,7 +279,11 @@ export class AddonModForumHelperProvider {
|
|||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const findDiscussion = (page: number): Promise<any> => {
|
||||
return this.forumProvider.getDiscussions(forumId, cmId, undefined, page, false, siteId).then((response) => {
|
||||
return this.forumProvider.getDiscussions(forumId, {
|
||||
cmId,
|
||||
page,
|
||||
siteId,
|
||||
}).then((response) => {
|
||||
if (response.discussions && response.discussions.length > 0) {
|
||||
// Note that discussion.id is the main post ID but discussion ID is discussion.discussion.
|
||||
const discussion = response.discussions.find((discussion) => discussion.discussion == discussionId);
|
||||
|
|
|
@ -143,7 +143,7 @@ export class AddonModForumModuleHandler implements CoreCourseModuleHandler {
|
|||
|
||||
this.forumProvider.invalidateForumData(courseId).finally(() => {
|
||||
// Handle unread posts.
|
||||
this.forumProvider.getForum(courseId, moduleId, siteId).then((forumData) => {
|
||||
this.forumProvider.getForum(courseId, moduleId, {siteId}).then((forumData) => {
|
||||
data.extraBadgeColor = '';
|
||||
data.extraBadge = forumData.unreadpostscount ? this.translate.instant('addon.mod_forum.unreadpostsnumber',
|
||||
{$a : forumData.unreadpostscount }) : '';
|
||||
|
|
|
@ -16,10 +16,10 @@ import { Injectable } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseProvider, CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
|
@ -69,7 +69,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
const files = this.getIntroFilesFromInstance(module, forum);
|
||||
|
||||
// Get posts.
|
||||
return this.getPostsForPrefetch(forum).then((posts) => {
|
||||
return this.getPostsForPrefetch(forum, {cmId: module.id}).then((posts) => {
|
||||
// Add posts attachments and embedded files.
|
||||
return files.concat(this.getPostsFiles(posts));
|
||||
});
|
||||
|
@ -108,14 +108,19 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
* Get the posts to be prefetched.
|
||||
*
|
||||
* @param forum Forum instance.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with array of posts.
|
||||
*/
|
||||
protected getPostsForPrefetch(forum: any, siteId?: string): Promise<any[]> {
|
||||
protected getPostsForPrefetch(forum: any, options: CoreCourseCommonModWSOptions = {}): Promise<any[]> {
|
||||
const promises = this.forumProvider.getAvailableSortOrders().map((sortOrder) => {
|
||||
// Get discussions in first 2 pages.
|
||||
return this.forumProvider.getDiscussionsInPages(forum.id, forum.cmid,
|
||||
sortOrder.value, false, 2, 0, siteId).then((response) => {
|
||||
const discussionsOptions = {
|
||||
sortOrder: sortOrder.value,
|
||||
numPages: 2,
|
||||
...options, // Include all options.
|
||||
};
|
||||
|
||||
return this.forumProvider.getDiscussionsInPages(forum.id, discussionsOptions).then((response) => {
|
||||
if (response.error) {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
|
@ -123,7 +128,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
const promises = [];
|
||||
|
||||
response.discussions.forEach((discussion) => {
|
||||
promises.push(this.forumProvider.getDiscussionPosts(discussion.discussion, forum.cmid, siteId));
|
||||
promises.push(this.forumProvider.getDiscussionPosts(discussion.discussion, options));
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
|
@ -202,12 +207,21 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected prefetchForum(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
const commonOptions = {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
const modOptions = {
|
||||
cmId: module.id,
|
||||
...commonOptions, // Include all common options.
|
||||
};
|
||||
|
||||
// Get the forum data.
|
||||
return this.forumProvider.getForum(courseId, module.id, siteId).then((forum) => {
|
||||
return this.forumProvider.getForum(courseId, module.id, commonOptions).then((forum) => {
|
||||
const promises = [];
|
||||
|
||||
// Prefetch the posts.
|
||||
promises.push(this.getPostsForPrefetch(forum, siteId).then((posts) => {
|
||||
promises.push(this.getPostsForPrefetch(forum, modOptions).then((posts) => {
|
||||
const promises = [];
|
||||
|
||||
const files = this.getIntroFilesFromInstance(module, forum).concat(this.getPostsFiles(posts));
|
||||
|
@ -223,7 +237,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
}));
|
||||
|
||||
// Prefetch access information.
|
||||
promises.push(this.forumProvider.getAccessInformation(forum.id, false, siteId));
|
||||
promises.push(this.forumProvider.getAccessInformation(forum.id, modOptions));
|
||||
|
||||
// Prefetch sort order preference.
|
||||
if (this.forumProvider.isDiscussionListSortingAvailable()) {
|
||||
|
@ -244,11 +258,16 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
* @return Promise resolved when group data has been prefetched.
|
||||
*/
|
||||
protected prefetchGroupsInfo(forum: any, courseId: number, canCreateDiscussions: boolean, siteId?: string): any {
|
||||
const options = {
|
||||
cmId: forum.cmid,
|
||||
siteId,
|
||||
};
|
||||
|
||||
// Check group mode.
|
||||
return this.groupsProvider.getActivityGroupMode(forum.cmid, siteId).then((mode) => {
|
||||
if (mode !== CoreGroupsProvider.SEPARATEGROUPS && mode !== CoreGroupsProvider.VISIBLEGROUPS) {
|
||||
// Activity doesn't use groups. Prefetch canAddDiscussionToAll to determine if user can pin/attach.
|
||||
return this.forumProvider.canAddDiscussionToAll(forum.id, siteId).catch(() => {
|
||||
return this.forumProvider.canAddDiscussionToAll(forum.id, options).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
|
@ -257,14 +276,14 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
return this.groupsProvider.getActivityAllowedGroups(forum.cmid, undefined, siteId).then((result) => {
|
||||
if (mode === CoreGroupsProvider.SEPARATEGROUPS) {
|
||||
// Groups are already filtered by WS. Prefetch canAddDiscussionToAll to determine if user can pin/attach.
|
||||
return this.forumProvider.canAddDiscussionToAll(forum.id, siteId).catch(() => {
|
||||
return this.forumProvider.canAddDiscussionToAll(forum.id, options).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
|
||||
if (canCreateDiscussions) {
|
||||
// Prefetch data to check the visible groups when creating discussions.
|
||||
return this.forumProvider.canAddDiscussionToAll(forum.id, siteId).catch(() => {
|
||||
return this.forumProvider.canAddDiscussionToAll(forum.id, options).catch(() => {
|
||||
// The call failed, let's assume he can't.
|
||||
return {
|
||||
status: false
|
||||
|
@ -278,7 +297,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
|||
// The user can't post to all groups, let's check which groups he can post to.
|
||||
const groupPromises = [];
|
||||
result.groups.forEach((group) => {
|
||||
groupPromises.push(this.forumProvider.canAddDiscussion(forum.id, group.id, siteId).catch(() => {
|
||||
groupPromises.push(this.forumProvider.canAddDiscussion(forum.id, group.id, options).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
});
|
||||
|
|
|
@ -227,7 +227,7 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider {
|
|||
let groupsPromise;
|
||||
if (data.groupid == AddonModForumProvider.ALL_GROUPS) {
|
||||
// Fetch all group ids.
|
||||
groupsPromise = this.forumProvider.getForumById(data.courseid, data.forumid, siteId).then((forum) => {
|
||||
groupsPromise = this.forumProvider.getForumById(data.courseid, data.forumid, {siteId}).then((forum) => {
|
||||
return this.groupsProvider.getActivityAllowedGroups(forum.cmid).then((result) => {
|
||||
return result.groups.map((group) => group.id);
|
||||
});
|
||||
|
@ -330,7 +330,7 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider {
|
|||
}
|
||||
if (result.warnings.length) {
|
||||
// Fetch forum to construct the warning message.
|
||||
promises.push(this.forumProvider.getForum(result.itemSet.courseId, result.itemSet.instanceId, siteId)
|
||||
promises.push(this.forumProvider.getForum(result.itemSet.courseId, result.itemSet.instanceId, {siteId})
|
||||
.then((forum) => {
|
||||
result.warnings.forEach((warning) => {
|
||||
warnings.push(this.translate.instant('core.warningofflinedatadeleted', {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && (hasOffline || hasOfflineRatings) && isOnline" [priority]="650" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="canAdd" [priority]="600" [content]="'addon.mod_glossary.addentry' | translate" (action)="openNewEntry()" iconAction="add"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -181,10 +181,10 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
|
|||
return Promise.resolve({entries: [], count: 0});
|
||||
}
|
||||
|
||||
const limitFrom = append ? this.entries.length : 0;
|
||||
const limitNum = AddonModGlossaryProvider.LIMIT_ENTRIES;
|
||||
|
||||
return this.glossaryProvider.fetchEntries(this.fetchFunction, this.fetchArguments, limitFrom, limitNum).then((result) => {
|
||||
return this.glossaryProvider.fetchEntries(this.fetchFunction, this.fetchArguments, {
|
||||
from: append ? this.entries.length : 0,
|
||||
cmId: this.module.id,
|
||||
}).then((result) => {
|
||||
if (append) {
|
||||
Array.prototype.push.apply(this.entries, result.entries);
|
||||
} else {
|
||||
|
|
|
@ -125,7 +125,9 @@ export class AddonModGlossaryEditPage implements OnInit {
|
|||
this.definitionControl.setValue(this.entry.definition);
|
||||
|
||||
Promise.resolve(promise).then(() => {
|
||||
this.glossaryProvider.getAllCategories(this.glossary.id).then((categories) => {
|
||||
this.glossaryProvider.getAllCategories(this.glossary.id, {
|
||||
cmId: this.module.id,
|
||||
}).then((categories) => {
|
||||
this.categories = categories;
|
||||
}).finally(() => {
|
||||
this.loaded = true;
|
||||
|
@ -215,8 +217,10 @@ export class AddonModGlossaryEditPage implements OnInit {
|
|||
let promise;
|
||||
if (this.entry && !this.glossary.allowduplicatedentries) {
|
||||
// Check if the entry is duplicated in online or offline mode.
|
||||
promise = this.glossaryProvider.isConceptUsed(this.glossary.id, this.entry.concept, this.entry.timecreated)
|
||||
.then((used) => {
|
||||
promise = this.glossaryProvider.isConceptUsed(this.glossary.id, this.entry.concept, {
|
||||
timeCreated: this.entry.timecreated,
|
||||
cmId: this.module.id,
|
||||
}).then((used) => {
|
||||
if (used) {
|
||||
// There's a entry with same name, reject with error message.
|
||||
return Promise.reject(this.translate.instant('addon.mod_glossary.errconceptalreadyexists'));
|
||||
|
@ -237,7 +241,12 @@ export class AddonModGlossaryEditPage implements OnInit {
|
|||
// Try to send it to server.
|
||||
// Don't allow offline if there are attachments since they were uploaded fine.
|
||||
return this.glossaryProvider.addEntry(this.glossary.id, this.entry.concept, definition, this.courseId, options,
|
||||
attach, timecreated, undefined, this.entry, !this.attachments.length, !this.glossary.allowduplicatedentries);
|
||||
attach, {
|
||||
timeCreated: timecreated,
|
||||
discardEntry: this.entry,
|
||||
allowOffline: !this.attachments.length,
|
||||
checkDuplicates: !this.glossary.allowduplicatedentries,
|
||||
});
|
||||
}
|
||||
}).then((entryId) => {
|
||||
// Delete the local files from the tmp folder.
|
||||
|
|
|
@ -63,7 +63,7 @@ export class AddonModGlossaryEntryLinkHandler extends CoreContentLinksHandlerBas
|
|||
if (courseId) {
|
||||
promise = Promise.resolve(courseId);
|
||||
} else {
|
||||
promise = this.glossaryProvider.getEntry(entryId, siteId).catch((error) => {
|
||||
promise = this.glossaryProvider.getEntry(entryId, {siteId}).catch((error) => {
|
||||
this.domUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentry', true);
|
||||
|
||||
return Promise.reject(null);
|
||||
|
|
|
@ -17,12 +17,13 @@ import { TranslateService } from '@ngx-translate/core';
|
|||
import { CoreSite } from '@classes/site';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSiteSchema, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { CoreRatingInfo } from '@core/rating/providers/rating';
|
||||
import { AddonModGlossaryOfflineProvider } from './offline';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Service that provides some features for glossaries.
|
||||
|
@ -92,17 +93,19 @@ export class AddonModGlossaryProvider {
|
|||
* Get all the glossaries in a course.
|
||||
*
|
||||
* @param courseId Course Id.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Resolved with the glossaries.
|
||||
*/
|
||||
getCourseGlossaries(courseId: number, siteId?: string): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getCourseGlossaries(courseId: number, options: CoreSitesCommonWSOptions = {}): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getCourseGlossariesCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_glossaries_by_courses', params, preSets).then((result) => {
|
||||
|
@ -146,29 +149,27 @@ export class AddonModGlossaryProvider {
|
|||
* @param letter First letter of firstname or lastname, or either keywords: ALL or SPECIAL.
|
||||
* @param field Search and order using: FIRSTNAME or LASTNAME
|
||||
* @param sort The direction of the order: ASC or DESC
|
||||
* @param from Start returning records from here.
|
||||
* @param limit Number of records to return.
|
||||
* @param omitExpires True to always get the value from cache. If data isn't cached, it will call the WS.
|
||||
* @param forceOffline True to always get the value from cache. If data isn't cached, it won't call the WS.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Resolved with the entries.
|
||||
*/
|
||||
getEntriesByAuthor(glossaryId: number, letter: string, field: string, sort: string, from: number, limit: number,
|
||||
omitExpires: boolean, forceOffline: boolean, siteId?: string): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getEntriesByAuthor(glossaryId: number, letter: string, field: string, sort: string,
|
||||
options: AddonModGlossaryGetEntriesOptions = {}): Promise<any[]> {
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
id: glossaryId,
|
||||
letter: letter,
|
||||
field: field,
|
||||
sort: sort,
|
||||
from: from,
|
||||
limit: limit
|
||||
from: options.from || 0,
|
||||
limit: options.limit || AddonModGlossaryProvider.LIMIT_ENTRIES,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntriesByAuthorCacheKey(glossaryId, letter, field, sort),
|
||||
omitExpires: omitExpires,
|
||||
forceOffline: forceOffline,
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_entries_by_author', params, preSets);
|
||||
|
@ -199,28 +200,24 @@ export class AddonModGlossaryProvider {
|
|||
* @param glossaryId Glossary Id.
|
||||
* @param categoryId The category ID. Use constant SHOW_ALL_CATEGORIES for all categories, or
|
||||
* constant SHOW_NOT_CATEGORISED for uncategorised entries.
|
||||
* @param from Start returning records from here.
|
||||
* @param limit Number of records to return.
|
||||
* @param omitExpires True to always get the value from cache. If data isn't cached, it will call the WS.
|
||||
* @param forceOffline True to always get the value from cache. If data isn't cached, it won't call the WS.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Resolved with the entries.
|
||||
*/
|
||||
getEntriesByCategory(glossaryId: number, categoryId: number, from: number, limit: number, omitExpires: boolean,
|
||||
forceOffline: boolean, siteId?: string): Promise<any[]> {
|
||||
getEntriesByCategory(glossaryId: number, categoryId: number, options: AddonModGlossaryGetEntriesOptions = {}): Promise<any[]> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
id: glossaryId,
|
||||
categoryid: categoryId,
|
||||
from: from,
|
||||
limit: limit
|
||||
from: options.from || 0,
|
||||
limit: options.limit || AddonModGlossaryProvider.LIMIT_ENTRIES,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntriesByCategoryCacheKey(glossaryId, categoryId),
|
||||
omitExpires: omitExpires,
|
||||
forceOffline: forceOffline,
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_entries_by_category', params, preSets);
|
||||
|
@ -274,29 +271,26 @@ export class AddonModGlossaryProvider {
|
|||
* @param glossaryId Glossary Id.
|
||||
* @param order The way to order the records.
|
||||
* @param sort The direction of the order.
|
||||
* @param from Start returning records from here.
|
||||
* @param limit Number of records to return.
|
||||
* @param omitExpires True to always get the value from cache. If data isn't cached, it will call the WS.
|
||||
* @param forceOffline True to always get the value from cache. If data isn't cached, it won't call the WS.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Resolved with the entries.
|
||||
*/
|
||||
getEntriesByDate(glossaryId: number, order: string, sort: string, from: number, limit: number, omitExpires: boolean,
|
||||
forceOffline: boolean, siteId?: string): Promise<any[]> {
|
||||
getEntriesByDate(glossaryId: number, order: string, sort: string, options: AddonModGlossaryGetEntriesOptions = {})
|
||||
: Promise<any[]> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
id: glossaryId,
|
||||
order: order,
|
||||
sort: sort,
|
||||
from: from,
|
||||
limit: limit
|
||||
from: options.from || 0,
|
||||
limit: options.limit || AddonModGlossaryProvider.LIMIT_ENTRIES,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntriesByDateCacheKey(glossaryId, order, sort),
|
||||
omitExpires: omitExpires,
|
||||
forceOffline: forceOffline,
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_entries_by_date', params, preSets);
|
||||
|
@ -336,35 +330,33 @@ export class AddonModGlossaryProvider {
|
|||
*
|
||||
* @param glossaryId Glossary Id.
|
||||
* @param letter A letter, or a special keyword.
|
||||
* @param from Start returning records from here.
|
||||
* @param limit Number of records to return.
|
||||
* @param omitExpires True to always get the value from cache. If data isn't cached, it will call the WS.
|
||||
* @param forceOffline True to always get the value from cache. If data isn't cached, it won't call the WS.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Resolved with the entries.
|
||||
*/
|
||||
getEntriesByLetter(glossaryId: number, letter: string, from: number, limit: number, omitExpires: boolean, forceOffline: boolean,
|
||||
siteId?: string): Promise<any> {
|
||||
getEntriesByLetter(glossaryId: number, letter: string, options: AddonModGlossaryGetEntriesOptions = {}): Promise<any> {
|
||||
options.from = options.from || 0;
|
||||
options.limit = options.limit || AddonModGlossaryProvider.LIMIT_ENTRIES;
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
id: glossaryId,
|
||||
letter: letter,
|
||||
from: from,
|
||||
limit: limit
|
||||
from: options.from,
|
||||
limit: options.limit,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntriesByLetterCacheKey(glossaryId, letter),
|
||||
omitExpires: omitExpires,
|
||||
forceOffline: forceOffline,
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_entries_by_letter', params, preSets).then((result) => {
|
||||
|
||||
if (limit == AddonModGlossaryProvider.LIMIT_ENTRIES) {
|
||||
if (options.limit == AddonModGlossaryProvider.LIMIT_ENTRIES) {
|
||||
// Store entries in background, don't block the user for this.
|
||||
this.storeEntries(glossaryId, result.entries, from, site.getId()).catch(() => {
|
||||
this.storeEntries(glossaryId, result.entries, options.from, site.getId()).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
|
@ -420,23 +412,25 @@ export class AddonModGlossaryProvider {
|
|||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return Resolved with the entries.
|
||||
*/
|
||||
getEntriesBySearch(glossaryId: number, query: string, fullSearch: boolean, order: string, sort: string, from: number,
|
||||
limit: number, omitExpires: boolean, forceOffline: boolean, siteId?: string): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getEntriesBySearch(glossaryId: number, query: string, fullSearch: boolean, order: string, sort: string,
|
||||
options: AddonModGlossaryGetEntriesOptions = {}): Promise<any[]> {
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
id: glossaryId,
|
||||
query: query,
|
||||
fullsearch: fullSearch,
|
||||
order: order,
|
||||
sort: sort,
|
||||
from: from,
|
||||
limit: limit
|
||||
from: options.from || 0,
|
||||
limit: options.limit || AddonModGlossaryProvider.LIMIT_ENTRIES,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntriesBySearchCacheKey(glossaryId, query, fullSearch, order, sort),
|
||||
omitExpires: omitExpires,
|
||||
forceOffline: forceOffline,
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_entries_by_search', params, preSets);
|
||||
|
@ -477,12 +471,12 @@ export class AddonModGlossaryProvider {
|
|||
* Get all the categories related to the glossary.
|
||||
*
|
||||
* @param glossaryId Glossary Id.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the categories if supported or empty array if not.
|
||||
*/
|
||||
getAllCategories(glossaryId: number, siteId?: string): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.getCategories(glossaryId, 0, AddonModGlossaryProvider.LIMIT_CATEGORIES, [], site);
|
||||
getAllCategories(glossaryId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any[]> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
return this.getCategories(glossaryId, [], site, options);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -490,30 +484,37 @@ export class AddonModGlossaryProvider {
|
|||
* Get the categories related to the glossary by sections. It's a recursive function see initial call values.
|
||||
*
|
||||
* @param glossaryId Glossary Id.
|
||||
* @param from Number of categories already fetched, so fetch will be done from this number. Initial value 0.
|
||||
* @param limit Number of categories to fetch. Initial value LIMIT_CATEGORIES.
|
||||
* @param categories Already fetched categories where to append the fetch. Initial value [].
|
||||
* @param categories Already fetched categories where to append the fetch.
|
||||
* @param site Site object.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the categories.
|
||||
*/
|
||||
protected getCategories(glossaryId: number, from: number, limit: number, categories: any[], site: CoreSite): Promise<any[]> {
|
||||
protected getCategories(glossaryId: number, categories: any[], site: CoreSite,
|
||||
options: AddonModGlossaryGetCategoriesOptions = {}): Promise<any[]> {
|
||||
|
||||
options.from = options.from || 0;
|
||||
options.limit = options.limit || AddonModGlossaryProvider.LIMIT_CATEGORIES;
|
||||
|
||||
const params = {
|
||||
id: glossaryId,
|
||||
from: from,
|
||||
limit: limit
|
||||
from: options.from,
|
||||
limit: options.limit,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getCategoriesCacheKey(glossaryId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_categories', params, preSets).then((response) => {
|
||||
categories = categories.concat(response.categories);
|
||||
const canLoadMore = (from + limit) < response.count;
|
||||
const canLoadMore = (options.from + options.limit) < response.count;
|
||||
if (canLoadMore) {
|
||||
from += limit;
|
||||
options.from += options.limit;
|
||||
|
||||
return this.getCategories(glossaryId, from, limit, categories, site);
|
||||
return this.getCategories(glossaryId, categories, site, options);
|
||||
}
|
||||
|
||||
return categories;
|
||||
|
@ -547,17 +548,22 @@ export class AddonModGlossaryProvider {
|
|||
* Get one entry by ID.
|
||||
*
|
||||
* @param entryId Entry ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the entry.
|
||||
*/
|
||||
getEntry(entryId: number, siteId?: string): Promise<{entry: any, ratinginfo: CoreRatingInfo, from?: number}> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getEntry(entryId: number, options: CoreCourseCommonModWSOptions = {})
|
||||
: Promise<{entry: any, ratinginfo: CoreRatingInfo, from?: number}> {
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
id: entryId
|
||||
id: entryId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getEntryCacheKey(entryId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModGlossaryProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_glossary_get_entry_by_id', params, preSets).then((response) => {
|
||||
|
@ -572,8 +578,12 @@ export class AddonModGlossaryProvider {
|
|||
|
||||
const searchEntry = (from: number, loadNext: boolean): Promise<any> => {
|
||||
// Get the entries from this "page" and check if the entry we're looking for is in it.
|
||||
return this.getEntriesByLetter(glossaryId, 'ALL', from, AddonModGlossaryProvider.LIMIT_ENTRIES, false, true,
|
||||
siteId).then((result) => {
|
||||
return this.getEntriesByLetter(glossaryId, 'ALL', {
|
||||
from: from,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyCache,
|
||||
cmId: options.cmId,
|
||||
siteId: options.siteId,
|
||||
}).then((result) => {
|
||||
|
||||
for (let i = 0; i < result.entries.length; i++) {
|
||||
const entry = result.entries[i];
|
||||
|
@ -643,48 +653,34 @@ export class AddonModGlossaryProvider {
|
|||
*
|
||||
* @param fetchFunction Function to fetch.
|
||||
* @param fetchArguments Arguments to call the fetching.
|
||||
* @param limitFrom Number of entries already fetched, so fetch will be done from this number.
|
||||
* @param limitNum Number of records to return. Defaults to LIMIT_ENTRIES.
|
||||
* @param omitExpires True to always get the value from cache. If data isn't cached, it will call the WS.
|
||||
* @param forceOffline True to always get the value from cache. If data isn't cached, it won't call the WS.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the response.
|
||||
*/
|
||||
fetchEntries(fetchFunction: Function, fetchArguments: any[], limitFrom: number = 0, limitNum?: number,
|
||||
omitExpires: boolean = false, forceOffline: boolean = false, siteId?: string): Promise<any> {
|
||||
limitNum = limitNum || AddonModGlossaryProvider.LIMIT_ENTRIES;
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
fetchEntries(fetchFunction: Function, fetchArguments: any[], options: AddonModGlossaryGetEntriesOptions = {}): Promise<any> {
|
||||
const args = fetchArguments.slice();
|
||||
args.push(limitFrom);
|
||||
args.push(limitNum);
|
||||
args.push(omitExpires);
|
||||
args.push(forceOffline);
|
||||
args.push(siteId);
|
||||
args.push(options);
|
||||
|
||||
return fetchFunction.apply(this, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the whole fetch of the entries using the propper function and arguments.
|
||||
* Performs the whole fetch of the entries using the proper function and arguments.
|
||||
*
|
||||
* @param fetchFunction Function to fetch.
|
||||
* @param fetchArguments Arguments to call the fetching.
|
||||
* @param omitExpires True to always get the value from cache. If data isn't cached, it will call the WS.
|
||||
* @param forceOffline True to always get the value from cache. If data isn't cached, it won't call the WS.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with all entrries.
|
||||
*/
|
||||
fetchAllEntries(fetchFunction: Function, fetchArguments: any[], omitExpires: boolean = false, forceOffline: boolean = false,
|
||||
siteId?: string): Promise<any[]> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
fetchAllEntries(fetchFunction: Function, fetchArguments: any[], options: CoreCourseCommonModWSOptions = {}): Promise<any[]> {
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const entries = [];
|
||||
const limitNum = AddonModGlossaryProvider.LIMIT_ENTRIES;
|
||||
|
||||
const fetchMoreEntries = (): Promise<any[]> => {
|
||||
return this.fetchEntries(fetchFunction, fetchArguments, entries.length, limitNum, omitExpires, forceOffline, siteId)
|
||||
.then((result) => {
|
||||
return this.fetchEntries(fetchFunction, fetchArguments, {
|
||||
from: entries.length,
|
||||
...options, // Include all options.
|
||||
}).then((result) => {
|
||||
Array.prototype.push.apply(entries, result.entries);
|
||||
|
||||
return entries.length < result.count ? fetchMoreEntries() : entries;
|
||||
|
@ -759,8 +755,11 @@ export class AddonModGlossaryProvider {
|
|||
const promises = [];
|
||||
|
||||
if (!onlyEntriesList) {
|
||||
promises.push(this.fetchAllEntries(this.getEntriesByLetter, [glossary.id, 'ALL'], true, false, siteId)
|
||||
.then((entries) => {
|
||||
promises.push(this.fetchAllEntries(this.getEntriesByLetter, [glossary.id, 'ALL'], {
|
||||
cmId: glossary.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId,
|
||||
}).then((entries) => {
|
||||
return this.invalidateEntries(entries, siteId);
|
||||
}));
|
||||
}
|
||||
|
@ -804,11 +803,11 @@ export class AddonModGlossaryProvider {
|
|||
*
|
||||
* @param courseId Course Id.
|
||||
* @param cmId Course Module Id.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the glossary.
|
||||
*/
|
||||
getGlossary(courseId: number, cmId: number, siteId?: string): Promise<any> {
|
||||
return this.getCourseGlossaries(courseId, siteId).then((glossaries) => {
|
||||
getGlossary(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getCourseGlossaries(courseId, options).then((glossaries) => {
|
||||
const glossary = glossaries.find((glossary) => glossary.coursemodule == cmId);
|
||||
|
||||
if (glossary) {
|
||||
|
@ -824,11 +823,11 @@ export class AddonModGlossaryProvider {
|
|||
*
|
||||
* @param courseId Course Id.
|
||||
* @param glossaryId Glossary Id.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the glossary.
|
||||
*/
|
||||
getGlossaryById(courseId: number, glossaryId: number, siteId?: string): Promise<any> {
|
||||
return this.getCourseGlossaries(courseId, siteId).then((glossaries) => {
|
||||
getGlossaryById(courseId: number, glossaryId: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getCourseGlossaries(courseId, options).then((glossaries) => {
|
||||
const glossary = glossaries.find((glossary) => glossary.id == glossaryId);
|
||||
|
||||
if (glossary) {
|
||||
|
@ -846,28 +845,27 @@ export class AddonModGlossaryProvider {
|
|||
* @param concept Glossary entry concept.
|
||||
* @param definition Glossary entry concept definition.
|
||||
* @param courseId Course ID of the glossary.
|
||||
* @param options Array of options for the entry.
|
||||
* @param entryOptions Array of options for the entry.
|
||||
* @param attach Attachments ID if sending online, result of CoreFileUploaderProvider#storeFilesToUpload
|
||||
* otherwise.
|
||||
* @param timeCreated The time the entry was created. If not defined, current time.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param discardEntry The entry provided will be discarded if found.
|
||||
* @param allowOffline True if it can be stored in offline, false otherwise.
|
||||
* @param checkDuplicates Check for duplicates before storing offline. Only used if allowOffline is true.
|
||||
* @param otherOptions Other options.
|
||||
* @return Promise resolved with entry ID if entry was created in server, false if stored in device.
|
||||
*/
|
||||
addEntry(glossaryId: number, concept: string, definition: string, courseId: number, options: any, attach: any,
|
||||
timeCreated: number, siteId?: string, discardEntry?: any, allowOffline?: boolean, checkDuplicates?: boolean):
|
||||
Promise<number | false> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
addEntry(glossaryId: number, concept: string, definition: string, courseId: number, entryOptions: any, attach: any,
|
||||
otherOptions: AddonModGlossaryAddEntryOptions = {}): Promise<number | false> {
|
||||
otherOptions.siteId = otherOptions.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
// Convenience function to store a new entry to be synchronized later.
|
||||
const storeOffline = (): Promise<number | false> => {
|
||||
const discardTime = discardEntry && discardEntry.timecreated;
|
||||
const discardTime = otherOptions.discardEntry && otherOptions.discardEntry.timecreated;
|
||||
|
||||
let duplicatesPromise;
|
||||
if (checkDuplicates) {
|
||||
duplicatesPromise = this.isConceptUsed(glossaryId, concept, discardTime, siteId);
|
||||
if (otherOptions.checkDuplicates) {
|
||||
duplicatesPromise = this.isConceptUsed(glossaryId, concept, {
|
||||
cmId: otherOptions.cmId,
|
||||
timeCreated: discardTime,
|
||||
siteId: otherOptions.siteId,
|
||||
});
|
||||
} else {
|
||||
duplicatesPromise = Promise.resolve(false);
|
||||
}
|
||||
|
@ -878,33 +876,34 @@ export class AddonModGlossaryProvider {
|
|||
return Promise.reject(this.translate.instant('addon.mod_glossary.errconceptalreadyexists'));
|
||||
}
|
||||
|
||||
return this.glossaryOffline.addNewEntry(glossaryId, concept, definition, courseId, attach, options, timeCreated,
|
||||
siteId, undefined, discardEntry).then(() => {
|
||||
return this.glossaryOffline.addNewEntry(glossaryId, concept, definition, courseId, attach, entryOptions,
|
||||
otherOptions.timeCreated, otherOptions.siteId, undefined, otherOptions.discardEntry).then(() => {
|
||||
return false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
if (!this.appProvider.isOnline() && allowOffline) {
|
||||
if (!this.appProvider.isOnline() && otherOptions.allowOffline) {
|
||||
// App is offline, store the action.
|
||||
return storeOffline();
|
||||
}
|
||||
|
||||
// If we are editing an offline entry, discard previous first.
|
||||
let discardPromise;
|
||||
if (discardEntry) {
|
||||
if (otherOptions.discardEntry) {
|
||||
discardPromise = this.glossaryOffline.deleteNewEntry(
|
||||
glossaryId, discardEntry.concept, discardEntry.timecreated, siteId);
|
||||
glossaryId, otherOptions.discardEntry.concept, otherOptions.discardEntry.timecreated, otherOptions.siteId);
|
||||
} else {
|
||||
discardPromise = Promise.resolve();
|
||||
}
|
||||
|
||||
return discardPromise.then(() => {
|
||||
// Try to add it in online.
|
||||
return this.addEntryOnline(glossaryId, concept, definition, options, attach, siteId).then((entryId) => {
|
||||
return this.addEntryOnline(glossaryId, concept, definition, entryOptions, attach, otherOptions.siteId)
|
||||
.then((entryId) => {
|
||||
return entryId;
|
||||
}).catch((error) => {
|
||||
if (allowOffline && !this.utils.isWebServiceError(error)) {
|
||||
if (otherOptions.allowOffline && !this.utils.isWebServiceError(error)) {
|
||||
// Couldn't connect to server, store in offline.
|
||||
return storeOffline();
|
||||
} else {
|
||||
|
@ -964,20 +963,23 @@ export class AddonModGlossaryProvider {
|
|||
*
|
||||
* @param glossaryId Glossary ID.
|
||||
* @param concept Concept to check.
|
||||
* @param timeCreated Timecreated to check that is not the timecreated we are editing.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with true if used, resolved with false if not used or error.
|
||||
*/
|
||||
isConceptUsed(glossaryId: number, concept: string, timeCreated?: number, siteId?: string): Promise<boolean> {
|
||||
isConceptUsed(glossaryId: number, concept: string, options: AddonModGlossaryIsConceptUsedOptions = {}): Promise<boolean> {
|
||||
// Check offline first.
|
||||
return this.glossaryOffline.isConceptUsed(glossaryId, concept, timeCreated, siteId).then((exists) => {
|
||||
return this.glossaryOffline.isConceptUsed(glossaryId, concept, options.timeCreated, options.siteId).then((exists) => {
|
||||
if (exists) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we get here, there's no offline entry with this name, check online.
|
||||
// Get entries from the cache.
|
||||
return this.fetchAllEntries(this.getEntriesByLetter, [glossaryId, 'ALL'], true, false, siteId).then((entries) => {
|
||||
return this.fetchAllEntries(this.getEntriesByLetter, [glossaryId, 'ALL'], {
|
||||
cmId: options.cmId,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId: options.siteId,
|
||||
}).then((entries) => {
|
||||
// Check if there's any entry with the same concept.
|
||||
return entries.some((entry) => entry.concept == concept);
|
||||
});
|
||||
|
@ -1074,3 +1076,40 @@ export class AddonModGlossaryProvider {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to pass to add entry.
|
||||
*/
|
||||
export type AddonModGlossaryAddEntryOptions = {
|
||||
timeCreated?: number; // The time the entry was created. If not defined, current time.
|
||||
discardEntry?: any; // The entry provided will be discarded if found.
|
||||
allowOffline?: boolean; // True if it can be stored in offline, false otherwise.
|
||||
checkDuplicates?: boolean; // Check for duplicates before storing offline. Only used if allowOffline is true.
|
||||
cmId?: number; // Module ID.
|
||||
siteId?: string; // Site ID. If not defined, current site.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to the different get entries functions.
|
||||
*/
|
||||
export type AddonModGlossaryGetEntriesOptions = CoreCourseCommonModWSOptions & {
|
||||
from?: number; // Start returning records from here. Defaults to 0.
|
||||
limit?: number; // Number of records to return. Defaults to AddonModGlossaryProvider.LIMIT_ENTRIES.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to get categories.
|
||||
*/
|
||||
export type AddonModGlossaryGetCategoriesOptions = CoreCourseCommonModWSOptions & {
|
||||
from?: number; // Start returning records from here. Defaults to 0.
|
||||
limit?: number; // Number of records to return. Defaults to AddonModGlossaryProvider.LIMIT_CATEGORIES.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to is concept used.
|
||||
*/
|
||||
export type AddonModGlossaryIsConceptUsedOptions = {
|
||||
cmId?: number; // Module ID.
|
||||
timeCreated?: number; // Timecreated to check that is not the timecreated we are editing.
|
||||
siteId?: string; // Site ID. If not defined, current site.
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
|
@ -66,8 +66,9 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
*/
|
||||
getFiles(module: any, courseId: number, single?: boolean): Promise<any[]> {
|
||||
return this.glossaryProvider.getGlossary(courseId, module.id).then((glossary) => {
|
||||
return this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByLetter, [glossary.id, 'ALL'])
|
||||
.then((entries) => {
|
||||
return this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByLetter, [glossary.id, 'ALL'], {
|
||||
cmId: module.id,
|
||||
}).then((entries) => {
|
||||
return this.getFilesFromGlossaryAndEntries(module, glossary, entries);
|
||||
});
|
||||
}).catch(() => {
|
||||
|
@ -139,8 +140,14 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
protected prefetchGlossary(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const options = {
|
||||
cmId: module.id,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
// Prefetch the glossary data.
|
||||
return this.glossaryProvider.getGlossary(courseId, module.id, siteId).then((glossary) => {
|
||||
return this.glossaryProvider.getGlossary(courseId, module.id, {siteId}).then((glossary) => {
|
||||
const promises = [];
|
||||
|
||||
glossary.browsemodes.forEach((mode) => {
|
||||
|
@ -149,25 +156,25 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
break;
|
||||
case 'cat': // Not implemented.
|
||||
promises.push(this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByCategory,
|
||||
[glossary.id, AddonModGlossaryProvider.SHOW_ALL_CATEGORIES], false, false, siteId));
|
||||
[glossary.id, AddonModGlossaryProvider.SHOW_ALL_CATEGORIES], options));
|
||||
break;
|
||||
case 'date':
|
||||
promises.push(this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByDate,
|
||||
[glossary.id, 'CREATION', 'DESC'], false, false, siteId));
|
||||
[glossary.id, 'CREATION', 'DESC'], options));
|
||||
promises.push(this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByDate,
|
||||
[glossary.id, 'UPDATE', 'DESC'], false, false, siteId));
|
||||
[glossary.id, 'UPDATE', 'DESC'], options));
|
||||
break;
|
||||
case 'author':
|
||||
promises.push(this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByAuthor,
|
||||
[glossary.id, 'ALL', 'LASTNAME', 'ASC'], false, false, siteId));
|
||||
[glossary.id, 'ALL', 'LASTNAME', 'ASC'], options));
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
// Fetch all entries to get information from.
|
||||
promises.push(this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByLetter,
|
||||
[glossary.id, 'ALL'], false, false, siteId).then((entries) => {
|
||||
promises.push(this.glossaryProvider.fetchAllEntries(this.glossaryProvider.getEntriesByLetter, [glossary.id, 'ALL'],
|
||||
options).then((entries) => {
|
||||
const promises = [];
|
||||
const commentsEnabled = !this.commentsProvider.areCommentsDisabledInSite();
|
||||
|
||||
|
@ -190,7 +197,7 @@ export class AddonModGlossaryPrefetchHandler extends CoreCourseActivityPrefetchH
|
|||
}));
|
||||
|
||||
// Get all categories.
|
||||
promises.push(this.glossaryProvider.getAllCategories(glossary.id, siteId));
|
||||
promises.push(this.glossaryProvider.getAllCategories(glossary.id, options));
|
||||
|
||||
// Prefetch data for link handlers.
|
||||
promises.push(this.courseProvider.getModuleBasicInfo(module.id, siteId));
|
||||
|
|
|
@ -281,7 +281,7 @@ export class AddonModGlossarySyncProvider extends CoreSyncBaseProvider {
|
|||
});
|
||||
}
|
||||
if (result.warnings.length) {
|
||||
promises.push(this.glossaryProvider.getGlossary(result.itemSet.courseId, result.itemSet.instanceId, siteId)
|
||||
promises.push(this.glossaryProvider.getGlossary(result.itemSet.courseId, result.itemSet.instanceId, {siteId})
|
||||
.then((glossary) => {
|
||||
result.warnings.forEach((warning) => {
|
||||
warnings.push(this.translate.instant('core.warningofflinedatadeleted', {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -108,7 +108,9 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
|||
*/
|
||||
protected async fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<void> {
|
||||
try {
|
||||
this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivity(this.courseId, this.module.id, false, this.siteId);
|
||||
this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivity(this.courseId, this.module.id, {
|
||||
siteId: this.siteId,
|
||||
});
|
||||
|
||||
this.dataRetrieved.emit(this.h5pActivity);
|
||||
this.description = this.h5pActivity.intro;
|
||||
|
@ -161,7 +163,10 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchAccessInfo(): Promise<void> {
|
||||
this.accessInfo = await AddonModH5PActivity.instance.getAccessInformation(this.h5pActivity.id, false, this.siteId);
|
||||
this.accessInfo = await AddonModH5PActivity.instance.getAccessInformation(this.h5pActivity.id, {
|
||||
cmId: this.module.id,
|
||||
siteId: this.siteId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -77,32 +77,15 @@ export class AddonModH5PActivityAttemptResultsPage implements OnInit {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchData(): Promise<void> {
|
||||
await Promise.all([
|
||||
this.fetchActivity(),
|
||||
this.fetchAttempt(),
|
||||
]);
|
||||
this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivityById(this.courseId, this.h5pActivityId);
|
||||
|
||||
this.attempt = await AddonModH5PActivity.instance.getAttemptResults(this.h5pActivityId, this.attemptId, {
|
||||
cmId: this.h5pActivity.coursemodule,
|
||||
});
|
||||
|
||||
await this.fetchUserProfile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get activity data.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchActivity(): Promise<void> {
|
||||
this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivityById(this.courseId, this.h5pActivityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attempts.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchAttempt(): Promise<void> {
|
||||
this.attempt = await AddonModH5PActivity.instance.getAttemptResults(this.h5pActivityId, this.attemptId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user profile.
|
||||
*
|
||||
|
|
|
@ -79,29 +79,24 @@ export class AddonModH5PActivityUserAttemptsPage implements OnInit {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchData(): Promise<void> {
|
||||
this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivityById(this.courseId, this.h5pActivityId);
|
||||
|
||||
await Promise.all([
|
||||
this.fetchActivity(),
|
||||
this.fetchAttempts(),
|
||||
this.fetchUserProfile(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get activity data.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchActivity(): Promise<void> {
|
||||
this.h5pActivity = await AddonModH5PActivity.instance.getH5PActivityById(this.courseId, this.h5pActivityId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attempts.
|
||||
*
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected async fetchAttempts(): Promise<void> {
|
||||
this.attemptsData = await AddonModH5PActivity.instance.getUserAttempts(this.h5pActivityId, { userId: this.userId });
|
||||
this.attemptsData = await AddonModH5PActivity.instance.getUserAttempts(this.h5pActivityId, {
|
||||
cmId: this.h5pActivity.coursemodule,
|
||||
userId: this.userId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,14 +14,15 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { CoreSites } from '@providers/sites';
|
||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } 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 { CoreSite } from '@classes/site';
|
||||
import { CoreCourseLogHelper } from '@core/course/providers/log-helper';
|
||||
import { CoreH5P } from '@core/h5p/providers/h5p';
|
||||
import { CoreH5PDisplayOptions } from '@core/h5p/classes/core';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
import { makeSingleton, Translate } from '@singletons/core.singletons';
|
||||
|
||||
|
@ -121,20 +122,22 @@ export class AddonModH5PActivityProvider {
|
|||
* Get access information for a given H5P activity.
|
||||
*
|
||||
* @param id H5P activity ID.
|
||||
* @param forceCache True to always get the value from cache. false otherwise.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the data.
|
||||
*/
|
||||
async getAccessInformation(id: number, forceCache?: boolean, siteId?: string): Promise<AddonModH5PActivityAccessInfo> {
|
||||
async getAccessInformation(id: number, options: CoreCourseCommonModWSOptions = {}): Promise<AddonModH5PActivityAccessInfo> {
|
||||
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
const site = await CoreSites.instance.getSite(options.siteId);
|
||||
|
||||
const params = {
|
||||
h5pactivityid: id,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAccessInformationCacheKey(id),
|
||||
omitExpires: forceCache,
|
||||
updateFrequency: CoreSite.FREQUENCY_OFTEN,
|
||||
component: AddonModH5PActivityProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_h5pactivity_get_h5pactivity_access_information', params, preSets);
|
||||
|
@ -209,18 +212,14 @@ export class AddonModH5PActivityProvider {
|
|||
h5pactivityid: id,
|
||||
attemptids: [attemptId],
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getAttemptResultsCacheKey(id, params.attemptids),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModH5PActivityProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
|
@ -235,9 +234,12 @@ export class AddonModH5PActivityProvider {
|
|||
}
|
||||
|
||||
// Check if the full list of results is cached. If so, get the results from there.
|
||||
options.forceCache = true;
|
||||
const cacheOptions = {
|
||||
...options, // Include all the original options.
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyCache,
|
||||
};
|
||||
|
||||
const attemptsResults = await AddonModH5PActivity.instance.getAllAttemptsResults(id, options);
|
||||
const attemptsResults = await AddonModH5PActivity.instance.getAllAttemptsResults(id, cacheOptions);
|
||||
|
||||
const attempt = attemptsResults.attempts.find((attempt) => {
|
||||
return attempt.id == attemptId;
|
||||
|
@ -270,18 +272,14 @@ export class AddonModH5PActivityProvider {
|
|||
h5pactivityid: id,
|
||||
attemptids: attemptsIds,
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getAttemptResultsCommonCacheKey(id),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModH5PActivityProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
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) => {
|
||||
|
@ -334,28 +332,24 @@ export class AddonModH5PActivityProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param moduleUrl Module URL.
|
||||
* @param forceCache Whether it should always return cached data.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the activity data.
|
||||
*/
|
||||
protected async getH5PActivityByField(courseId: number, key: string, value: any, forceCache?: boolean, siteId?: string)
|
||||
protected async getH5PActivityByField(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModH5PActivityData> {
|
||||
|
||||
const site = await CoreSites.instance.getSite(siteId);
|
||||
const site = await CoreSites.instance.getSite(options.siteId);
|
||||
|
||||
const params = {
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getH5PActivityDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModH5PActivityProvider.COMPONENT,
|
||||
...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
if (forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
}
|
||||
|
||||
const response: AddonModH5PActivityGetByCoursesResult =
|
||||
await site.read('mod_h5pactivity_get_h5pactivities_by_courses', params, preSets);
|
||||
|
||||
|
@ -377,12 +371,11 @@ export class AddonModH5PActivityProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param forceCache Whether it should always return cached data.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the activity data.
|
||||
*/
|
||||
getH5PActivity(courseId: number, cmId: number, forceCache?: boolean, siteId?: string): Promise<AddonModH5PActivityData> {
|
||||
return this.getH5PActivityByField(courseId, 'coursemodule', cmId, forceCache, siteId);
|
||||
getH5PActivity(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModH5PActivityData> {
|
||||
return this.getH5PActivityByField(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -390,13 +383,12 @@ export class AddonModH5PActivityProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param contextId Context ID.
|
||||
* @param forceCache Whether it should always return cached data.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the activity data.
|
||||
*/
|
||||
getH5PActivityByContextId(courseId: number, contextId: number, forceCache?: boolean, siteId?: string)
|
||||
getH5PActivityByContextId(courseId: number, contextId: number, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModH5PActivityData> {
|
||||
return this.getH5PActivityByField(courseId, 'context', contextId, forceCache, siteId);
|
||||
return this.getH5PActivityByField(courseId, 'context', contextId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -404,12 +396,11 @@ export class AddonModH5PActivityProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param id Instance ID.
|
||||
* @param forceCache Whether it should always return cached data.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the activity data.
|
||||
*/
|
||||
getH5PActivityById(courseId: number, id: number, forceCache?: boolean, siteId?: string): Promise<AddonModH5PActivityData> {
|
||||
return this.getH5PActivityByField(courseId, 'id', id, forceCache, siteId);
|
||||
getH5PActivityById(courseId: number, id: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModH5PActivityData> {
|
||||
return this.getH5PActivityByField(courseId, 'id', id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -440,9 +431,8 @@ export class AddonModH5PActivityProvider {
|
|||
* @param options Other options.
|
||||
* @return Promise resolved with the attempts of the user.
|
||||
*/
|
||||
async getUserAttempts(id: number, options?: AddonModH5PActivityGetAttemptsOptions): Promise<AddonModH5PActivityUserAttempts> {
|
||||
|
||||
options = options || {};
|
||||
async getUserAttempts(id: number, options: AddonModH5PActivityGetAttemptsOptions = {})
|
||||
: Promise<AddonModH5PActivityUserAttempts> {
|
||||
|
||||
const site = await CoreSites.instance.getSite(options.siteId);
|
||||
|
||||
|
@ -450,18 +440,14 @@ export class AddonModH5PActivityProvider {
|
|||
h5pactivityid: id,
|
||||
userids: [options.userId || site.getUserId()],
|
||||
};
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
const preSets = {
|
||||
cacheKey: this.getUserAttemptsCacheKey(id, params.userids),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModH5PActivityProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...CoreSites.instance.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
if (options.forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (options.ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
|
||||
const response: AddonModH5PActivityGetAttemptsResult = await site.read('mod_h5pactivity_get_attempts', params, preSets);
|
||||
|
||||
if (response.warnings[0]) {
|
||||
|
@ -789,10 +775,7 @@ export type AddonModH5PActivityGetDeployedFileOptions = {
|
|||
/**
|
||||
* Options to pass to getAttemptResults function.
|
||||
*/
|
||||
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.
|
||||
export type AddonModH5PActivityGetAttemptResultsOptions = CoreCourseCommonModWSOptions & {
|
||||
userId?: number; // User ID. If not defined, user of the site.
|
||||
};
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CorePluginFileDelegate } from '@providers/plugin-file-delegate';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreWSExternalFile } from '@providers/ws';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
|
@ -130,7 +130,10 @@ export class AddonModH5PActivityPrefetchHandler extends CoreCourseActivityPrefet
|
|||
*/
|
||||
protected async prefetchActivity(module: any, courseId: number, single: boolean, siteId: string): Promise<void> {
|
||||
|
||||
const h5pActivity = await AddonModH5PActivity.instance.getH5PActivity(courseId, module.id, true, siteId);
|
||||
const h5pActivity = await AddonModH5PActivity.instance.getH5PActivity(courseId, module.id, {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
});
|
||||
|
||||
const introFiles = this.getIntroFilesFromInstance(module, h5pActivity);
|
||||
|
||||
|
@ -171,14 +174,19 @@ export class AddonModH5PActivityPrefetchHandler extends CoreCourseActivityPrefet
|
|||
*/
|
||||
protected async prefetchWSData(h5pActivity: AddonModH5PActivityData, siteId: string): Promise<void> {
|
||||
|
||||
const accessInfo = await AddonModH5PActivity.instance.getAccessInformation(h5pActivity.id, true, siteId);
|
||||
const accessInfo = await AddonModH5PActivity.instance.getAccessInformation(h5pActivity.id, {
|
||||
cmId: h5pActivity.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
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,
|
||||
cmId: h5pActivity.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId: siteId,
|
||||
};
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ export class AddonModH5PActivitySyncProvider extends CoreCourseActivitySyncBaseP
|
|||
// Get the activity instance.
|
||||
const courseId = entries[0].courseid;
|
||||
|
||||
const h5pActivity = await AddonModH5PActivity.instance.getH5PActivityByContextId(courseId, contextId, false, siteId);
|
||||
const h5pActivity = await AddonModH5PActivity.instance.getH5PActivityByContextId(courseId, contextId, {siteId});
|
||||
|
||||
// Sync offline logs.
|
||||
try {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
|
||||
<core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
|
@ -155,17 +155,21 @@ export class AddonModImscpProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the imscp is retrieved.
|
||||
*/
|
||||
protected getImscpByKey(courseId: number, key: string, value: any, siteId?: string): Promise<AddonModImscpImscp> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
protected getImscpByKey(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModImscpImscp> {
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getImscpDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModImscpProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_imscp_get_imscps_by_courses', params, preSets)
|
||||
|
@ -188,11 +192,11 @@ export class AddonModImscpProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the imscp is retrieved.
|
||||
*/
|
||||
getImscp(courseId: number, cmId: number, siteId?: string): Promise<AddonModImscpImscp> {
|
||||
return this.getImscpByKey(courseId, 'coursemodule', cmId, siteId);
|
||||
getImscp(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModImscpImscp> {
|
||||
return this.getImscpByKey(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
|
@ -67,7 +67,10 @@ export class AddonModImscpPrefetchHandler extends CoreCourseResourcePrefetchHand
|
|||
const promises = [];
|
||||
|
||||
promises.push(super.downloadOrPrefetch(module, courseId, prefetch, dirPath));
|
||||
promises.push(this.imscpProvider.getImscp(courseId, module.id, siteId));
|
||||
promises.push(this.imscpProvider.getImscp(courseId, module.id, {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
}));
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
|
|
|
@ -13,10 +13,10 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
|
||||
|
||||
/**
|
||||
|
@ -47,29 +47,22 @@ export class AddonModLabelProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param forceCache True to always get the value from cache, false otherwise.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not provided, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the label is retrieved.
|
||||
*/
|
||||
protected getLabelByField(courseId: number, key: string, value: any, forceCache?: boolean, ignoreCache?: boolean,
|
||||
siteId?: string): Promise<AddonModLabelLabel> {
|
||||
protected getLabelByField(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModLabelLabel> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getLabelDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
if (forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getLabelDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModLabelProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_label_get_labels_by_courses', params, preSets)
|
||||
.then((response: AddonModLabelGetLabelsByCoursesResult): any => {
|
||||
|
@ -91,14 +84,11 @@ export class AddonModLabelProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param forceCache True to always get the value from cache, false otherwise.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the label is retrieved.
|
||||
*/
|
||||
getLabel(courseId: number, cmId: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string)
|
||||
: Promise<AddonModLabelLabel> {
|
||||
return this.getLabelByField(courseId, 'coursemodule', cmId, forceCache, ignoreCache, siteId);
|
||||
getLabel(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModLabelLabel> {
|
||||
return this.getLabelByField(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,14 +96,11 @@ export class AddonModLabelProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param labelId Label ID.
|
||||
* @param forceCache True to always get the value from cache, false otherwise.
|
||||
* @param ignoreCache True if it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the label is retrieved.
|
||||
*/
|
||||
getLabelById(courseId: number, labelId: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string)
|
||||
: Promise<AddonModLabelLabel> {
|
||||
return this.getLabelByField(courseId, 'id', labelId, forceCache, ignoreCache, siteId);
|
||||
getLabelById(courseId: number, labelId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModLabelLabel> {
|
||||
return this.getLabelByField(courseId, 'id', labelId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
|
@ -63,7 +63,9 @@ export class AddonModLabelPrefetchHandler extends CoreCourseResourcePrefetchHand
|
|||
let promise;
|
||||
|
||||
if (this.labelProvider.isGetLabelAvailableForSite()) {
|
||||
promise = this.labelProvider.getLabel(courseId, module.id, false, ignoreCache);
|
||||
promise = this.labelProvider.getLabel(courseId, module.id, {
|
||||
readingStrategy: ignoreCache ? CoreSitesReadingStrategy.OnlyNetwork : undefined
|
||||
});
|
||||
} else {
|
||||
promise = Promise.resolve();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
|
||||
let lessonReady = true;
|
||||
this.askPassword = false;
|
||||
const options = {cmId: this.module.id};
|
||||
|
||||
return this.lessonProvider.getLesson(this.courseId, this.module.id).then((lessonData) => {
|
||||
this.lesson = lessonData;
|
||||
|
@ -130,7 +131,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
return this.syncActivity(showErrors);
|
||||
}
|
||||
}).then(() => {
|
||||
return this.lessonProvider.getAccessInformation(this.lesson.id);
|
||||
return this.lessonProvider.getAccessInformation(this.lesson.id, options);
|
||||
}).then((info) => {
|
||||
const promises = [];
|
||||
|
||||
|
@ -167,8 +168,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
}));
|
||||
|
||||
// Update the list of content pages viewed and question attempts.
|
||||
promises.push(this.lessonProvider.getContentPagesViewedOnline(this.lesson.id, info.attemptscount));
|
||||
promises.push(this.lessonProvider.getQuestionsAttemptsOnline(this.lesson.id, info.attemptscount));
|
||||
promises.push(this.lessonProvider.getContentPagesViewedOnline(this.lesson.id, info.attemptscount, options));
|
||||
promises.push(this.lessonProvider.getQuestionsAttemptsOnline(this.lesson.id, info.attemptscount, options));
|
||||
}
|
||||
|
||||
if (info.preventaccessreasons && info.preventaccessreasons.length) {
|
||||
|
@ -364,7 +365,9 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
|
||||
if (this.hasOffline) {
|
||||
if (continueLast) {
|
||||
promise = this.lessonProvider.getLastPageSeen(this.lesson.id, this.accessInfo.attemptscount);
|
||||
promise = this.lessonProvider.getLastPageSeen(this.lesson.id, this.accessInfo.attemptscount, {
|
||||
cmId: this.module.id,
|
||||
});
|
||||
} else {
|
||||
promise = Promise.resolve(this.accessInfo.firstpageid);
|
||||
}
|
||||
|
@ -445,7 +448,10 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
}
|
||||
|
||||
// Get the overview of retakes for the group.
|
||||
return this.lessonProvider.getRetakesOverview(this.lesson.id, groupId).then((data) => {
|
||||
return this.lessonProvider.getRetakesOverview(this.lesson.id, {
|
||||
groupId,
|
||||
cmId: this.lesson.coursemodule,
|
||||
}).then((data) => {
|
||||
const promises = [];
|
||||
|
||||
// Format times and grades.
|
||||
|
@ -617,7 +623,7 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected validatePassword(password: string): Promise<any> {
|
||||
return this.lessonProvider.getLessonWithPassword(this.lesson.id, password).then((lessonData) => {
|
||||
return this.lessonProvider.getLessonWithPassword(this.lesson.id, {password, cmId: this.module.id}).then((lessonData) => {
|
||||
this.lesson = lessonData;
|
||||
this.password = password;
|
||||
}).catch((error) => {
|
||||
|
|
|
@ -18,7 +18,7 @@ import { IonicPage, NavParams, Content, PopoverController, ModalController, Moda
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
@ -172,11 +172,10 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
*
|
||||
* @param func Function to call.
|
||||
* @param args Arguments to pass to the function.
|
||||
* @param offlineParamPos Position of the offline parameter in the args.
|
||||
* @param jumpsParamPos Position of the jumps parameter in the args.
|
||||
* @param options Options passed to the function (also included in args).
|
||||
* @return Promise resolved in success, rejected otherwise.
|
||||
*/
|
||||
protected callFunction(func: Function, args: any[], offlineParamPos: number, jumpsParamPos?: number): Promise<any> {
|
||||
protected callFunction(func: Function, args: any[], options: any): Promise<any> {
|
||||
return func.apply(func, args).catch((error) => {
|
||||
if (!this.offline && !this.review && this.lessonProvider.isLessonOffline(this.lesson) &&
|
||||
!this.utils.isWebServiceError(error)) {
|
||||
|
@ -184,14 +183,16 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
this.offline = true;
|
||||
|
||||
// Get the possible jumps now.
|
||||
return this.lessonProvider.getPagesPossibleJumps(this.lesson.id, true).then((jumpList) => {
|
||||
return this.lessonProvider.getPagesPossibleJumps(this.lesson.id, {
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
}).then((jumpList) => {
|
||||
this.jumps = jumpList;
|
||||
|
||||
// Call the function again with offline set to true and the new jumps.
|
||||
args[offlineParamPos] = true;
|
||||
if (typeof jumpsParamPos != 'undefined') {
|
||||
args[jumpsParamPos] = this.jumps;
|
||||
}
|
||||
// Call the function again with offline mode and the new jumps.
|
||||
options.readingStrategy = CoreSitesReadingStrategy.PreferCache;
|
||||
options.jumps = this.jumps;
|
||||
options.offline = true;
|
||||
|
||||
return func.apply(func, args);
|
||||
});
|
||||
|
@ -246,8 +247,13 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
this.offline = true;
|
||||
}
|
||||
|
||||
const options = {
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
|
||||
return this.callFunction(this.lessonProvider.getAccessInformation.bind(this.lessonProvider),
|
||||
[this.lesson.id, this.offline, true], 1);
|
||||
[this.lesson.id, options], options);
|
||||
}).then((info) => {
|
||||
const promises = [];
|
||||
|
||||
|
@ -272,15 +278,23 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
|
||||
if (this.password) {
|
||||
// Lesson uses password, get the whole lesson object.
|
||||
const options = {
|
||||
password: this.password,
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
promises.push(this.callFunction(this.lessonProvider.getLessonWithPassword.bind(this.lessonProvider),
|
||||
[this.lesson.id, this.password, true, this.offline, true], 3).then((lesson) => {
|
||||
[this.lesson.id, options], options).then((lesson) => {
|
||||
this.lesson = lesson;
|
||||
}));
|
||||
}
|
||||
|
||||
if (this.offline) {
|
||||
// Offline mode, get the list of possible jumps to allow navigation.
|
||||
promises.push(this.lessonProvider.getPagesPossibleJumps(this.lesson.id, true).then((jumpList) => {
|
||||
promises.push(this.lessonProvider.getPagesPossibleJumps(this.lesson.id, {
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
}).then((jumpList) => {
|
||||
this.jumps = jumpList;
|
||||
}));
|
||||
}
|
||||
|
@ -334,7 +348,9 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
const error = result.warnings[0];
|
||||
|
||||
// Some data was deleted. Check if the retake has changed.
|
||||
return this.lessonProvider.getAccessInformation(this.lesson.id).then((info) => {
|
||||
return this.lessonProvider.getAccessInformation(this.lesson.id, {
|
||||
cmId: this.lesson.coursemodule,
|
||||
}).then((info) => {
|
||||
if (info.attemptscount != this.accessInfo.attemptscount) {
|
||||
// The retake has changed. Leave the view and show the error.
|
||||
this.forceLeave = true;
|
||||
|
@ -359,9 +375,16 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
|
||||
return promise.then(() => {
|
||||
// Now finish the retake.
|
||||
const args = [this.lesson, this.courseId, this.password, outOfTime, this.review, this.offline, this.accessInfo];
|
||||
const options = {
|
||||
password: this.password,
|
||||
outOfTime,
|
||||
review: this.review,
|
||||
offline: this.offline,
|
||||
accessInfo: this.accessInfo,
|
||||
};
|
||||
const args = [this.lesson, this.courseId, options];
|
||||
|
||||
return this.callFunction(this.lessonProvider.finishRetake.bind(this.lessonProvider), args, 5);
|
||||
return this.callFunction(this.lessonProvider.finishRetake.bind(this.lessonProvider), args, options);
|
||||
}).then((data) => {
|
||||
this.title = this.lesson.name;
|
||||
this.eolData = data.data;
|
||||
|
@ -447,7 +470,10 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
|
||||
if (this.lesson.timelimit && !this.accessInfo.canmanage) {
|
||||
// Get the last lesson timer.
|
||||
return this.lessonProvider.getTimers(this.lesson.id, false, true).then((timers) => {
|
||||
return this.lessonProvider.getTimers(this.lesson.id, {
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).then((timers) => {
|
||||
this.endTime = timers[timers.length - 1].starttime + this.lesson.timelimit;
|
||||
});
|
||||
}
|
||||
|
@ -469,9 +495,14 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
|
||||
this.loadingMenu = true;
|
||||
|
||||
const args = [this.lessonId, this.password, this.offline, true];
|
||||
const options = {
|
||||
password: this.password,
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
const args = [this.lessonId, options];
|
||||
|
||||
return this.callFunction(this.lessonProvider.getPages.bind(this.lessonProvider), args, 2).then((pages) => {
|
||||
return this.callFunction(this.lessonProvider.getPages.bind(this.lessonProvider), args, options).then((pages) => {
|
||||
this.lessonPages = pages.map((entry) => {
|
||||
return entry.page;
|
||||
});
|
||||
|
@ -494,9 +525,18 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
return this.finishRetake();
|
||||
}
|
||||
|
||||
const args = [this.lesson, pageId, this.password, this.review, true, this.offline, true, this.accessInfo, this.jumps];
|
||||
const options = {
|
||||
password: this.password,
|
||||
review: this.review,
|
||||
inludeContents: true,
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
accessInfo: this.accessInfo,
|
||||
jumps: this.jumps,
|
||||
};
|
||||
const args = [this.lesson, pageId, options];
|
||||
|
||||
return this.callFunction(this.lessonProvider.getPageData.bind(this.lessonProvider), args, 5, 8).then((data) => {
|
||||
return this.callFunction(this.lessonProvider.getPageData.bind(this.lessonProvider), args, options).then((data) => {
|
||||
if (data.newpageid == AddonModLessonProvider.LESSON_EOL) {
|
||||
// End of lesson reached.
|
||||
return this.finishRetake();
|
||||
|
@ -548,10 +588,16 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
protected processPage(data: any, formSubmitted?: boolean): Promise<any> {
|
||||
this.loaded = false;
|
||||
|
||||
const args = [this.lesson, this.courseId, this.pageData, data, this.password, this.review, this.offline, this.accessInfo,
|
||||
this.jumps];
|
||||
const options = {
|
||||
password: this.password,
|
||||
review: this.review,
|
||||
offline: this.offline,
|
||||
accessInfo: this.accessInfo,
|
||||
jumps: this.jumps,
|
||||
};
|
||||
const args = [this.lesson, this.courseId, this.pageData, data, options];
|
||||
|
||||
return this.callFunction(this.lessonProvider.processPage.bind(this.lessonProvider), args, 6, 8).then((result) => {
|
||||
return this.callFunction(this.lessonProvider.processPage.bind(this.lessonProvider), args, options).then((result) => {
|
||||
if (formSubmitted) {
|
||||
this.domUtils.triggerFormSubmittedEvent(this.formElement, result.sent, this.sitesProvider.getCurrentSiteId());
|
||||
}
|
||||
|
@ -559,11 +605,15 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy {
|
|||
if (!this.offline && !this.review && this.lessonProvider.isLessonOffline(this.lesson)) {
|
||||
// Lesson allows offline and the user changed some data in server. Update cached data.
|
||||
const retake = this.accessInfo.attemptscount;
|
||||
const options = {
|
||||
cmId: this.lesson.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
};
|
||||
|
||||
if (this.lessonProvider.isQuestionPage(this.pageData.page.type)) {
|
||||
this.lessonProvider.getQuestionsAttemptsOnline(this.lessonId, retake, false, undefined, false, true);
|
||||
this.lessonProvider.getQuestionsAttemptsOnline(this.lessonId, retake, options);
|
||||
} else {
|
||||
this.lessonProvider.getContentPagesViewedOnline(this.lessonId, retake, false, true);
|
||||
this.lessonProvider.getContentPagesViewedOnline(this.lessonId, retake, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,9 @@ export class AddonModLessonUserRetakePage implements OnInit {
|
|||
this.lesson = lessonData;
|
||||
|
||||
// Get the retakes overview for all participants.
|
||||
return this.lessonProvider.getRetakesOverview(this.lesson.id);
|
||||
return this.lessonProvider.getRetakesOverview(this.lesson.id, {
|
||||
cmId: this.lesson.coursemodule,
|
||||
});
|
||||
}).then((data) => {
|
||||
// Search the student.
|
||||
let student;
|
||||
|
@ -193,7 +195,10 @@ export class AddonModLessonUserRetakePage implements OnInit {
|
|||
protected setRetake(retakeNumber: number): Promise<any> {
|
||||
this.selectedRetake = retakeNumber;
|
||||
|
||||
return this.lessonProvider.getUserRetake(this.lessonId, retakeNumber, this.userId).then((data) => {
|
||||
return this.lessonProvider.getUserRetake(this.lessonId, retakeNumber, {
|
||||
cmId: this.lesson.coursemodule,
|
||||
userId: this.userId,
|
||||
}).then((data) => {
|
||||
|
||||
if (data && data.completed != -1) {
|
||||
// Completed.
|
||||
|
|
|
@ -57,7 +57,7 @@ export class AddonModLessonGradeLinkHandler extends CoreContentLinksModuleGradeH
|
|||
courseId = module.course || courseId || params.courseid || params.cid;
|
||||
|
||||
// Check if the user can see the user reports in the lesson.
|
||||
return this.lessonProvider.getAccessInformation(module.instance);
|
||||
return this.lessonProvider.getAccessInformation(module.instance, {cmId: module.id, siteId});
|
||||
}).then((info) => {
|
||||
if (info.canviewreports) {
|
||||
// User can view reports, go to view the report.
|
||||
|
|
|
@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSiteSchema, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
@ -292,10 +292,14 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
|
|||
courseId = attempts[0].courseid;
|
||||
|
||||
// Get the info, access info and the lesson password if needed.
|
||||
return this.lessonProvider.getLessonById(courseId, lessonId, false, false, siteId).then((lessonData) => {
|
||||
return this.lessonProvider.getLessonById(courseId, lessonId, {siteId}).then((lessonData) => {
|
||||
lesson = lessonData;
|
||||
|
||||
return this.prefetchHandler.getLessonPassword(lessonId, false, true, askPassword, siteId);
|
||||
return this.prefetchHandler.getLessonPassword(lessonId, {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
askPassword,
|
||||
siteId,
|
||||
});
|
||||
}).then((data) => {
|
||||
const attemptsLength = attempts.length,
|
||||
promises = [];
|
||||
|
@ -368,10 +372,14 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
|
|||
// Data already retrieved when syncing attempts.
|
||||
promise = Promise.resolve();
|
||||
} else {
|
||||
promise = this.lessonProvider.getLessonById(courseId, lessonId, false, false, siteId).then((lessonData) => {
|
||||
promise = this.lessonProvider.getLessonById(courseId, lessonId, {siteId}).then((lessonData) => {
|
||||
lesson = lessonData;
|
||||
|
||||
return this.prefetchHandler.getLessonPassword(lessonId, false, true, askPassword, siteId);
|
||||
return this.prefetchHandler.getLessonPassword(lessonId, {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
askPassword,
|
||||
siteId,
|
||||
});
|
||||
}).then((data) => {
|
||||
accessInfo = data.accessInfo;
|
||||
password = data.password;
|
||||
|
@ -394,7 +402,7 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
|
|||
}
|
||||
|
||||
// All good, finish the retake.
|
||||
return this.lessonProvider.finishRetakeOnline(lessonId, password, false, false, siteId).then((response) => {
|
||||
return this.lessonProvider.finishRetakeOnline(lessonId, {password, siteId}).then((response) => {
|
||||
result.updated = true;
|
||||
|
||||
if (!ignoreBlock) {
|
||||
|
@ -466,7 +474,10 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
|
|||
protected sendAttempt(lesson: any, password: string, attempt: any, result: AddonModLessonSyncResult, siteId?: string)
|
||||
: Promise<any> {
|
||||
|
||||
return this.lessonProvider.processPageOnline(lesson.id, attempt.pageid, attempt.data, password, false, siteId).then(() => {
|
||||
return this.lessonProvider.processPageOnline(lesson.id, attempt.pageid, attempt.data, {
|
||||
password,
|
||||
siteId,
|
||||
}).then(() => {
|
||||
result.updated = true;
|
||||
|
||||
return this.lessonOfflineProvider.deleteAttempt(lesson.id, attempt.retake, attempt.pageid, attempt.timemodified,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,10 +17,10 @@ import { ModalController } from 'ionic-angular';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseProvider, CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
import { CoreGroupsProvider } from '@providers/groups';
|
||||
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
|
||||
import { AddonModLessonProvider } from './lesson';
|
||||
|
@ -98,11 +98,15 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
password,
|
||||
result;
|
||||
|
||||
return this.lessonProvider.getLesson(courseId, module.id, false, false, siteId).then((lessonData) => {
|
||||
return this.lessonProvider.getLesson(courseId, module.id, {siteId}).then((lessonData) => {
|
||||
lesson = lessonData;
|
||||
|
||||
// Get the lesson password if it's needed.
|
||||
return this.getLessonPassword(lesson.id, false, true, single, siteId);
|
||||
return this.getLessonPassword(lesson.id, {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
askPassword: single,
|
||||
siteId,
|
||||
});
|
||||
}).then((data) => {
|
||||
password = data.password;
|
||||
lesson = data.lesson || lesson;
|
||||
|
@ -116,7 +120,11 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
result = res;
|
||||
|
||||
// Get the pages to calculate the size.
|
||||
return this.lessonProvider.getPages(lesson.id, password, false, false, siteId);
|
||||
return this.lessonProvider.getPages(lesson.id, {
|
||||
cmId: module.id,
|
||||
password,
|
||||
siteId,
|
||||
});
|
||||
}).then((pages) => {
|
||||
pages.forEach((page) => {
|
||||
result.size += page.filessizetotal;
|
||||
|
@ -130,19 +138,16 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
* Get the lesson password if needed. If not stored, it can ask the user to enter it.
|
||||
*
|
||||
* @param lessonId Lesson ID.
|
||||
* @param forceCache Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param askPassword True if we should ask for password if needed, false otherwise.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
getLessonPassword(lessonId: number, forceCache?: boolean, ignoreCache?: boolean, askPassword?: boolean, siteId?: string)
|
||||
getLessonPassword(lessonId: number, options: AddonModLessonGetPasswordOptions = {})
|
||||
: Promise<{password?: string, lesson?: any, accessInfo: any}> {
|
||||
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
// Get access information to check if password is needed.
|
||||
return this.lessonProvider.getAccessInformation(lessonId, forceCache, ignoreCache, siteId).then((info): any => {
|
||||
return this.lessonProvider.getAccessInformation(lessonId, options).then((info): any => {
|
||||
if (info.preventaccessreasons && info.preventaccessreasons.length) {
|
||||
const passwordNeeded = info.preventaccessreasons.length == 1 && this.lessonProvider.isPasswordProtected(info);
|
||||
if (passwordNeeded) {
|
||||
|
@ -152,15 +157,15 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
// No password found.
|
||||
}).then((password) => {
|
||||
if (password) {
|
||||
return this.validatePassword(lessonId, info, password, forceCache, ignoreCache, siteId);
|
||||
return this.validatePassword(lessonId, info, password, options);
|
||||
} else {
|
||||
return Promise.reject(null);
|
||||
}
|
||||
}).catch(() => {
|
||||
// No password or error validating it. Ask for it if allowed.
|
||||
if (askPassword) {
|
||||
if (options.askPassword) {
|
||||
return this.askUserPassword(info).then((password) => {
|
||||
return this.validatePassword(lessonId, info, password, forceCache, ignoreCache, siteId);
|
||||
return this.validatePassword(lessonId, info, password, options);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -207,7 +212,10 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
// Invalidate data to determine if module is downloadable.
|
||||
return this.lessonProvider.getLesson(courseId, module.id, true, false, siteId).then((lesson) => {
|
||||
return this.lessonProvider.getLesson(courseId, module.id, {
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId,
|
||||
}).then((lesson) => {
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.lessonProvider.invalidateLessonData(courseId, siteId));
|
||||
|
@ -227,9 +235,9 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.lessonProvider.getLesson(courseId, module.id, false, false, siteId).then((lesson) => {
|
||||
return this.lessonProvider.getLesson(courseId, module.id, {siteId}).then((lesson) => {
|
||||
// Check if there is any prevent access reason.
|
||||
return this.lessonProvider.getAccessInformation(lesson.id, false, false, siteId).then((info) => {
|
||||
return this.lessonProvider.getAccessInformation(lesson.id, {cmId: module.id, siteId}).then((info) => {
|
||||
if (!info.canviewreports && !this.lessonProvider.isLessonOffline(lesson)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -273,15 +281,28 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected prefetchLesson(module: any, courseId: number, single: boolean, siteId: string): Promise<any> {
|
||||
let lesson,
|
||||
password,
|
||||
accessInfo;
|
||||
let lesson;
|
||||
let password;
|
||||
let accessInfo;
|
||||
|
||||
return this.lessonProvider.getLesson(courseId, module.id, false, true, siteId).then((lessonData) => {
|
||||
const commonOptions = {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
const modOptions = {
|
||||
cmId: module.id,
|
||||
...commonOptions, // Include all common options.
|
||||
};
|
||||
|
||||
return this.lessonProvider.getLesson(courseId, module.id, commonOptions).then((lessonData) => {
|
||||
lesson = lessonData;
|
||||
|
||||
// Get the lesson password if it's needed.
|
||||
return this.getLessonPassword(lesson.id, false, true, single, siteId);
|
||||
return this.getLessonPassword(lesson.id, {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
askPassword: single,
|
||||
siteId,
|
||||
});
|
||||
}).then((data) => {
|
||||
password = data.password;
|
||||
lesson = data.lesson || lesson;
|
||||
|
@ -297,7 +318,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
// Ignore errors.
|
||||
}));
|
||||
|
||||
promises.push(this.lessonProvider.getAccessInformation(lesson.id, false, true, siteId).then((info) => {
|
||||
promises.push(this.lessonProvider.getAccessInformation(lesson.id, modOptions).then((info) => {
|
||||
accessInfo = info;
|
||||
}));
|
||||
|
||||
|
@ -316,7 +337,12 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
|
||||
// Get the list of pages.
|
||||
if (this.lessonProvider.isLessonOffline(lesson)) {
|
||||
promises.push(this.lessonProvider.getPages(lesson.id, password, false, true, siteId).then((pages) => {
|
||||
const passwordOptions = {
|
||||
password,
|
||||
...modOptions, // Include all mod options.
|
||||
};
|
||||
|
||||
promises.push(this.lessonProvider.getPages(lesson.id, passwordOptions).then((pages) => {
|
||||
const subPromises = [];
|
||||
let hasRandomBranch = false;
|
||||
|
||||
|
@ -333,8 +359,10 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
}
|
||||
|
||||
// Get the page data. We don't pass accessInfo because we don't need to calculate the offline data.
|
||||
subPromises.push(this.lessonProvider.getPageData(lesson, data.page.id, password, false, true, false,
|
||||
true, undefined, undefined, siteId).then((pageData) => {
|
||||
subPromises.push(this.lessonProvider.getPageData(lesson, data.page.id, {
|
||||
includeContents: true,
|
||||
...passwordOptions, // Include all options.
|
||||
}).then((pageData) => {
|
||||
|
||||
// Download the page files.
|
||||
let pageFiles = pageData.contentfiles || [];
|
||||
|
@ -353,7 +381,7 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
});
|
||||
|
||||
// Prefetch the list of possible jumps for offline navigation. Do it here because we know hasRandomBranch.
|
||||
subPromises.push(this.lessonProvider.getPagesPossibleJumps(lesson.id, false, true, siteId).catch((error) => {
|
||||
subPromises.push(this.lessonProvider.getPagesPossibleJumps(lesson.id, modOptions).catch((error) => {
|
||||
if (hasRandomBranch) {
|
||||
// The WebSevice probably failed because RANDOMBRANCH aren't supported if the user hasn't seen any page.
|
||||
return Promise.reject(this.translate.instant('addon.mod_lesson.errorprefetchrandombranch'));
|
||||
|
@ -366,16 +394,15 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
}));
|
||||
|
||||
// Prefetch user timers to be able to calculate timemodified in offline.
|
||||
promises.push(this.lessonProvider.getTimers(lesson.id, false, true, siteId).catch(() => {
|
||||
promises.push(this.lessonProvider.getTimers(lesson.id, modOptions).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
|
||||
// Prefetch viewed pages in last retake to calculate progress.
|
||||
promises.push(this.lessonProvider.getContentPagesViewedOnline(lesson.id, retake, false, true, siteId));
|
||||
promises.push(this.lessonProvider.getContentPagesViewedOnline(lesson.id, retake, modOptions));
|
||||
|
||||
// Prefetch question attempts in last retake for offline calculations.
|
||||
promises.push(this.lessonProvider.getQuestionsAttemptsOnline(lesson.id, retake, false, undefined, false, true,
|
||||
siteId));
|
||||
promises.push(this.lessonProvider.getQuestionsAttemptsOnline(lesson.id, retake, modOptions));
|
||||
}
|
||||
|
||||
if (accessInfo.canviewreports) {
|
||||
|
@ -384,11 +411,14 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
const subPromises = [];
|
||||
|
||||
info.groups.forEach((group) => {
|
||||
subPromises.push(this.lessonProvider.getRetakesOverview(lesson.id, group.id, false, true, siteId));
|
||||
subPromises.push(this.lessonProvider.getRetakesOverview(lesson.id, {
|
||||
groupId: group.id,
|
||||
...modOptions, // Include all options.
|
||||
}));
|
||||
});
|
||||
|
||||
// Always get group 0, even if there are no groups.
|
||||
subPromises.push(this.lessonProvider.getRetakesOverview(lesson.id, 0, false, true, siteId).then((data) => {
|
||||
// Always get all participants, even if there are no groups.
|
||||
subPromises.push(this.lessonProvider.getRetakesOverview(lesson.id, modOptions).then((data) => {
|
||||
if (!data || !data.students) {
|
||||
return;
|
||||
}
|
||||
|
@ -406,8 +436,10 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
return;
|
||||
}
|
||||
|
||||
retakePromises.push(this.lessonProvider.getUserRetake(lesson.id, lastRetake.try, student.id, false,
|
||||
true, siteId).then((attempt) => {
|
||||
retakePromises.push(this.lessonProvider.getUserRetake(lesson.id, lastRetake.try, {
|
||||
userId: student.id,
|
||||
...modOptions, // Include all options.
|
||||
}).then((attempt) => {
|
||||
if (!attempt || !attempt.answerpages) {
|
||||
return;
|
||||
}
|
||||
|
@ -445,19 +477,20 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
* @param lessonId Lesson ID.
|
||||
* @param info Lesson access info.
|
||||
* @param pwd Password to check.
|
||||
* @param forceCache Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected validatePassword(lessonId: number, info: any, pwd: string, forceCache?: boolean, ignoreCache?: boolean,
|
||||
siteId?: string): Promise<{password: string, lesson: any, accessInfo: any}> {
|
||||
protected validatePassword(lessonId: number, info: any, pwd: string, options: CoreCourseCommonModWSOptions = {})
|
||||
: Promise<{password: string, lesson: any, accessInfo: any}> {
|
||||
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.lessonProvider.getLessonWithPassword(lessonId, pwd, true, forceCache, ignoreCache, siteId).then((lesson) => {
|
||||
return this.lessonProvider.getLessonWithPassword(lessonId, {
|
||||
password: pwd,
|
||||
...options, // Include all options.
|
||||
}).then((lesson) => {
|
||||
// Password is ok, store it and return the data.
|
||||
return this.lessonProvider.storePassword(lesson.id, pwd, siteId).then(() => {
|
||||
return this.lessonProvider.storePassword(lesson.id, pwd, options.siteId).then(() => {
|
||||
return {
|
||||
password: pwd,
|
||||
lesson: lesson,
|
||||
|
@ -483,3 +516,10 @@ export class AddonModLessonPrefetchHandler extends CoreCourseActivityPrefetchHan
|
|||
return this.syncProvider.syncLesson(module.instance, false, false, siteId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to pass to get lesson password.
|
||||
*/
|
||||
export type AddonModLessonGetPasswordOptions = CoreCourseCommonModWSOptions & {
|
||||
askPassword?: boolean; // True if we should ask for password if needed, false otherwise.
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ import { Injectable } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFileProvider } from '@providers/file';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreUrlUtilsProvider } from '@providers/utils/url';
|
||||
|
@ -100,29 +100,32 @@ export class AddonModLtiProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the LTI is retrieved.
|
||||
*/
|
||||
getLti(courseId: number, cmId: number): Promise<AddonModLtiLti> {
|
||||
async getLti(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModLtiLti> {
|
||||
const params: any = {
|
||||
courseids: [courseId]
|
||||
};
|
||||
const preSets: any = {
|
||||
const preSets = {
|
||||
cacheKey: this.getLtiCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModLtiProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return this.sitesProvider.getCurrentSite().read('mod_lti_get_ltis_by_courses', params, preSets)
|
||||
.then((response: AddonModLtiGetLtisByCoursesResult): any => {
|
||||
const site = await this.sitesProvider.getSite(options.siteId);
|
||||
|
||||
if (response.ltis) {
|
||||
const currentLti = response.ltis.find((lti) => lti.coursemodule == cmId);
|
||||
if (currentLti) {
|
||||
return currentLti;
|
||||
}
|
||||
const response: AddonModLtiGetLtisByCoursesResult = await site.read('mod_lti_get_ltis_by_courses', params, preSets);
|
||||
|
||||
if (response.ltis) {
|
||||
const currentLti = response.ltis.find((lti) => lti.coursemodule == cmId);
|
||||
if (currentLti) {
|
||||
return currentLti;
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
});
|
||||
throw new Error('Activity not found.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
|
||||
<core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
|
@ -43,11 +43,11 @@ export class AddonModPageProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the page is retrieved.
|
||||
*/
|
||||
getPageData(courseId: number, cmId: number, siteId?: string): Promise<AddonModPagePage> {
|
||||
return this.getPageByKey(courseId, 'coursemodule', cmId, siteId);
|
||||
getPageData(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModPagePage> {
|
||||
return this.getPageByKey(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,18 +56,21 @@ export class AddonModPageProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the page is retrieved.
|
||||
*/
|
||||
protected getPageByKey(courseId: number, key: string, value: any, siteId?: string): Promise<AddonModPagePage> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
protected getPageByKey(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModPagePage> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getPageCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getPageCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModPageProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_page_get_pages_by_courses', params, preSets)
|
||||
.then((response: AddonModPageGetPagesByCoursesResult): any => {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
}
|
||||
|
||||
// Get quiz access info.
|
||||
return this.quizProvider.getQuizAccessInformation(this.quizData.id).then((info) => {
|
||||
return this.quizProvider.getQuizAccessInformation(this.quizData.id, {cmId: this.module.id}).then((info) => {
|
||||
this.quizAccessInfo = info;
|
||||
this.quizData.showReviewColumn = info.canreviewmyattempts;
|
||||
this.accessRules = info.accessrules;
|
||||
|
@ -213,7 +213,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
}
|
||||
|
||||
// Get question types in the quiz.
|
||||
return this.quizProvider.getQuizRequiredQtypes(this.quizData.id).then((types) => {
|
||||
return this.quizProvider.getQuizRequiredQtypes(this.quizData.id, {cmId: this.module.id}).then((types) => {
|
||||
this.unsupportedQuestions = this.quizProvider.getUnsupportedQuestions(types);
|
||||
this.hasSupportedQuestions = !!types.find((type) => {
|
||||
return type != 'random' && this.unsupportedQuestions.indexOf(type) == -1;
|
||||
|
@ -239,11 +239,11 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
protected getAttempts(): Promise<void> {
|
||||
|
||||
// Get access information of last attempt (it also works if no attempts made).
|
||||
return this.quizProvider.getAttemptAccessInformation(this.quizData.id, 0).then((info) => {
|
||||
return this.quizProvider.getAttemptAccessInformation(this.quizData.id, 0, {cmId: this.module.id}).then((info) => {
|
||||
this.attemptAccessInfo = info;
|
||||
|
||||
// Get attempts.
|
||||
return this.quizProvider.getUserAttempts(this.quizData.id).then((atts) => {
|
||||
return this.quizProvider.getUserAttempts(this.quizData.id, {cmId: this.module.id}).then((atts) => {
|
||||
|
||||
return this.treatAttempts(atts).then((atts) => {
|
||||
this.attempts = atts;
|
||||
|
@ -355,7 +355,9 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
|
||||
if (this.quizData.showFeedbackColumn) {
|
||||
// Get the quiz overall feedback.
|
||||
return this.quizProvider.getFeedbackForGrade(this.quizData.id, this.gradebookData.grade).then((response) => {
|
||||
return this.quizProvider.getFeedbackForGrade(this.quizData.id, this.gradebookData.grade, {
|
||||
cmId: this.module.id,
|
||||
}).then((response) => {
|
||||
this.overallFeedback = response.feedbacktext;
|
||||
});
|
||||
}
|
||||
|
@ -379,7 +381,7 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
const attemptId = this.autoReview.attemptId;
|
||||
|
||||
if (this.quizAccessInfo.canreviewmyattempts) {
|
||||
return this.quizProvider.getAttemptReview(attemptId, -1).then(() => {
|
||||
return this.quizProvider.getAttemptReview(attemptId, {page: -1, cmId: this.module.id}).then(() => {
|
||||
this.navCtrl.push('AddonModQuizReviewPage', {courseId: this.courseId, quizId: this.quizData.id, attemptId});
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
|
@ -559,12 +561,12 @@ export class AddonModQuizIndexComponent extends CoreCourseModuleMainActivityComp
|
|||
promises.push(this.quizProvider.loadFinishedOfflineData(attempts));
|
||||
|
||||
// Get combined review options.
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(this.quizData.id).then((result) => {
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(this.quizData.id, {cmId: this.module.id}).then((result) => {
|
||||
this.options = result;
|
||||
}));
|
||||
|
||||
// Get best grade.
|
||||
promises.push(this.quizProvider.getUserBestGrade(this.quizData.id).then((best) => {
|
||||
promises.push(this.quizProvider.getUserBestGrade(this.quizData.id, {cmId: this.module.id}).then((best) => {
|
||||
this.bestGrade = best;
|
||||
|
||||
// Get gradebook grade.
|
||||
|
|
|
@ -92,7 +92,7 @@ export class AddonModQuizAttemptPage implements OnInit {
|
|||
accessInfo;
|
||||
|
||||
// Get all the attempts and search the one we want.
|
||||
promises.push(this.quizProvider.getUserAttempts(this.quizId).then((attempts) => {
|
||||
promises.push(this.quizProvider.getUserAttempts(this.quizId, {cmId: this.quiz.coursemodule}).then((attempts) => {
|
||||
for (let i = 0; i < attempts.length; i++) {
|
||||
const attempt = attempts[i];
|
||||
if (attempt.id == this.attemptId) {
|
||||
|
@ -110,12 +110,13 @@ export class AddonModQuizAttemptPage implements OnInit {
|
|||
return this.quizProvider.loadFinishedOfflineData([this.attempt]);
|
||||
}));
|
||||
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(this.quiz.id).then((opts) => {
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(this.quiz.id, {cmId: this.quiz.coursemodule}).then((opts) => {
|
||||
options = opts;
|
||||
}));
|
||||
|
||||
// Check if the user can review the attempt.
|
||||
promises.push(this.quizProvider.getQuizAccessInformation(this.quiz.id).then((quizAccessInfo) => {
|
||||
promises.push(this.quizProvider.getQuizAccessInformation(this.quiz.id, {cmId: this.quiz.coursemodule})
|
||||
.then((quizAccessInfo) => {
|
||||
accessInfo = quizAccessInfo;
|
||||
|
||||
if (accessInfo.canreviewmyattempts) {
|
||||
|
@ -123,7 +124,7 @@ export class AddonModQuizAttemptPage implements OnInit {
|
|||
return this.quizProvider.invalidateAttemptReviewForPage(this.attemptId, -1).catch(() => {
|
||||
// Ignore errors.
|
||||
}).then(() => {
|
||||
return this.quizProvider.getAttemptReview(this.attemptId, -1);
|
||||
return this.quizProvider.getAttemptReview(this.attemptId, {page: -1, cmId: this.quiz.coursemodule});
|
||||
}).catch(() => {
|
||||
// Error getting the review, assume the user cannot review the attempt.
|
||||
accessInfo.canreviewmyattempts = false;
|
||||
|
@ -146,7 +147,9 @@ export class AddonModQuizAttemptPage implements OnInit {
|
|||
options.someoptions.overallfeedback && !isNaN(grade)) {
|
||||
|
||||
// Feedback should be displayed, get the feedback for the grade.
|
||||
return this.quizProvider.getFeedbackForGrade(this.quiz.id, grade).then((response) => {
|
||||
return this.quizProvider.getFeedbackForGrade(this.quiz.id, grade, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
}).then((response) => {
|
||||
this.attempt.feedback = response.feedbacktext;
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { IonicPage, NavParams, Content, PopoverController, ModalController, Moda
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
@ -315,12 +315,18 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
// Get access information for the quiz.
|
||||
return this.quizProvider.getQuizAccessInformation(this.quiz.id, this.offline, true);
|
||||
return this.quizProvider.getQuizAccessInformation(this.quiz.id, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
});
|
||||
}).then((info) => {
|
||||
this.quizAccessInfo = info;
|
||||
|
||||
// Get user attempts to determine last attempt.
|
||||
return this.quizProvider.getUserAttempts(this.quiz.id, 'all', true, this.offline, true);
|
||||
return this.quizProvider.getUserAttempts(this.quiz.id, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
});
|
||||
}).then((attempts) => {
|
||||
if (!attempts.length) {
|
||||
// There are no attempts, start a new one.
|
||||
|
@ -396,8 +402,10 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
|
|||
*/
|
||||
protected fixSequenceChecks(): Promise<any> {
|
||||
// Get current page data again to get the latest sequencechecks.
|
||||
return this.quizProvider.getAttemptData(this.attempt.id, this.attempt.currentpage, this.preflightData, this.offline, true)
|
||||
.then((data) => {
|
||||
return this.quizProvider.getAttemptData(this.attempt.id, this.attempt.currentpage, this.preflightData, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).then((data) => {
|
||||
|
||||
const newSequenceChecks = {};
|
||||
|
||||
|
@ -443,7 +451,10 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected loadPage(page: number): Promise<void> {
|
||||
return this.quizProvider.getAttemptData(this.attempt.id, page, this.preflightData, this.offline, true).then((data) => {
|
||||
return this.quizProvider.getAttemptData(this.attempt.id, page, this.preflightData, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).then((data) => {
|
||||
// Update attempt, status could change during the execution.
|
||||
this.attempt = data.attempt;
|
||||
this.attempt.currentpage = page;
|
||||
|
@ -487,7 +498,11 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
|
|||
protected loadSummary(): Promise<void> {
|
||||
this.summaryQuestions = [];
|
||||
|
||||
return this.quizProvider.getAttemptSummary(this.attempt.id, this.preflightData, this.offline, true, true).then((qs) => {
|
||||
return this.quizProvider.getAttemptSummary(this.attempt.id, this.preflightData, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
loadLocal: this.offline,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).then((qs) => {
|
||||
this.showSummary = true;
|
||||
this.summaryQuestions = qs;
|
||||
|
||||
|
@ -511,8 +526,11 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
|
|||
*/
|
||||
protected loadNavigation(): Promise<void> {
|
||||
// We use the attempt summary to build the navigation because it contains all the questions.
|
||||
return this.quizProvider.getAttemptSummary(this.attempt.id, this.preflightData, this.offline, true, true)
|
||||
.then((questions) => {
|
||||
return this.quizProvider.getAttemptSummary(this.attempt.id, this.preflightData, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
loadLocal: this.offline,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).then((questions) => {
|
||||
|
||||
questions.forEach((question) => {
|
||||
question.stateClass = this.questionHelper.getQuestionStateClass(question.state);
|
||||
|
@ -652,7 +670,10 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
|
|||
false, 'addon.mod_quiz.startattempt').then((attempt) => {
|
||||
|
||||
// Re-fetch attempt access information with the right attempt (might have changed because a new attempt was created).
|
||||
return this.quizProvider.getAttemptAccessInformation(this.quiz.id, attempt.id, this.offline, true).then((info) => {
|
||||
return this.quizProvider.getAttemptAccessInformation(this.quiz.id, attempt.id, {
|
||||
cmId: this.quiz.coursemodule,
|
||||
readingStrategy: this.offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).then((info) => {
|
||||
this.attemptAccessInfo = info;
|
||||
this.attempt = attempt;
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ export class AddonModQuizReviewPage implements OnInit {
|
|||
this.quiz = quizData;
|
||||
this.componentId = this.quiz.coursemodule;
|
||||
|
||||
return this.quizProvider.getCombinedReviewOptions(this.quizId).then((result) => {
|
||||
return this.quizProvider.getCombinedReviewOptions(this.quizId, {cmId: this.quiz.coursemodule}).then((result) => {
|
||||
this.options = result;
|
||||
|
||||
// Load the navigation data.
|
||||
|
@ -155,7 +155,7 @@ export class AddonModQuizReviewPage implements OnInit {
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected loadPage(page: number): Promise<void> {
|
||||
return this.quizProvider.getAttemptReview(this.attemptId, page).then((data) => {
|
||||
return this.quizProvider.getAttemptReview(this.attemptId, {page, cmId: this.quiz.coursemodule}).then((data) => {
|
||||
this.attempt = data.attempt;
|
||||
this.attempt.currentpage = page;
|
||||
this.currentPage = page;
|
||||
|
@ -187,7 +187,7 @@ export class AddonModQuizReviewPage implements OnInit {
|
|||
*/
|
||||
protected loadNavigation(): Promise<void> {
|
||||
// Get all questions in single page to retrieve all the questions.
|
||||
return this.quizProvider.getAttemptReview(this.attemptId, -1).then((data) => {
|
||||
return this.quizProvider.getAttemptReview(this.attemptId, {page: -1, cmId: this.quiz.coursemodule}).then((data) => {
|
||||
const lastQuestion = data.questions[data.questions.length - 1];
|
||||
|
||||
data.questions.forEach((question) => {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ModalController, NavController } from 'ionic-angular';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { AddonModQuizProvider } from './quiz';
|
||||
|
@ -166,12 +166,12 @@ export class AddonModQuizHelperProvider {
|
|||
* Get a quiz ID by attempt ID.
|
||||
*
|
||||
* @param attemptId Attempt ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the quiz ID.
|
||||
*/
|
||||
getQuizIdByAttemptId(attemptId: number, siteId?: string): Promise<number> {
|
||||
getQuizIdByAttemptId(attemptId: number, options: {cmId?: number, siteId?: string} = {}): Promise<number> {
|
||||
// Use getAttemptReview to retrieve the quiz ID.
|
||||
return this.quizProvider.getAttemptReview(attemptId, undefined, false, siteId).then((reviewData) => {
|
||||
return this.quizProvider.getAttemptReview(attemptId, options).then((reviewData) => {
|
||||
if (reviewData.attempt && reviewData.attempt.quiz) {
|
||||
return reviewData.attempt.quiz;
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ export class AddonModQuizHelperProvider {
|
|||
promise = Promise.resolve(quizId);
|
||||
} else {
|
||||
// Retrieve the quiz ID using the attempt ID.
|
||||
promise = this.getQuizIdByAttemptId(attemptId);
|
||||
promise = this.getQuizIdByAttemptId(attemptId, {siteId});
|
||||
}
|
||||
|
||||
return promise.then((id) => {
|
||||
|
@ -298,6 +298,11 @@ export class AddonModQuizHelperProvider {
|
|||
siteId?: string): Promise<any> {
|
||||
|
||||
const rules = accessInfo && accessInfo.activerulenames;
|
||||
const modOptions = {
|
||||
cmId: quiz.coursemodule,
|
||||
readingStrategy: offline ? CoreSitesReadingStrategy.PreferCache : CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
let promise;
|
||||
|
||||
if (attempt) {
|
||||
|
@ -305,7 +310,7 @@ export class AddonModQuizHelperProvider {
|
|||
// We're continuing an attempt. Call getAttemptData to validate the preflight data.
|
||||
const page = attempt.currentpage;
|
||||
|
||||
promise = this.quizProvider.getAttemptData(attempt.id, page, preflightData, offline, true, siteId).then(() => {
|
||||
promise = this.quizProvider.getAttemptData(attempt.id, page, preflightData, modOptions).then(() => {
|
||||
if (offline) {
|
||||
// Get current page stored in local.
|
||||
return this.quizOfflineProvider.getAttemptById(attempt.id).then((localAttempt) => {
|
||||
|
@ -318,7 +323,7 @@ export class AddonModQuizHelperProvider {
|
|||
} else {
|
||||
// Attempt is overdue or finished in offline, we can only see the summary.
|
||||
// Call getAttemptSummary to validate the preflight data.
|
||||
promise = this.quizProvider.getAttemptSummary(attempt.id, preflightData, offline, true, false, siteId);
|
||||
promise = this.quizProvider.getAttemptSummary(attempt.id, preflightData, modOptions);
|
||||
}
|
||||
} else {
|
||||
// We're starting a new attempt, call startAttempt.
|
||||
|
|
|
@ -16,10 +16,10 @@ import { Injectable, Injector } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseProvider, CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreQuestionHelperProvider } from '@core/question/providers/helper';
|
||||
import { CoreCourseActivityPrefetchHandlerBase } from '@core/course/classes/activity-prefetch-handler';
|
||||
|
@ -90,7 +90,10 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
return this.quizProvider.getQuiz(courseId, module.id).then((quiz) => {
|
||||
const files = this.getIntroFilesFromInstance(module, quiz);
|
||||
|
||||
return this.quizProvider.getUserAttempts(quiz.id, 'all', true, false, true).then((attempts) => {
|
||||
return this.quizProvider.getUserAttempts(quiz.id, {
|
||||
cmId: module.id,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).then((attempts) => {
|
||||
return this.getAttemptsFeedbackFiles(quiz, attempts).then((attemptFiles) => {
|
||||
return files.concat(attemptFiles);
|
||||
});
|
||||
|
@ -106,9 +109,10 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
*
|
||||
* @param quiz Quiz.
|
||||
* @param attempts Quiz user attempts.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @return List of Files.
|
||||
*/
|
||||
protected getAttemptsFeedbackFiles(quiz: any, attempts: any[]): Promise<any[]> {
|
||||
protected getAttemptsFeedbackFiles(quiz: any, attempts: any[], siteId?: string): Promise<any[]> {
|
||||
// We have quiz data, now we'll get specific data for each attempt.
|
||||
const promises = [];
|
||||
const getInlineFiles = this.sitesProvider.getCurrentSite() &&
|
||||
|
@ -121,8 +125,11 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
|
||||
const attemptGrade = this.quizProvider.rescaleGrade(attempt.sumgrades, quiz, false);
|
||||
if (typeof attemptGrade != 'undefined') {
|
||||
promises.push(this.quizProvider.getFeedbackForGrade(quiz.id, Number(attemptGrade), true)
|
||||
.then((feedback) => {
|
||||
promises.push(this.quizProvider.getFeedbackForGrade(quiz.id, Number(attemptGrade), {
|
||||
cmId: quiz.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
}).then((feedback) => {
|
||||
if (getInlineFiles && feedback.feedbackinlinefiles && feedback.feedbackinlinefiles.length) {
|
||||
files = files.concat(feedback.feedbackinlinefiles);
|
||||
} else if (feedback.feedbacktext && !getInlineFiles) {
|
||||
|
@ -219,13 +226,16 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
|
||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.quizProvider.getQuiz(courseId, module.id, false, false, siteId).then((quiz) => {
|
||||
return this.quizProvider.getQuiz(courseId, module.id, {siteId}).then((quiz) => {
|
||||
if (quiz.allowofflineattempts !== 1 || quiz.hasquestions === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not downloadable if we reached max attempts or the quiz has an unfinished attempt.
|
||||
return this.quizProvider.getUserAttempts(quiz.id, undefined, true, false, false, siteId).then((attempts) => {
|
||||
return this.quizProvider.getUserAttempts(quiz.id, {
|
||||
cmId: module.id,
|
||||
siteId,
|
||||
}).then((attempts) => {
|
||||
const isLastFinished = !attempts.length || this.quizProvider.isAttemptFinished(attempts[attempts.length - 1].state);
|
||||
|
||||
return quiz.attempts === 0 || quiz.attempts > attempts.length || !isLastFinished;
|
||||
|
@ -283,26 +293,35 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
attemptAccessInfo,
|
||||
preflightData;
|
||||
|
||||
const commonOptions = {
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
const modOptions = {
|
||||
cmId: module.id,
|
||||
...commonOptions, // Include all common options.
|
||||
};
|
||||
|
||||
// Get quiz.
|
||||
return this.quizProvider.getQuiz(courseId, module.id, false, true, siteId).then((quizData) => {
|
||||
return this.quizProvider.getQuiz(courseId, module.id, commonOptions).then((quizData) => {
|
||||
quiz = quizData;
|
||||
|
||||
const promises = [],
|
||||
introFiles = this.getIntroFilesFromInstance(module, quiz);
|
||||
|
||||
// Prefetch some quiz data.
|
||||
promises.push(this.quizProvider.getQuizAccessInformation(quiz.id, false, true, siteId).then((info) => {
|
||||
promises.push(this.quizProvider.getQuizAccessInformation(quiz.id, modOptions).then((info) => {
|
||||
quizAccessInfo = info;
|
||||
}));
|
||||
promises.push(this.quizProvider.getQuizRequiredQtypes(quiz.id, true, siteId));
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, 'all', true, false, true, siteId).then((atts) => {
|
||||
promises.push(this.quizProvider.getQuizRequiredQtypes(quiz.id, modOptions));
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, modOptions).then((atts) => {
|
||||
attempts = atts;
|
||||
|
||||
return this.getAttemptsFeedbackFiles(quiz, attempts).then((attemptFiles) => {
|
||||
return this.getAttemptsFeedbackFiles(quiz, attempts, siteId).then((attemptFiles) => {
|
||||
return this.filepoolProvider.addFilesToQueue(siteId, attemptFiles, AddonModQuizProvider.COMPONENT, module.id);
|
||||
});
|
||||
}));
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, 0, false, true, siteId).then((info) => {
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, 0, modOptions).then((info) => {
|
||||
attemptAccessInfo = info;
|
||||
}));
|
||||
|
||||
|
@ -338,10 +357,10 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
|
||||
if (startAttempt) {
|
||||
// Re-fetch user attempts since we created a new one.
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, 'all', true, false, true, siteId).then((atts) => {
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, modOptions).then((atts) => {
|
||||
attempts = atts;
|
||||
|
||||
return this.getAttemptsFeedbackFiles(quiz, attempts).then((attemptFiles) => {
|
||||
return this.getAttemptsFeedbackFiles(quiz, attempts, siteId).then((attemptFiles) => {
|
||||
return this.filepoolProvider.addFilesToQueue(siteId, attemptFiles, AddonModQuizProvider.COMPONENT,
|
||||
module.id);
|
||||
});
|
||||
|
@ -355,16 +374,16 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
}
|
||||
|
||||
// Fetch attempt related data.
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(quiz.id, true, siteId));
|
||||
promises.push(this.quizProvider.getUserBestGrade(quiz.id, true, siteId));
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(quiz.id, modOptions));
|
||||
promises.push(this.quizProvider.getUserBestGrade(quiz.id, modOptions));
|
||||
promises.push(this.quizProvider.getGradeFromGradebook(courseId, module.id, true, siteId).then((gradebookData) => {
|
||||
if (typeof gradebookData.graderaw != 'undefined') {
|
||||
return this.quizProvider.getFeedbackForGrade(quiz.id, gradebookData.graderaw, true, siteId);
|
||||
return this.quizProvider.getFeedbackForGrade(quiz.id, gradebookData.graderaw, modOptions);
|
||||
}
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, 0, false, true, siteId)); // Last attempt.
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, 0, modOptions)); // Last attempt.
|
||||
|
||||
return Promise.all(promises);
|
||||
}).then(() => {
|
||||
|
@ -410,23 +429,35 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
promises = [],
|
||||
isSequential = this.quizProvider.isNavigationSequential(quiz);
|
||||
|
||||
const modOptions = {
|
||||
cmId: quiz.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
|
||||
if (this.quizProvider.isAttemptFinished(attempt.state)) {
|
||||
// Attempt is finished, get feedback and review data.
|
||||
|
||||
const attemptGrade = this.quizProvider.rescaleGrade(attempt.sumgrades, quiz, false);
|
||||
if (typeof attemptGrade != 'undefined') {
|
||||
promises.push(this.quizProvider.getFeedbackForGrade(quiz.id, Number(attemptGrade), true, siteId));
|
||||
promises.push(this.quizProvider.getFeedbackForGrade(quiz.id, Number(attemptGrade), modOptions));
|
||||
}
|
||||
|
||||
// Get the review for each page.
|
||||
pages.forEach((page) => {
|
||||
promises.push(this.quizProvider.getAttemptReview(attempt.id, page, true, siteId).catch(() => {
|
||||
promises.push(this.quizProvider.getAttemptReview(attempt.id, {
|
||||
page,
|
||||
...modOptions, // Include all options.
|
||||
}).catch(() => {
|
||||
// Ignore failures, maybe the user can't review the attempt.
|
||||
}));
|
||||
});
|
||||
|
||||
// Get the review for all questions in same page.
|
||||
promises.push(this.quizProvider.getAttemptReview(attempt.id, -1, true, siteId).then((data) => {
|
||||
// Get the review for all questions in same page.
|
||||
promises.push(this.quizProvider.getAttemptReview(attempt.id, {
|
||||
page: -1,
|
||||
...modOptions, // Include all options.
|
||||
}).then((data) => {
|
||||
// Download the files inside the questions.
|
||||
const questionPromises = [];
|
||||
|
||||
|
@ -442,8 +473,8 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
} else {
|
||||
|
||||
// Attempt not finished, get data needed to continue the attempt.
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, attempt.id, false, true, siteId));
|
||||
promises.push(this.quizProvider.getAttemptSummary(attempt.id, preflightData, false, true, false, siteId));
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, attempt.id, modOptions));
|
||||
promises.push(this.quizProvider.getAttemptSummary(attempt.id, preflightData, modOptions));
|
||||
|
||||
if (attempt.state == AddonModQuizProvider.ATTEMPT_IN_PROGRESS) {
|
||||
// Get data for each page.
|
||||
|
@ -453,8 +484,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
return;
|
||||
}
|
||||
|
||||
promises.push(this.quizProvider.getAttemptData(attempt.id, page, preflightData, false, true, siteId)
|
||||
.then((data) => {
|
||||
promises.push(this.quizProvider.getAttemptData(attempt.id, page, preflightData, modOptions).then((data) => {
|
||||
// Download the files inside the questions.
|
||||
const questionPromises = [];
|
||||
|
||||
|
@ -485,30 +515,35 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const promises = [];
|
||||
const modOptions = {
|
||||
cmId: quiz.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
let attempts,
|
||||
quizAccessInfo,
|
||||
preflightData,
|
||||
lastAttempt;
|
||||
|
||||
// Get quiz data.
|
||||
promises.push(this.quizProvider.getQuizAccessInformation(quiz.id, false, true, siteId).then((info) => {
|
||||
promises.push(this.quizProvider.getQuizAccessInformation(quiz.id, modOptions).then((info) => {
|
||||
quizAccessInfo = info;
|
||||
}));
|
||||
promises.push(this.quizProvider.getQuizRequiredQtypes(quiz.id, true, siteId));
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(quiz.id, true, siteId));
|
||||
promises.push(this.quizProvider.getUserBestGrade(quiz.id, true, siteId));
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, 'all', true, false, true, siteId).then((atts) => {
|
||||
promises.push(this.quizProvider.getQuizRequiredQtypes(quiz.id, modOptions));
|
||||
promises.push(this.quizProvider.getCombinedReviewOptions(quiz.id, modOptions));
|
||||
promises.push(this.quizProvider.getUserBestGrade(quiz.id, modOptions));
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, modOptions).then((atts) => {
|
||||
attempts = atts;
|
||||
}));
|
||||
promises.push(this.quizProvider.getGradeFromGradebook(quiz.course, quiz.coursemodule, true, siteId)
|
||||
.then((gradebookData) => {
|
||||
if (typeof gradebookData.graderaw != 'undefined') {
|
||||
return this.quizProvider.getFeedbackForGrade(quiz.id, gradebookData.graderaw, true, siteId);
|
||||
return this.quizProvider.getFeedbackForGrade(quiz.id, gradebookData.graderaw, modOptions);
|
||||
}
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, 0, false, true, siteId)); // Last attempt.
|
||||
promises.push(this.quizProvider.getAttemptAccessInformation(quiz.id, 0, modOptions)); // Last attempt.
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
lastAttempt = attempts[attempts.length - 1];
|
||||
|
@ -529,7 +564,12 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
}
|
||||
}).then(() => {
|
||||
// Prefetch finished, set the right status.
|
||||
return this.setStatusAfterPrefetch(quiz, attempts, true, false, siteId);
|
||||
return this.setStatusAfterPrefetch(quiz, {
|
||||
cmId: quiz.coursemodule,
|
||||
attempts,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -538,29 +578,25 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
* If the last attempt is finished or there isn't one, set it as not downloaded to show download icon.
|
||||
*
|
||||
* @param quiz Quiz.
|
||||
* @param attempts List of attempts. If not provided, they will be calculated.
|
||||
* @param forceCache Whether it should always return cached data. Only if attempts is undefined.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down). Only if
|
||||
* attempts is undefined.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when done.
|
||||
*/
|
||||
setStatusAfterPrefetch(quiz: any, attempts?: any[], forceCache?: boolean, ignoreCache?: boolean, siteId?: string)
|
||||
: Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
setStatusAfterPrefetch(quiz: any, options: AddonModQuizSetStatusAfterPrefetchOptions = {}): Promise<any> {
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const promises = [];
|
||||
let status;
|
||||
let attempts = options.attempts;
|
||||
|
||||
if (!attempts) {
|
||||
// Get the attempts.
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, 'all', true, forceCache, ignoreCache, siteId).then((atts) => {
|
||||
promises.push(this.quizProvider.getUserAttempts(quiz.id, options).then((atts) => {
|
||||
attempts = atts;
|
||||
}));
|
||||
}
|
||||
|
||||
// Check the current status of the quiz.
|
||||
promises.push(this.filepoolProvider.getPackageStatus(siteId, this.component, quiz.coursemodule).then((stat) => {
|
||||
promises.push(this.filepoolProvider.getPackageStatus(options.siteId, this.component, quiz.coursemodule).then((stat) => {
|
||||
status = stat;
|
||||
}));
|
||||
|
||||
|
@ -573,7 +609,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
isLastFinished = !lastAttempt || this.quizProvider.isAttemptFinished(lastAttempt.state),
|
||||
newStatus = isLastFinished ? CoreConstants.NOT_DOWNLOADED : CoreConstants.DOWNLOADED;
|
||||
|
||||
return this.filepoolProvider.storePackageStatus(siteId, newStatus, this.component, quiz.coursemodule);
|
||||
return this.filepoolProvider.storePackageStatus(options.siteId, newStatus, this.component, quiz.coursemodule);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -591,7 +627,7 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
this.syncProvider = this.injector.get(AddonModQuizSyncProvider);
|
||||
}
|
||||
|
||||
return this.quizProvider.getQuiz(courseId, module.id).then((quiz) => {
|
||||
return this.quizProvider.getQuiz(courseId, module.id, {siteId}).then((quiz) => {
|
||||
return this.syncProvider.syncQuiz(quiz, false, siteId).then((results) => {
|
||||
module.attemptFinished = (results && results.attemptFinished) || false;
|
||||
|
||||
|
@ -604,3 +640,10 @@ export class AddonModQuizPrefetchHandler extends CoreCourseActivityPrefetchHandl
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to pass to setStatusAfterPrefetch.
|
||||
*/
|
||||
export type AddonModQuizSetStatusAfterPrefetchOptions = CoreCourseCommonModWSOptions & {
|
||||
attempts?: any[]; // List of attempts. If not provided, they will be calculated.
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ import { TranslateService } from '@ngx-translate/core';
|
|||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
@ -111,7 +111,7 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
|
|||
// Check if online attempt was finished because of the sync.
|
||||
if (onlineAttempt && !this.quizProvider.isAttemptFinished(onlineAttempt.state)) {
|
||||
// Attempt wasn't finished at start. Check if it's finished now.
|
||||
return this.quizProvider.getUserAttempts(quiz.id, 'all', true, false, false, siteId).then((attempts) => {
|
||||
return this.quizProvider.getUserAttempts(quiz.id, {cmId: quiz.coursemodule, siteId}).then((attempts) => {
|
||||
// Search the attempt.
|
||||
for (const i in attempts) {
|
||||
const attempt = attempts[i];
|
||||
|
@ -180,7 +180,11 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
|
|||
|
||||
}).then(() => {
|
||||
// Prefetch finished or not needed, set the right status.
|
||||
return this.prefetchHandler.setStatusAfterPrefetch(quiz, undefined, shouldDownload, false, siteId);
|
||||
return this.prefetchHandler.setStatusAfterPrefetch(quiz, {
|
||||
cmId: module.id,
|
||||
readingStrategy: shouldDownload ? CoreSitesReadingStrategy.PreferCache : undefined,
|
||||
siteId,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -226,7 +230,7 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
|
|||
if (!this.syncProvider.isBlocked(AddonModQuizProvider.COMPONENT, quiz.id, siteId)) {
|
||||
|
||||
// Quiz not blocked, try to synchronize it.
|
||||
promises.push(this.quizProvider.getQuizById(quiz.courseid, quiz.id, false, false, siteId).then((quiz) => {
|
||||
promises.push(this.quizProvider.getQuizById(quiz.courseid, quiz.id, {siteId}).then((quiz) => {
|
||||
const promise = force ? this.syncQuiz(quiz, false, siteId) : this.syncQuizIfNeeded(quiz, false, siteId);
|
||||
|
||||
return promise.then((data) => {
|
||||
|
@ -284,10 +288,15 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
|
|||
syncQuiz(quiz: any, askPreflight?: boolean, siteId?: string): Promise<AddonModQuizSyncResult> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const warnings = [],
|
||||
courseId = quiz.course;
|
||||
let syncPromise,
|
||||
preflightData;
|
||||
const warnings = [];
|
||||
const courseId = quiz.course;
|
||||
const modOptions = {
|
||||
cmId: quiz.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
};
|
||||
let syncPromise;
|
||||
let preflightData;
|
||||
|
||||
if (this.isSyncing(quiz.id, siteId)) {
|
||||
// There's already a sync ongoing for this quiz, return the promise.
|
||||
|
@ -318,7 +327,7 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
|
|||
const offlineAttempt = attempts.pop();
|
||||
|
||||
// Now get the list of online attempts to make sure this attempt exists and isn't finished.
|
||||
return this.quizProvider.getUserAttempts(quiz.id, 'all', true, false, true, siteId).then((attempts) => {
|
||||
return this.quizProvider.getUserAttempts(quiz.id, modOptions).then((attempts) => {
|
||||
const lastAttemptId = attempts.length ? attempts[attempts.length - 1].id : undefined;
|
||||
let onlineAttempt;
|
||||
|
||||
|
@ -354,7 +363,7 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
|
|||
let finish;
|
||||
|
||||
// We're going to need preflightData, get it.
|
||||
return this.quizProvider.getQuizAccessInformation(quiz.id, false, true, siteId).then((info) => {
|
||||
return this.quizProvider.getQuizAccessInformation(quiz.id, modOptions).then((info) => {
|
||||
|
||||
return this.prefetchHandler.getPreflightData(quiz, info, onlineAttempt, askPreflight,
|
||||
'core.settings.synchronization', siteId);
|
||||
|
@ -364,8 +373,11 @@ export class AddonModQuizSyncProvider extends CoreCourseActivitySyncBaseProvider
|
|||
// Now get the online questions data.
|
||||
const pages = this.quizProvider.getPagesFromLayoutAndQuestions(onlineAttempt.layout, offlineQuestions);
|
||||
|
||||
return this.quizProvider.getAllQuestionsData(quiz, onlineAttempt, preflightData, pages, false, true,
|
||||
siteId);
|
||||
return this.quizProvider.getAllQuestionsData(quiz, onlineAttempt, preflightData, {
|
||||
pages,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
siteId,
|
||||
});
|
||||
}).then((onlineQuestions) => {
|
||||
|
||||
// Validate questions, discarding the offline answers that can't be synchronized.
|
||||
|
|
|
@ -16,18 +16,19 @@ import { Injectable } from '@angular/core';
|
|||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { CoreFilepoolProvider } from '@providers/filepool';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreGradesHelperProvider } from '@core/grades/providers/helper';
|
||||
import { CoreQuestionDelegate } from '@core/question/providers/delegate';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
import { AddonModQuizAccessRuleDelegate } from './access-rules-delegate';
|
||||
import { AddonModQuizOfflineProvider } from './quiz-offline';
|
||||
import { CorePushNotificationsProvider } from '@core/pushnotifications/providers/pushnotifications';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Service that provides some features for quiz.
|
||||
|
@ -90,22 +91,16 @@ export class AddonModQuizProvider {
|
|||
* @param quiz Quiz.
|
||||
* @param attempt Attempt.
|
||||
* @param preflightData Preflight required data (like password).
|
||||
* @param pages List of pages to get. If not defined, all pages.
|
||||
* @param offline Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the questions.
|
||||
*/
|
||||
getAllQuestionsData(quiz: any, attempt: any, preflightData: any, pages?: number[], offline?: boolean, ignoreCache?: boolean,
|
||||
siteId?: string): Promise<any> {
|
||||
getAllQuestionsData(quiz: any, attempt: any, preflightData: any, options: AddonModQuizAllQuestionsDataOptions = {})
|
||||
: Promise<any> {
|
||||
|
||||
const promises = [],
|
||||
questions = {},
|
||||
isSequential = this.isNavigationSequential(quiz);
|
||||
|
||||
if (!pages) {
|
||||
pages = this.getPagesFromLayout(attempt.layout);
|
||||
}
|
||||
const promises = [];
|
||||
const questions = {};
|
||||
const isSequential = this.isNavigationSequential(quiz);
|
||||
const pages = options.pages || this.getPagesFromLayout(attempt.layout);
|
||||
|
||||
pages.forEach((page) => {
|
||||
if (isSequential && page < attempt.currentpage) {
|
||||
|
@ -114,7 +109,7 @@ export class AddonModQuizProvider {
|
|||
}
|
||||
|
||||
// Get the questions in the page.
|
||||
promises.push(this.getAttemptData(attempt.id, page, preflightData, offline, ignoreCache, siteId).then((data) => {
|
||||
promises.push(this.getAttemptData(attempt.id, page, preflightData, options).then((data) => {
|
||||
// Add the questions to the result object.
|
||||
data.questions.forEach((question) => {
|
||||
questions[question.slot] = question;
|
||||
|
@ -153,29 +148,22 @@ export class AddonModQuizProvider {
|
|||
*
|
||||
* @param quizId Quiz ID.
|
||||
* @param attemptId Attempt ID. 0 for user's last attempt.
|
||||
* @param offline Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the access information.
|
||||
*/
|
||||
getAttemptAccessInformation(quizId: number, attemptId: number, offline?: boolean, ignoreCache?: boolean, siteId?: string)
|
||||
: Promise<any> {
|
||||
getAttemptAccessInformation(quizId: number, attemptId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
quizid: quizId,
|
||||
attemptid: attemptId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAttemptAccessInformationCacheKey(quizId, attemptId)
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
quizid: quizId,
|
||||
attemptid: attemptId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAttemptAccessInformationCacheKey(quizId, attemptId),
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_attempt_access_information', params, preSets);
|
||||
});
|
||||
|
@ -208,30 +196,23 @@ export class AddonModQuizProvider {
|
|||
* @param attemptId Attempt ID.
|
||||
* @param page Page number.
|
||||
* @param preflightData Preflight required data (like password).
|
||||
* @param offline Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the attempt data.
|
||||
*/
|
||||
getAttemptData(attemptId: number, page: number, preflightData: any, offline?: boolean, ignoreCache?: boolean, siteId?: string)
|
||||
: Promise<any> {
|
||||
getAttemptData(attemptId: number, page: number, preflightData: any, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
attemptid: attemptId,
|
||||
page: page,
|
||||
preflightdata: this.utils.objectToArrayOfObjects(preflightData, 'name', 'value', true)
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAttemptDataCacheKey(attemptId, page)
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
attemptid: attemptId,
|
||||
page: page,
|
||||
preflightdata: this.utils.objectToArrayOfObjects(preflightData, 'name', 'value', true),
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAttemptDataCacheKey(attemptId, page),
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_attempt_data', params, preSets);
|
||||
});
|
||||
|
@ -389,30 +370,24 @@ export class AddonModQuizProvider {
|
|||
* Get an attempt's review.
|
||||
*
|
||||
* @param attemptId Attempt ID.
|
||||
* @param page Page number. If not defined, return all the questions in all the pages.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the attempt review.
|
||||
*/
|
||||
getAttemptReview(attemptId: number, page?: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
if (typeof page == 'undefined') {
|
||||
page = -1;
|
||||
}
|
||||
getAttemptReview(attemptId: number, options: AddonModQuizGetAttemptReviewOptions = {}): Promise<any> {
|
||||
const page = typeof options.page == 'undefined' ? -1 : options.page;
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
attemptid: attemptId,
|
||||
page: page
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAttemptReviewCacheKey(attemptId, page),
|
||||
cacheErrors: ['noreview']
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
attemptid: attemptId,
|
||||
page: page,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAttemptReviewCacheKey(attemptId, page),
|
||||
cacheErrors: ['noreview'],
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_attempt_review', params, preSets);
|
||||
});
|
||||
|
@ -433,34 +408,26 @@ export class AddonModQuizProvider {
|
|||
*
|
||||
* @param attemptId Attempt ID.
|
||||
* @param preflightData Preflight required data (like password).
|
||||
* @param offline Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param loadLocal Whether it should load local state for each question. Only applicable if offline=true.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the list of questions for the attempt summary.
|
||||
*/
|
||||
getAttemptSummary(attemptId: number, preflightData: any, offline?: boolean, ignoreCache?: boolean, loadLocal?: boolean,
|
||||
siteId?: string): Promise<any[]> {
|
||||
getAttemptSummary(attemptId: number, preflightData: any, options: AddonModQuizGetAttemptSummaryOptions = {}): Promise<any[]> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
attemptid: attemptId,
|
||||
preflightdata: this.utils.objectToArrayOfObjects(preflightData, 'name', 'value', true)
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAttemptSummaryCacheKey(attemptId)
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
attemptid: attemptId,
|
||||
preflightdata: this.utils.objectToArrayOfObjects(preflightData, 'name', 'value', true),
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getAttemptSummaryCacheKey(attemptId),
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_attempt_summary', params, preSets).then((response) => {
|
||||
if (response && response.questions) {
|
||||
if (offline && loadLocal) {
|
||||
if (options.loadLocal) {
|
||||
return this.quizOfflineProvider.loadQuestionsLocalStates(attemptId, response.questions, site.getId());
|
||||
}
|
||||
|
||||
|
@ -497,27 +464,23 @@ export class AddonModQuizProvider {
|
|||
* Get a quiz combined review options.
|
||||
*
|
||||
* @param quizId Quiz ID.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param userId User ID. If not defined use site's current user.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the combined review options.
|
||||
*/
|
||||
getCombinedReviewOptions(quizId: number, ignoreCache?: boolean, siteId?: string, userId?: number): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
userId = userId || site.getUserId();
|
||||
getCombinedReviewOptions(quizId: number, options: AddonModQuizUserOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const userId = options.userId || site.getUserId();
|
||||
|
||||
const params = {
|
||||
quizid: quizId,
|
||||
userid: userId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getCombinedReviewOptionsCacheKey(quizId, userId)
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
quizid: quizId,
|
||||
userid: userId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getCombinedReviewOptionsCacheKey(quizId, userId),
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_combined_review_options', params, preSets).then((response) => {
|
||||
if (response && response.someoptions && response.alloptions) {
|
||||
|
@ -559,25 +522,22 @@ export class AddonModQuizProvider {
|
|||
*
|
||||
* @param quizId Quiz ID.
|
||||
* @param grade Grade.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the feedback.
|
||||
*/
|
||||
getFeedbackForGrade(quizId: number, grade: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getFeedbackForGrade(quizId: number, grade: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
quizid: quizId,
|
||||
grade: grade
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getFeedbackForGradeCacheKey(quizId, grade),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
quizid: quizId,
|
||||
grade: grade,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getFeedbackForGradeCacheKey(quizId, grade),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_quiz_feedback_for_grade', params, preSets);
|
||||
});
|
||||
|
@ -683,29 +643,21 @@ export class AddonModQuizProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param forceCache Whether it should always return cached data.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the Quiz is retrieved.
|
||||
*/
|
||||
protected getQuizByField(courseId: number, key: string, value: any, forceCache?: boolean, ignoreCache?: boolean,
|
||||
siteId?: string): Promise<any> {
|
||||
protected getQuizByField(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getQuizDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
|
||||
if (forceCache) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getQuizDataCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_quizzes_by_courses', params, preSets).then((response) => {
|
||||
if (response && response.quizzes) {
|
||||
|
@ -728,13 +680,11 @@ export class AddonModQuizProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param forceCache Whether it should always return cached data.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the quiz is retrieved.
|
||||
*/
|
||||
getQuiz(courseId: number, cmId: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.getQuizByField(courseId, 'coursemodule', cmId, forceCache, ignoreCache, siteId);
|
||||
getQuiz(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getQuizByField(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -742,13 +692,11 @@ export class AddonModQuizProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param id Quiz ID.
|
||||
* @param forceCache Whether it should always return cached data.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the quiz is retrieved.
|
||||
*/
|
||||
getQuizById(courseId: number, id: number, forceCache?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.getQuizByField(courseId, 'id', id, forceCache, ignoreCache, siteId);
|
||||
getQuizById(courseId: number, id: number, options: CoreSitesCommonWSOptions = {}): Promise<any> {
|
||||
return this.getQuizByField(courseId, 'id', id, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -765,26 +713,20 @@ export class AddonModQuizProvider {
|
|||
* Get access information for an attempt.
|
||||
*
|
||||
* @param quizId Quiz ID.
|
||||
* @param offline Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the access information.
|
||||
*/
|
||||
getQuizAccessInformation(quizId: number, offline?: boolean, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getQuizAccessInformation(quizId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
quizid: quizId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getQuizAccessInformationCacheKey(quizId)
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
quizid: quizId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getQuizAccessInformationCacheKey(quizId),
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_quiz_access_information', params, preSets);
|
||||
});
|
||||
|
@ -829,24 +771,21 @@ export class AddonModQuizProvider {
|
|||
* Get the potential question types that would be required for a given quiz.
|
||||
*
|
||||
* @param quizId Quiz ID.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the access information.
|
||||
*/
|
||||
getQuizRequiredQtypes(quizId: number, ignoreCache?: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
getQuizRequiredQtypes(quizId: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
quizid: quizId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getQuizRequiredQtypesCacheKey(quizId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
quizid: quizId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getQuizRequiredQtypesCacheKey(quizId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_quiz_required_qtypes', params, preSets).then((response) => {
|
||||
if (response && response.questiontypes) {
|
||||
|
@ -981,37 +920,29 @@ export class AddonModQuizProvider {
|
|||
* Get quiz attempts for a certain user.
|
||||
*
|
||||
* @param quizId Quiz ID.
|
||||
* @param status Status of the attempts to get. By default, 'all'.
|
||||
* @param includePreviews Whether to include previews. Defaults to true.
|
||||
* @param offline Whether it should return cached data. Has priority over ignoreCache.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param userId User ID. If not defined use site's current user.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the attempts.
|
||||
*/
|
||||
getUserAttempts(quizId: number, status: string = 'all', includePreviews: boolean = true, offline?: boolean,
|
||||
ignoreCache?: boolean, siteId?: string, userId?: number): Promise<any[]> {
|
||||
getUserAttempts(quizId: number, options: AddonModQuizGetUserAttemptsOptions = {}): Promise<any[]> {
|
||||
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
userId = userId || site.getUserId();
|
||||
const status = options.status || 'all';
|
||||
const includePreviews = typeof options.includePreviews == 'undefined' ? true : options.includePreviews;
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const userId = options.userId || site.getUserId();
|
||||
const params = {
|
||||
quizid: quizId,
|
||||
userid: userId,
|
||||
status: status,
|
||||
includepreviews: includePreviews ? 1 : 0
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getUserAttemptsCacheKey(quizId, userId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES
|
||||
};
|
||||
|
||||
if (offline) {
|
||||
preSets.omitExpires = true;
|
||||
} else if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
quizid: quizId,
|
||||
userid: userId,
|
||||
status: status,
|
||||
includepreviews: includePreviews ? 1 : 0,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getUserAttemptsCacheKey(quizId, userId),
|
||||
updateFrequency: CoreSite.FREQUENCY_SOMETIMES,
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_user_attempts', params, preSets).then((response) => {
|
||||
if (response && response.attempts) {
|
||||
|
@ -1048,27 +979,23 @@ export class AddonModQuizProvider {
|
|||
* Get best grade in a quiz for a certain user.
|
||||
*
|
||||
* @param quizId Quiz ID.
|
||||
* @param ignoreCache Whether it should ignore cached data (it will always fail in offline or server down).
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param userId User ID. If not defined use site's current user.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the best grade data.
|
||||
*/
|
||||
getUserBestGrade(quizId: number, ignoreCache?: boolean, siteId?: string, userId?: number): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
userId = userId || site.getUserId();
|
||||
getUserBestGrade(quizId: number, options: AddonModQuizUserOptions = {}): Promise<any> {
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const userId = options.userId || site.getUserId();
|
||||
|
||||
const params = {
|
||||
quizid: quizId,
|
||||
userid: userId
|
||||
},
|
||||
preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getUserBestGradeCacheKey(quizId, userId)
|
||||
};
|
||||
|
||||
if (ignoreCache) {
|
||||
preSets.getFromCache = false;
|
||||
preSets.emergencyCache = false;
|
||||
}
|
||||
quizid: quizId,
|
||||
userid: userId,
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getUserBestGradeCacheKey(quizId, userId),
|
||||
component: AddonModQuizProvider.COMPONENT,
|
||||
componentId: options.cmId,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_quiz_get_user_best_grade', params, preSets);
|
||||
});
|
||||
|
@ -1246,8 +1173,11 @@ export class AddonModQuizProvider {
|
|||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
// Get required data to call the invalidate functions.
|
||||
return this.getQuiz(courseId, moduleId, true, false, siteId).then((quiz) => {
|
||||
return this.getUserAttempts(quiz.id, 'all', true, false, false, siteId).then((attempts) => {
|
||||
return this.getQuiz(courseId, moduleId, {
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId,
|
||||
}).then((quiz) => {
|
||||
return this.getUserAttempts(quiz.id, {cmId: quiz.coursemodule, siteId}).then((attempts) => {
|
||||
// Now invalidate it.
|
||||
const lastAttemptId = attempts.length ? attempts[attempts.length - 1].id : undefined;
|
||||
|
||||
|
@ -1703,7 +1633,12 @@ export class AddonModQuizProvider {
|
|||
: Promise<any> {
|
||||
|
||||
// Get attempt summary to have the list of questions.
|
||||
return this.getAttemptSummary(attempt.id, preflightData, true, false, true, siteId).then((questionArray) => {
|
||||
return this.getAttemptSummary(attempt.id, preflightData, {
|
||||
cmId: quiz.coursemodule,
|
||||
loadLocal: true,
|
||||
readingStrategy: CoreSitesReadingStrategy.PreferCache,
|
||||
siteId,
|
||||
}).then((questionArray) => {
|
||||
// Convert the question array to an object.
|
||||
const questions = this.utils.arrayToObject(questionArray, 'slot');
|
||||
|
||||
|
@ -1860,3 +1795,40 @@ export class AddonModQuizProvider {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Common options with user ID.
|
||||
*/
|
||||
export type AddonModQuizUserOptions = CoreCourseCommonModWSOptions & {
|
||||
userId?: number; // User ID. If not defined use site's current user.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to getAllQuestionsData.
|
||||
*/
|
||||
export type AddonModQuizAllQuestionsDataOptions = CoreCourseCommonModWSOptions & {
|
||||
pages?: number[]; // List of pages to get. If not defined, all pages.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to getAttemptReview.
|
||||
*/
|
||||
export type AddonModQuizGetAttemptReviewOptions = CoreCourseCommonModWSOptions & {
|
||||
page?: number; // List of pages to get. If not defined, all pages.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to getAttemptSummary.
|
||||
*/
|
||||
export type AddonModQuizGetAttemptSummaryOptions = CoreCourseCommonModWSOptions & {
|
||||
loadLocal?: boolean; // Whether it should load local state for each question.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options to pass to getUserAttempts.
|
||||
*/
|
||||
export type AddonModQuizGetUserAttemptsOptions = CoreCourseCommonModWSOptions & {
|
||||
status?: string; // Status of the attempts to get. By default, 'all'.
|
||||
includePreviews?: boolean; // Whether to include previews. Defaults to true.
|
||||
userId?: number; // User ID. If not defined use site's current user.
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<core-context-menu-item *ngIf="blog" [priority]="750" content="{{'addon.blog.blog' | translate}}" [iconAction]="'fa-newspaper-o'" (action)="gotoBlog($event)"></core-context-menu-item>
|
||||
<core-context-menu-item [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="600" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="500" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { CoreLoggerProvider } from '@providers/logger';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesCommonWSOptions } from '@providers/sites';
|
||||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||
import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
|
||||
|
@ -54,18 +54,22 @@ export class AddonModResourceProvider {
|
|||
* @param courseId Course ID.
|
||||
* @param key Name of the property to check.
|
||||
* @param value Value to search.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the resource is retrieved.
|
||||
*/
|
||||
protected getResourceDataByKey(courseId: number, key: string, value: any, siteId?: string): Promise<AddonModResourceResource> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
protected getResourceDataByKey(courseId: number, key: string, value: any, options: CoreSitesCommonWSOptions = {})
|
||||
: Promise<AddonModResourceResource> {
|
||||
|
||||
return this.sitesProvider.getSite(options.siteId).then((site) => {
|
||||
const params = {
|
||||
courseids: [courseId]
|
||||
},
|
||||
preSets = {
|
||||
cacheKey: this.getResourceCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY
|
||||
};
|
||||
courseids: [courseId],
|
||||
};
|
||||
const preSets = {
|
||||
cacheKey: this.getResourceCacheKey(courseId),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
component: AddonModResourceProvider.COMPONENT,
|
||||
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
||||
};
|
||||
|
||||
return site.read('mod_resource_get_resources_by_courses', params, preSets)
|
||||
.then((response: AddonModResourceGetResourcesByCoursesResult): any => {
|
||||
|
@ -89,11 +93,11 @@ export class AddonModResourceProvider {
|
|||
*
|
||||
* @param courseId Course ID.
|
||||
* @param cmId Course module ID.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved when the resource is retrieved.
|
||||
*/
|
||||
getResourceData(courseId: number, cmId: number, siteId?: string): Promise<AddonModResourceResource> {
|
||||
return this.getResourceDataByKey(courseId, 'coursemodule', cmId, siteId);
|
||||
getResourceData(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModResourceResource> {
|
||||
return this.getResourceDataByKey(courseId, 'coursemodule', cmId, options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="loaded && hasOffline && isOnline" [priority]="600" [content]="'core.settings.synchronizenow' | translate" (action)="doRefresh(null, $event, true)" [iconAction]="syncIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="prefetchStatusIcon" [priority]="500" [content]="prefetchText" (action)="prefetch($event)" [iconAction]="prefetchStatusIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.removefiles' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
<core-context-menu-item *ngIf="size" [priority]="400" [content]="'core.clearstoreddata' | translate:{$a: size}" [iconDescription]="'cube'" (action)="removeFiles($event)" [iconAction]="'trash'" [closeOnClick]="false"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
protected fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<any> {
|
||||
|
||||
// Get the SCORM instance.
|
||||
return this.scormProvider.getScorm(this.courseId, this.module.id, this.module.url).then((scormData) => {
|
||||
return this.scormProvider.getScorm(this.courseId, this.module.id, {moduleUrl: this.module.url}).then((scormData) => {
|
||||
this.scorm = scormData;
|
||||
|
||||
this.dataRetrieved.emit(this.scorm);
|
||||
|
@ -185,12 +185,12 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
const promises = [];
|
||||
|
||||
// Get access information.
|
||||
promises.push(this.scormProvider.getAccessInformation(this.scorm.id).then((accessInfo) => {
|
||||
promises.push(this.scormProvider.getAccessInformation(this.scorm.id, {cmId: this.module.id}).then((accessInfo) => {
|
||||
this.accessInfo = accessInfo;
|
||||
}));
|
||||
|
||||
// Get the number of attempts.
|
||||
promises.push(this.scormProvider.getAttemptCount(this.scorm.id).then((attemptsData) => {
|
||||
promises.push(this.scormProvider.getAttemptCount(this.scorm.id, {cmId: this.module.id}).then((attemptsData) => {
|
||||
this.attempts = attemptsData;
|
||||
this.hasOffline = !!this.attempts.offline.length;
|
||||
|
||||
|
@ -207,7 +207,10 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
}
|
||||
|
||||
// Check if the last attempt is incomplete.
|
||||
return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.lastAttempt, this.lastIsOffline);
|
||||
return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.lastAttempt, {
|
||||
offline: this.lastIsOffline,
|
||||
cmId: this.module.id,
|
||||
});
|
||||
}).then((incomplete) => {
|
||||
const promises = [];
|
||||
|
||||
|
@ -260,7 +263,7 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
* @return Promise resolved when done.
|
||||
*/
|
||||
protected fetchStructure(): Promise<any> {
|
||||
return this.scormProvider.getOrganizations(this.scorm.id).then((organizations) => {
|
||||
return this.scormProvider.getOrganizations(this.scorm.id, {cmId: this.module.id}).then((organizations) => {
|
||||
this.organizations = organizations;
|
||||
|
||||
if (!this.currentOrganization.identifier) {
|
||||
|
@ -460,8 +463,11 @@ export class AddonModScormIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
|
||||
this.loadingToc = true;
|
||||
|
||||
return this.scormProvider.getOrganizationToc(this.scorm.id, this.lastAttempt, organizationId, this.lastIsOffline)
|
||||
.then((toc) => {
|
||||
return this.scormProvider.getOrganizationToc(this.scorm.id, this.lastAttempt, {
|
||||
organization: organizationId,
|
||||
offline: this.lastIsOffline,
|
||||
cmId: this.module.id,
|
||||
}).then((toc) => {
|
||||
|
||||
this.toc = this.scormProvider.formatTocToArray(toc);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { IonicPage, NavParams, ModalController } from 'ionic-angular';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreSitesProvider, CoreSitesReadingStrategy } from '@providers/sites';
|
||||
import { CoreSyncProvider } from '@providers/sync';
|
||||
import { CoreDomUtils } from '@providers/utils/dom';
|
||||
import { CoreTimeUtilsProvider } from '@providers/utils/time';
|
||||
|
@ -201,7 +201,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
|
|||
|
||||
// Check if current attempt is incomplete.
|
||||
if (this.attempt > 0) {
|
||||
return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.attempt, this.offline);
|
||||
return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.attempt, {
|
||||
offline: this.offline,
|
||||
cmId: this.scorm.coursemodule,
|
||||
});
|
||||
} else {
|
||||
// User doesn't have attempts. Last attempt is not incomplete (since he doesn't have any).
|
||||
return false;
|
||||
|
@ -217,7 +220,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
|
|||
return this.scormHelper.createOfflineAttempt(this.scorm, result.attempt, attemptsData.online.length);
|
||||
} else {
|
||||
// Last attempt was online, verify that we can create a new online attempt. We ignore cache.
|
||||
return this.scormProvider.getScormUserData(this.scorm.id, result.attempt, undefined, false, true).catch(() => {
|
||||
return this.scormProvider.getScormUserData(this.scorm.id, result.attempt, {
|
||||
cmId: this.scorm.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).catch(() => {
|
||||
// Cannot communicate with the server, create an offline attempt.
|
||||
this.offline = true;
|
||||
|
||||
|
@ -241,18 +247,22 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
|
|||
// Wait for any ongoing sync to finish. We won't sync a SCORM while it's being played.
|
||||
return this.scormSyncProvider.waitForSync(this.scorm.id).then(() => {
|
||||
// Get attempts data.
|
||||
return this.scormProvider.getAttemptCount(this.scorm.id).then((attemptsData) => {
|
||||
return this.scormProvider.getAttemptCount(this.scorm.id, {cmId: this.scorm.coursemodule}).then((attemptsData) => {
|
||||
return this.determineAttemptAndMode(attemptsData).then(() => {
|
||||
// Fetch TOC and get user data.
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.fetchToc());
|
||||
promises.push(this.scormProvider.getScormUserData(this.scorm.id, this.attempt, undefined, this.offline)
|
||||
.then((data) => {
|
||||
promises.push(this.scormProvider.getScormUserData(this.scorm.id, this.attempt, {
|
||||
cmId: this.scorm.coursemodule,
|
||||
offline: this.offline,
|
||||
}).then((data) => {
|
||||
this.userData = data;
|
||||
}));
|
||||
// Get access information.
|
||||
promises.push(this.scormProvider.getAccessInformation(this.scorm.id).then((accessInfo) => {
|
||||
promises.push(this.scormProvider.getAccessInformation(this.scorm.id, {
|
||||
cmId: this.scorm.coursemodule,
|
||||
}).then((accessInfo) => {
|
||||
this.accessInfo = accessInfo;
|
||||
}));
|
||||
|
||||
|
@ -273,11 +283,18 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
|
|||
this.loadingToc = true;
|
||||
|
||||
// We need to check incomplete again: attempt number or status might have changed.
|
||||
return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.attempt, this.offline).then((incomplete) => {
|
||||
return this.scormProvider.isAttemptIncomplete(this.scorm.id, this.attempt, {
|
||||
offline: this.offline,
|
||||
cmId: this.scorm.coursemodule,
|
||||
}).then((incomplete) => {
|
||||
this.scorm.incomplete = incomplete;
|
||||
|
||||
// Get TOC.
|
||||
return this.scormProvider.getOrganizationToc(this.scorm.id, this.attempt, this.organizationId, this.offline);
|
||||
return this.scormProvider.getOrganizationToc(this.scorm.id, this.attempt, {
|
||||
organization: this.organizationId,
|
||||
offline: this.offline,
|
||||
cmId: this.scorm.coursemodule,
|
||||
});
|
||||
}).then((toc) => {
|
||||
this.toc = this.scormProvider.formatTocToArray(toc);
|
||||
|
||||
|
@ -300,8 +317,13 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
|
|||
|
||||
if (!this.currentSco) {
|
||||
// No SCO defined. Get the first valid one.
|
||||
return this.scormHelper.getFirstSco(this.scorm.id, this.attempt, this.toc, this.organizationId, this.mode,
|
||||
this.offline).then((sco) => {
|
||||
return this.scormHelper.getFirstSco(this.scorm.id, this.attempt, {
|
||||
toc: this.toc,
|
||||
organization: this.organizationId,
|
||||
mode: this.mode,
|
||||
offline: this.offline,
|
||||
cmId: this.scorm.coursemodule,
|
||||
}).then((sco) => {
|
||||
|
||||
if (sco) {
|
||||
this.currentSco = sco;
|
||||
|
@ -374,7 +396,9 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
|
|||
this.scormProvider.saveTracks(sco.id, this.attempt, tracks, this.scorm, this.offline).catch(() => {
|
||||
// Error saving data. We'll go offline if we're online and the asset is not marked as completed already.
|
||||
if (!this.offline) {
|
||||
return this.scormProvider.getScormUserData(this.scorm.id, this.attempt, undefined, false).then((data) => {
|
||||
return this.scormProvider.getScormUserData(this.scorm.id, this.attempt, {
|
||||
cmId: this.scorm.coursemodule,
|
||||
}).then((data) => {
|
||||
if (!data[sco.id] || data[sco.id].userdata['cmi.core.lesson_status'] != 'completed') {
|
||||
// Go offline.
|
||||
return this.scormHelper.convertAttemptToOffline(this.scorm, this.attempt).then(() => {
|
||||
|
@ -462,7 +486,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
|
|||
return this.scormProvider.saveTracks(scoId, this.attempt, tracks, this.scorm, this.offline).then(() => {
|
||||
if (!this.offline) {
|
||||
// New online attempt created, update cached data about online attempts.
|
||||
this.scormProvider.getAttemptCount(this.scorm.id, false, true).catch(() => {
|
||||
this.scormProvider.getAttemptCount(this.scorm.id, {
|
||||
cmId: this.scorm.coursemodule,
|
||||
readingStrategy: CoreSitesReadingStrategy.OnlyNetwork,
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
|||
import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||
import { AddonModScormProvider, AddonModScormAttemptCountResult } from './scorm';
|
||||
import { AddonModScormOfflineProvider } from './scorm-offline';
|
||||
import { CoreCourseCommonModWSOptions } from '@core/course/providers/course';
|
||||
|
||||
/**
|
||||
* Helper service that provides some features for SCORM.
|
||||
|
@ -78,7 +79,7 @@ export class AddonModScormHelperProvider {
|
|||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
// Get data from the online attempt.
|
||||
return this.scormProvider.getScormUserData(scorm.id, attempt, undefined, false, false, siteId).then((onlineData) => {
|
||||
return this.scormProvider.getScormUserData(scorm.id, attempt, {cmId: scorm.coursemodule, siteId}).then((onlineData) => {
|
||||
// The SCORM API might have written some data to the offline attempt already.
|
||||
// We don't want to override it with cached online data.
|
||||
return this.scormOfflineProvider.getScormUserData(scorm.id, attempt, undefined, siteId).catch(() => {
|
||||
|
@ -131,7 +132,7 @@ export class AddonModScormHelperProvider {
|
|||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
// Try to get data from online attempts.
|
||||
return this.searchOnlineAttemptUserData(scorm.id, lastOnline, siteId).then((userData) => {
|
||||
return this.searchOnlineAttemptUserData(scorm.id, lastOnline, {cmId: scorm.coursemodule, siteId}).then((userData) => {
|
||||
// We're creating a new attempt, remove all the user data that is not needed for a new attempt.
|
||||
for (const scoId in userData) {
|
||||
const sco = userData[scoId],
|
||||
|
@ -177,7 +178,11 @@ export class AddonModScormHelperProvider {
|
|||
// Check if last online incomplete.
|
||||
const hasOffline = attempts.offline.indexOf(lastOnline) > -1;
|
||||
|
||||
return this.scormProvider.isAttemptIncomplete(scorm.id, lastOnline, hasOffline, false, siteId).then((incomplete) => {
|
||||
return this.scormProvider.isAttemptIncomplete(scorm.id, lastOnline, {
|
||||
offline: hasOffline,
|
||||
cmId: scorm.coursemodule,
|
||||
siteId,
|
||||
}).then((incomplete) => {
|
||||
if (incomplete) {
|
||||
return {
|
||||
number: lastOnline,
|
||||
|
@ -197,24 +202,19 @@ export class AddonModScormHelperProvider {
|
|||
*
|
||||
* @param scormId Scorm ID.
|
||||
* @param attempt Attempt number.
|
||||
* @param toc SCORM's TOC. If not provided, it will be calculated.
|
||||
* @param organization Organization to use.
|
||||
* @param mode Mode.
|
||||
* @param offline Whether the attempt is offline.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with the first SCO.
|
||||
*/
|
||||
getFirstSco(scormId: number, attempt: number, toc?: any[], organization?: string, mode?: string, offline?: boolean,
|
||||
siteId?: string): Promise<any> {
|
||||
getFirstSco(scormId: number, attempt: number, options: AddonModScormGetFirstScoOptions = {}): Promise<any> {
|
||||
|
||||
mode = mode || AddonModScormProvider.MODENORMAL;
|
||||
const mode = options.mode || AddonModScormProvider.MODENORMAL;
|
||||
|
||||
let promise;
|
||||
if (toc && toc.length) {
|
||||
promise = Promise.resolve(toc);
|
||||
if (options.toc && options.toc.length) {
|
||||
promise = Promise.resolve(options.toc);
|
||||
} else {
|
||||
// SCORM doesn't have a TOC. Get all the scos.
|
||||
promise = this.scormProvider.getScosWithData(scormId, attempt, organization, offline, false, siteId);
|
||||
promise = this.scormProvider.getScosWithData(scormId, attempt, options);
|
||||
}
|
||||
|
||||
return promise.then((scos) => {
|
||||
|
@ -319,16 +319,16 @@ export class AddonModScormHelperProvider {
|
|||
*
|
||||
* @param scormId SCORM ID.
|
||||
* @param attempt Online attempt to get the data.
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @param options Other options.
|
||||
* @return Promise resolved with user data.
|
||||
*/
|
||||
searchOnlineAttemptUserData(scormId: number, attempt: number, siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
searchOnlineAttemptUserData(scormId: number, attempt: number, options: CoreCourseCommonModWSOptions = {}): Promise<any> {
|
||||
options.siteId = options.siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
return this.scormProvider.getScormUserData(scormId, attempt, undefined, false, false, siteId).catch(() => {
|
||||
return this.scormProvider.getScormUserData(scormId, attempt, options).catch(() => {
|
||||
if (attempt > 0) {
|
||||
// We couldn't retrieve the data. Try again with the previous online attempt.
|
||||
return this.searchOnlineAttemptUserData(scormId, attempt - 1, siteId);
|
||||
return this.searchOnlineAttemptUserData(scormId, attempt - 1, options);
|
||||
} else {
|
||||
// No more attempts to try. Reject
|
||||
return Promise.reject(null);
|
||||
|
@ -336,3 +336,13 @@ export class AddonModScormHelperProvider {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to pass to getFirstSco.
|
||||
*/
|
||||
export type AddonModScormGetFirstScoOptions = CoreCourseCommonModWSOptions & {
|
||||
toc?: any[]; // SCORM's TOC. If not provided, it will be calculated.
|
||||
organization?: string; // Organization to use.
|
||||
mode?: string; // Mode.
|
||||
offline?: boolean; // Whether the attempt is offline.
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue