Merge pull request #3327 from dpalou/MOBILE-4099

MOBILE-4099 scorm: Don't call WS if user cannot save tracks
main
Noel De Martin 2022-06-21 13:01:13 +02:00 committed by GitHub
commit 82918f787b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 48 deletions

View File

@ -93,13 +93,6 @@ export class AddonModScormDataModel12 {
protected errorCode = '0'; // Last error. protected errorCode = '0'; // Last error.
protected timeout?: number; // Timeout to commit changes. protected timeout?: number; // Timeout to commit changes.
protected siteId: string;
protected scorm: AddonModScormScorm;
protected scoId: number;
protected attempt: number;
protected mode: string;
protected offline: boolean;
/** /**
* Constructor. * Constructor.
* *
@ -110,23 +103,18 @@ export class AddonModScormDataModel12 {
* @param userData The user default data. * @param userData The user default data.
* @param mode Mode being played. By default, MODENORMAL. * @param mode Mode being played. By default, MODENORMAL.
* @param offline Whether the attempt is offline. * @param offline Whether the attempt is offline.
* @param canSaveTracks Whether the user can save tracks.
*/ */
constructor( constructor(
siteId: string, protected siteId: string,
scorm: AddonModScormScorm, protected scorm: AddonModScormScorm,
scoId: number, protected scoId: number,
attempt: number, protected attempt: number,
userData: AddonModScormUserDataMap, protected userData: AddonModScormUserDataMap,
mode?: string, protected mode = AddonModScormProvider.MODENORMAL,
offline?: boolean, protected offline = false,
protected canSaveTracks = true,
) { ) {
this.siteId = siteId;
this.scorm = scorm;
this.scoId = scoId;
this.attempt = attempt;
this.mode = mode || AddonModScormProvider.MODENORMAL;
this.offline = !!offline;
this.init(userData); this.init(userData);
} }
@ -522,8 +510,9 @@ export class AddonModScormDataModel12 {
// Load default values. // Load default values.
for (const element in this.dataModel[scoId]) { for (const element in this.dataModel[scoId]) {
if (element.match(/\.n\./) === null) { if (element.match(/\.n\./) === null) {
if (this.dataModel[scoId][element].defaultvalue !== undefined) { const defaultValue = this.dataModel[scoId][element].defaultvalue;
this.currentUserData[scoId].userdata[element] = this.dataModel[scoId][element].defaultvalue!; if (defaultValue !== undefined) {
this.currentUserData[scoId].userdata[element] = defaultValue;
} }
} }
} }
@ -531,8 +520,9 @@ export class AddonModScormDataModel12 {
// Load initial user data for current SCO. // Load initial user data for current SCO.
for (const element in this.def[scoId]) { for (const element in this.def[scoId]) {
if (element.match(/\.n\./) === null) { if (element.match(/\.n\./) === null) {
if (this.dataModel[scoId][element].defaultvalue !== undefined) { const defaultValue = this.dataModel[scoId][element].defaultvalue;
this.currentUserData[scoId].userdata[element] = this.dataModel[scoId][element].defaultvalue!; if (defaultValue !== undefined) {
this.currentUserData[scoId].userdata[element] = defaultValue;
} else if (this.defExtra[scoId][element] !== undefined) { } else if (this.defExtra[scoId][element] !== undefined) {
// Check in user data values. // Check in user data values.
this.currentUserData[scoId].userdata[element] = this.defExtra[scoId][element]; this.currentUserData[scoId].userdata[element] = this.defExtra[scoId][element];
@ -820,7 +810,7 @@ export class AddonModScormDataModel12 {
if (this.dataModel[this.scoId][elementModel] !== undefined) { if (this.dataModel[this.scoId][elementModel] !== undefined) {
if (this.dataModel[this.scoId][elementModel].mod != 'r') { if (this.dataModel[this.scoId][elementModel].mod != 'r') {
expression = new RegExp(this.dataModel[this.scoId][elementModel].format!); expression = new RegExp(this.dataModel[this.scoId][elementModel].format ?? '');
value = value + ''; value = value + '';
const matches = value.match(expression); const matches = value.match(expression);
@ -981,6 +971,10 @@ export class AddonModScormDataModel12 {
* @return True if success, false otherwise. * @return True if success, false otherwise.
*/ */
protected storeData(storeTotalTime?: boolean): boolean { protected storeData(storeTotalTime?: boolean): boolean {
if (!this.canSaveTracks) {
return true;
}
let tracks: AddonModScormDataEntry[]; let tracks: AddonModScormDataEntry[];
if (storeTotalTime) { if (storeTotalTime) {

View File

@ -132,6 +132,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
} }
get canSaveTracks(): boolean {
return !this.accessInfo || !!this.accessInfo.cansavetrack;
}
/** /**
* Initialize. * Initialize.
* *
@ -235,9 +239,13 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
* Determine the attempt to use, the mode (normal/preview) and if it's offline or online. * Determine the attempt to use, the mode (normal/preview) and if it's offline or online.
* *
* @param attemptsData Attempts count. * @param attemptsData Attempts count.
* @param accessInfo Access info.
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
protected async determineAttemptAndMode(attemptsData: AddonModScormAttemptCountResult): Promise<void> { protected async determineAttemptAndMode(
attemptsData: AddonModScormAttemptCountResult,
accessInfo: AddonModScormGetScormAccessInformationWSResponse,
): Promise<void> {
const data = await AddonModScormHelper.determineAttemptToContinue(this.scorm, attemptsData); const data = await AddonModScormHelper.determineAttemptToContinue(this.scorm, attemptsData);
let incomplete = false; let incomplete = false;
@ -257,7 +265,14 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
} }
// Determine mode and attempt to use. // Determine mode and attempt to use.
const result = AddonModScorm.determineAttemptAndMode(this.scorm, this.mode, this.attempt, this.newAttempt, incomplete); const result = AddonModScorm.determineAttemptAndMode(
this.scorm,
this.mode,
this.attempt,
this.newAttempt,
incomplete,
accessInfo.cansavetrack,
);
if (result.attempt > this.attempt) { if (result.attempt > this.attempt) {
// We're creating a new attempt. // We're creating a new attempt.
@ -300,23 +315,26 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
try { try {
// Get attempts data. // Get attempts data.
const attemptsData = await AddonModScorm.getAttemptCount(this.scorm.id, { cmId: this.cmId }); const [attemptsData, accessInfo] = await Promise.all([
AddonModScorm.getAttemptCount(this.scorm.id, { cmId: this.cmId }),
AddonModScorm.getAccessInformation(this.scorm.id, {
cmId: this.cmId,
}),
]);
await this.determineAttemptAndMode(attemptsData); this.accessInfo = accessInfo;
const [data, accessInfo] = await Promise.all([ await this.determineAttemptAndMode(attemptsData, accessInfo);
const [data] = await Promise.all([
AddonModScorm.getScormUserData(this.scorm.id, this.attempt, { AddonModScorm.getScormUserData(this.scorm.id, this.attempt, {
cmId: this.cmId, cmId: this.cmId,
offline: this.offline, offline: this.offline,
}), }),
AddonModScorm.getAccessInformation(this.scorm.id, {
cmId: this.cmId,
}),
this.fetchToc(), this.fetchToc(),
]); ]);
this.userData = data; this.userData = data;
this.accessInfo = accessInfo;
} catch (error) { } catch (error) {
CoreDomUtils.showErrorModalDefault(error, 'addon.mod_scorm.errorgetscorm', true); CoreDomUtils.showErrorModalDefault(error, 'addon.mod_scorm.errorgetscorm', true);
} }
@ -397,9 +415,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
this.scorm, this.scorm,
sco.id, sco.id,
this.attempt, this.attempt,
this.userData!, this.userData ?? {},
this.mode, this.mode,
this.offline, this.offline,
this.canSaveTracks,
); );
// Add the model to the window so the SCORM can access it. // Add the model to the window so the SCORM can access it.
@ -453,6 +472,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
protected async markCompleted(sco: AddonModScormScoWithData): Promise<void> { protected async markCompleted(sco: AddonModScormScoWithData): Promise<void> {
if (!this.canSaveTracks) {
return;
}
const tracks = [{ const tracks = [{
element: 'cmi.core.lesson_status', element: 'cmi.core.lesson_status',
value: 'completed', value: 'completed',
@ -536,6 +559,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
* @return Promise resolved when done. * @return Promise resolved when done.
*/ */
protected async setStartTime(scoId: number): Promise<void> { protected async setStartTime(scoId: number): Promise<void> {
if (!this.canSaveTracks) {
return;
}
const tracks = [{ const tracks = [{
element: 'x.start.time', element: 'x.start.time',
value: String(CoreTimeUtils.timestamp()), value: String(CoreTimeUtils.timestamp()),

View File

@ -89,7 +89,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe
]); ]);
// Success, return the hash. // Success, return the hash.
return scorm.sha1hash!; return scorm.sha1hash ?? '';
} }
/** /**
@ -112,7 +112,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe
const packageUrl = AddonModScorm.getPackageUrl(scorm); const packageUrl = AddonModScorm.getPackageUrl(scorm);
// Get the folder where the unzipped files will be. // Get the folder where the unzipped files will be.
const dirPath = await AddonModScorm.getScormFolder(scorm.moduleurl!); const dirPath = await AddonModScorm.getScormFolder(scorm.moduleurl ?? '');
// Notify that the download is starting. // Notify that the download is starting.
onProgress && onProgress({ message: 'core.downloading' }); onProgress && onProgress({ message: 'core.downloading' });
@ -282,7 +282,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe
const scorm = await this.getScorm(module, courseId); const scorm = await this.getScorm(module, courseId);
// Get the folder where SCORM should be unzipped. // Get the folder where SCORM should be unzipped.
const path = await AddonModScorm.getScormFolder(scorm.moduleurl!); const path = await AddonModScorm.getScormFolder(scorm.moduleurl ?? '');
return CoreFile.getDirectorySize(path); return CoreFile.getDirectorySize(path);
} }
@ -388,7 +388,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe
const scorm = await this.getScorm(module, courseId, siteId); const scorm = await this.getScorm(module, courseId, siteId);
// Get the folder where SCORM should be unzipped. // Get the folder where SCORM should be unzipped.
const path = await AddonModScorm.getScormFolder(scorm.moduleurl!); const path = await AddonModScorm.getScormFolder(scorm.moduleurl ?? '');
const promises: Promise<unknown>[] = []; const promises: Promise<unknown>[] = [];

View File

@ -484,7 +484,7 @@ export class AddonModScormOfflineProvider {
response[scoId] = { response[scoId] = {
scoid: scoId, scoid: scoId,
userdata: { userdata: {
userid: userId!, userid: userId ?? site.getUserId(),
scoid: scoId, scoid: scoId,
timemodified: 0, timemodified: 0,
}, },
@ -492,7 +492,7 @@ export class AddonModScormOfflineProvider {
}; };
} }
response[scoId].userdata[entry.element] = entry.value!; response[scoId].userdata[entry.element] = entry.value ?? '';
if (entry.timemodified > Number(response[scoId].userdata.timemodified)) { if (entry.timemodified > Number(response[scoId].userdata.timemodified)) {
response[scoId].userdata.timemodified = entry.timemodified; response[scoId].userdata.timemodified = entry.timemodified;
} }

View File

@ -777,7 +777,7 @@ export class AddonModScormSyncProvider extends CoreCourseActivitySyncBaseProvide
lastOffline, lastOffline,
newAttemptsSameOrder, newAttemptsSameOrder,
newAttemptsAtEnd, newAttemptsAtEnd,
lastOfflineData.timecreated!, lastOfflineData.timecreated ?? 0,
lastOfflineData.incomplete, lastOfflineData.incomplete,
warnings, warnings,
siteId, siteId,
@ -812,7 +812,7 @@ export class AddonModScormSyncProvider extends CoreCourseActivitySyncBaseProvide
lastOffline, lastOffline,
newAttemptsSameOrder, newAttemptsSameOrder,
newAttemptsAtEnd, newAttemptsAtEnd,
lastOfflineData.timecreated!, lastOfflineData.timecreated ?? 0,
lastOfflineData.incomplete, lastOfflineData.incomplete,
warnings, warnings,
siteId, siteId,

View File

@ -206,6 +206,7 @@ export class AddonModScormProvider {
* @param attempt Current attempt. * @param attempt Current attempt.
* @param newAttempt Whether it should start a new attempt. * @param newAttempt Whether it should start a new attempt.
* @param incomplete Whether current attempt is incomplete. * @param incomplete Whether current attempt is incomplete.
* @param canSaveTracks Whether the user can save tracks.
* @return Mode, attempt number and whether to start a new attempt. * @return Mode, attempt number and whether to start a new attempt.
*/ */
determineAttemptAndMode( determineAttemptAndMode(
@ -214,7 +215,15 @@ export class AddonModScormProvider {
attempt: number, attempt: number,
newAttempt?: boolean, newAttempt?: boolean,
incomplete?: boolean, incomplete?: boolean,
canSaveTracks = true,
): {mode: string; attempt: number; newAttempt: boolean} { ): {mode: string; attempt: number; newAttempt: boolean} {
if (!canSaveTracks) {
return {
mode: scorm.hidebrowse ? AddonModScormProvider.MODENORMAL : mode,
attempt,
newAttempt: false,
};
}
if (mode == AddonModScormProvider.MODEBROWSE) { if (mode == AddonModScormProvider.MODEBROWSE) {
if (scorm.hidebrowse) { if (scorm.hidebrowse) {
@ -348,8 +357,8 @@ export class AddonModScormProvider {
element = '!'; element = '!';
} else if (reOther.test(element)) { } else if (reOther.test(element)) {
// Other symbols = | <> . // Other symbols = | <> .
matches = element.match(reOther)!; matches = element.match(reOther) ?? [];
element = matches[1].trim(); element = matches[1]?.trim();
if (trackData[element] !== undefined) { if (trackData[element] !== undefined) {
let value = matches[3].trim().replace(/('|")/gi, ''); let value = matches[3].trim().replace(/('|")/gi, '');
@ -959,7 +968,7 @@ export class AddonModScormProvider {
return launchUrl; return launchUrl;
} }
const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, scorm.moduleurl!); const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, scorm.moduleurl ?? '');
return CoreText.concatenatePaths(dirPath, launchUrl); return CoreText.concatenatePaths(dirPath, launchUrl);
} }
@ -1564,7 +1573,7 @@ export class AddonModScormProvider {
userData?: AddonModScormUserDataMap, userData?: AddonModScormUserDataMap,
): boolean { ): boolean {
if (offline) { if (offline) {
return AddonModScormOffline.saveTracksSync(scorm, scoId, attempt, tracks, userData!); return AddonModScormOffline.saveTracksSync(scorm, scoId, attempt, tracks, userData ?? {});
} else { } else {
const success = this.saveTracksSyncOnline(scoId, attempt, tracks); const success = this.saveTracksSyncOnline(scoId, attempt, tracks);