From 7b5a5bed8f4c8c28f627b99d8ffc0ae795b15b5e Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Mon, 20 Jun 2022 15:05:51 +0200 Subject: [PATCH 1/2] MOBILE-4099 scorm: Don't call WS if user cannot save tracks --- src/addons/mod/scorm/classes/data-model-12.ts | 34 ++++++-------- src/addons/mod/scorm/pages/player/player.ts | 45 +++++++++++++++---- src/addons/mod/scorm/services/scorm.ts | 9 ++++ 3 files changed, 58 insertions(+), 30 deletions(-) diff --git a/src/addons/mod/scorm/classes/data-model-12.ts b/src/addons/mod/scorm/classes/data-model-12.ts index 8c82d6876..3fb1609cd 100644 --- a/src/addons/mod/scorm/classes/data-model-12.ts +++ b/src/addons/mod/scorm/classes/data-model-12.ts @@ -93,13 +93,6 @@ export class AddonModScormDataModel12 { protected errorCode = '0'; // Last error. 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. * @@ -110,23 +103,18 @@ export class AddonModScormDataModel12 { * @param userData The user default data. * @param mode Mode being played. By default, MODENORMAL. * @param offline Whether the attempt is offline. + * @param canSaveTracks Whether the user can save tracks. */ constructor( - siteId: string, - scorm: AddonModScormScorm, - scoId: number, - attempt: number, - userData: AddonModScormUserDataMap, - mode?: string, - offline?: boolean, + protected siteId: string, + protected scorm: AddonModScormScorm, + protected scoId: number, + protected attempt: number, + protected userData: AddonModScormUserDataMap, + protected mode = AddonModScormProvider.MODENORMAL, + 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); } @@ -981,6 +969,10 @@ export class AddonModScormDataModel12 { * @return True if success, false otherwise. */ protected storeData(storeTotalTime?: boolean): boolean { + if (!this.canSaveTracks) { + return true; + } + let tracks: AddonModScormDataEntry[]; if (storeTotalTime) { diff --git a/src/addons/mod/scorm/pages/player/player.ts b/src/addons/mod/scorm/pages/player/player.ts index d6dabb226..cdf25d82b 100644 --- a/src/addons/mod/scorm/pages/player/player.ts +++ b/src/addons/mod/scorm/pages/player/player.ts @@ -132,6 +132,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { } + get canSaveTracks(): boolean { + return !this.accessInfo || !!this.accessInfo.cansavetrack; + } + /** * 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. * * @param attemptsData Attempts count. + * @param accessInfo Access info. * @return Promise resolved when done. */ - protected async determineAttemptAndMode(attemptsData: AddonModScormAttemptCountResult): Promise { + protected async determineAttemptAndMode( + attemptsData: AddonModScormAttemptCountResult, + accessInfo: AddonModScormGetScormAccessInformationWSResponse, + ): Promise { const data = await AddonModScormHelper.determineAttemptToContinue(this.scorm, attemptsData); let incomplete = false; @@ -257,7 +265,14 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { } // 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) { // We're creating a new attempt. @@ -300,23 +315,26 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { try { // 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, { cmId: this.cmId, offline: this.offline, }), - AddonModScorm.getAccessInformation(this.scorm.id, { - cmId: this.cmId, - }), this.fetchToc(), ]); this.userData = data; - this.accessInfo = accessInfo; } catch (error) { CoreDomUtils.showErrorModalDefault(error, 'addon.mod_scorm.errorgetscorm', true); } @@ -400,6 +418,7 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { this.userData!, this.mode, this.offline, + this.canSaveTracks, ); // 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. */ protected async markCompleted(sco: AddonModScormScoWithData): Promise { + if (!this.canSaveTracks) { + return; + } + const tracks = [{ element: 'cmi.core.lesson_status', value: 'completed', @@ -536,6 +559,10 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { * @return Promise resolved when done. */ protected async setStartTime(scoId: number): Promise { + if (!this.canSaveTracks) { + return; + } + const tracks = [{ element: 'x.start.time', value: String(CoreTimeUtils.timestamp()), diff --git a/src/addons/mod/scorm/services/scorm.ts b/src/addons/mod/scorm/services/scorm.ts index 27bb5c945..87c9fa072 100644 --- a/src/addons/mod/scorm/services/scorm.ts +++ b/src/addons/mod/scorm/services/scorm.ts @@ -206,6 +206,7 @@ export class AddonModScormProvider { * @param attempt Current attempt. * @param newAttempt Whether it should start a new attempt. * @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. */ determineAttemptAndMode( @@ -214,7 +215,15 @@ export class AddonModScormProvider { attempt: number, newAttempt?: boolean, incomplete?: boolean, + canSaveTracks = true, ): {mode: string; attempt: number; newAttempt: boolean} { + if (!canSaveTracks) { + return { + mode: scorm.hidebrowse ? AddonModScormProvider.MODENORMAL : mode, + attempt, + newAttempt: false, + }; + } if (mode == AddonModScormProvider.MODEBROWSE) { if (scorm.hidebrowse) { From fad887aa65eb270876c46bb05f0aac3488327768 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Tue, 21 Jun 2022 08:20:57 +0200 Subject: [PATCH 2/2] MOBILE-4099 scorm: Remove some non-null assertions --- src/addons/mod/scorm/classes/data-model-12.ts | 12 +++++++----- src/addons/mod/scorm/pages/player/player.ts | 2 +- src/addons/mod/scorm/services/handlers/prefetch.ts | 8 ++++---- src/addons/mod/scorm/services/scorm-offline.ts | 4 ++-- src/addons/mod/scorm/services/scorm-sync.ts | 4 ++-- src/addons/mod/scorm/services/scorm.ts | 8 ++++---- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/addons/mod/scorm/classes/data-model-12.ts b/src/addons/mod/scorm/classes/data-model-12.ts index 3fb1609cd..7f7f48582 100644 --- a/src/addons/mod/scorm/classes/data-model-12.ts +++ b/src/addons/mod/scorm/classes/data-model-12.ts @@ -510,8 +510,9 @@ export class AddonModScormDataModel12 { // Load default values. for (const element in this.dataModel[scoId]) { if (element.match(/\.n\./) === null) { - if (this.dataModel[scoId][element].defaultvalue !== undefined) { - this.currentUserData[scoId].userdata[element] = this.dataModel[scoId][element].defaultvalue!; + const defaultValue = this.dataModel[scoId][element].defaultvalue; + if (defaultValue !== undefined) { + this.currentUserData[scoId].userdata[element] = defaultValue; } } } @@ -519,8 +520,9 @@ export class AddonModScormDataModel12 { // Load initial user data for current SCO. for (const element in this.def[scoId]) { if (element.match(/\.n\./) === null) { - if (this.dataModel[scoId][element].defaultvalue !== undefined) { - this.currentUserData[scoId].userdata[element] = this.dataModel[scoId][element].defaultvalue!; + const defaultValue = this.dataModel[scoId][element].defaultvalue; + if (defaultValue !== undefined) { + this.currentUserData[scoId].userdata[element] = defaultValue; } else if (this.defExtra[scoId][element] !== undefined) { // Check in user data values. this.currentUserData[scoId].userdata[element] = this.defExtra[scoId][element]; @@ -808,7 +810,7 @@ export class AddonModScormDataModel12 { if (this.dataModel[this.scoId][elementModel] !== undefined) { 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 + ''; const matches = value.match(expression); diff --git a/src/addons/mod/scorm/pages/player/player.ts b/src/addons/mod/scorm/pages/player/player.ts index cdf25d82b..8303adb5d 100644 --- a/src/addons/mod/scorm/pages/player/player.ts +++ b/src/addons/mod/scorm/pages/player/player.ts @@ -415,7 +415,7 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy { this.scorm, sco.id, this.attempt, - this.userData!, + this.userData ?? {}, this.mode, this.offline, this.canSaveTracks, diff --git a/src/addons/mod/scorm/services/handlers/prefetch.ts b/src/addons/mod/scorm/services/handlers/prefetch.ts index c4ffb9112..b935d1f61 100644 --- a/src/addons/mod/scorm/services/handlers/prefetch.ts +++ b/src/addons/mod/scorm/services/handlers/prefetch.ts @@ -89,7 +89,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe ]); // Success, return the hash. - return scorm.sha1hash!; + return scorm.sha1hash ?? ''; } /** @@ -112,7 +112,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe const packageUrl = AddonModScorm.getPackageUrl(scorm); // 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. onProgress && onProgress({ message: 'core.downloading' }); @@ -282,7 +282,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe const scorm = await this.getScorm(module, courseId); // 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); } @@ -388,7 +388,7 @@ export class AddonModScormPrefetchHandlerService extends CoreCourseActivityPrefe const scorm = await this.getScorm(module, courseId, siteId); // 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[] = []; diff --git a/src/addons/mod/scorm/services/scorm-offline.ts b/src/addons/mod/scorm/services/scorm-offline.ts index 9f9874486..a7a188102 100644 --- a/src/addons/mod/scorm/services/scorm-offline.ts +++ b/src/addons/mod/scorm/services/scorm-offline.ts @@ -484,7 +484,7 @@ export class AddonModScormOfflineProvider { response[scoId] = { scoid: scoId, userdata: { - userid: userId!, + userid: userId ?? site.getUserId(), scoid: scoId, 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)) { response[scoId].userdata.timemodified = entry.timemodified; } diff --git a/src/addons/mod/scorm/services/scorm-sync.ts b/src/addons/mod/scorm/services/scorm-sync.ts index 19d073614..f3100d10c 100644 --- a/src/addons/mod/scorm/services/scorm-sync.ts +++ b/src/addons/mod/scorm/services/scorm-sync.ts @@ -777,7 +777,7 @@ export class AddonModScormSyncProvider extends CoreCourseActivitySyncBaseProvide lastOffline, newAttemptsSameOrder, newAttemptsAtEnd, - lastOfflineData.timecreated!, + lastOfflineData.timecreated ?? 0, lastOfflineData.incomplete, warnings, siteId, @@ -812,7 +812,7 @@ export class AddonModScormSyncProvider extends CoreCourseActivitySyncBaseProvide lastOffline, newAttemptsSameOrder, newAttemptsAtEnd, - lastOfflineData.timecreated!, + lastOfflineData.timecreated ?? 0, lastOfflineData.incomplete, warnings, siteId, diff --git a/src/addons/mod/scorm/services/scorm.ts b/src/addons/mod/scorm/services/scorm.ts index 87c9fa072..756721a61 100644 --- a/src/addons/mod/scorm/services/scorm.ts +++ b/src/addons/mod/scorm/services/scorm.ts @@ -357,8 +357,8 @@ export class AddonModScormProvider { element = '!'; } else if (reOther.test(element)) { // Other symbols = | <> . - matches = element.match(reOther)!; - element = matches[1].trim(); + matches = element.match(reOther) ?? []; + element = matches[1]?.trim(); if (trackData[element] !== undefined) { let value = matches[3].trim().replace(/('|")/gi, ''); @@ -968,7 +968,7 @@ export class AddonModScormProvider { return launchUrl; } - const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, scorm.moduleurl!); + const dirPath = await CoreFilepool.getPackageDirUrlByUrl(siteId, scorm.moduleurl ?? ''); return CoreText.concatenatePaths(dirPath, launchUrl); } @@ -1573,7 +1573,7 @@ export class AddonModScormProvider { userData?: AddonModScormUserDataMap, ): boolean { if (offline) { - return AddonModScormOffline.saveTracksSync(scorm, scoId, attempt, tracks, userData!); + return AddonModScormOffline.saveTracksSync(scorm, scoId, attempt, tracks, userData ?? {}); } else { const success = this.saveTracksSyncOnline(scoId, attempt, tracks);