MOBILE-4304 scorm: Update database usage
This commit is contained in:
		
							parent
							
								
									38d0ad1aad
								
							
						
					
					
						commit
						b6f32dfddd
					
				@ -13,7 +13,6 @@
 | 
				
			|||||||
// limitations under the License.
 | 
					// limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Injectable } from '@angular/core';
 | 
					import { Injectable } from '@angular/core';
 | 
				
			||||||
import { SQLiteDB } from '@classes/sqlitedb';
 | 
					 | 
				
			||||||
import { CoreUser } from '@features/user/services/user';
 | 
					import { CoreUser } from '@features/user/services/user';
 | 
				
			||||||
import { CoreSites } from '@services/sites';
 | 
					import { CoreSites } from '@services/sites';
 | 
				
			||||||
import { CoreSync } from '@services/sync';
 | 
					import { CoreSync } from '@services/sync';
 | 
				
			||||||
@ -38,6 +37,10 @@ import {
 | 
				
			|||||||
    AddonModScormUserDataMap,
 | 
					    AddonModScormUserDataMap,
 | 
				
			||||||
    AddonModScormWSSco,
 | 
					    AddonModScormWSSco,
 | 
				
			||||||
} from './scorm';
 | 
					} from './scorm';
 | 
				
			||||||
 | 
					import { lazyMap, LazyMap } from '@/core/utils/lazy-map';
 | 
				
			||||||
 | 
					import { asyncInstance, AsyncInstance } from '@/core/utils/async-instance';
 | 
				
			||||||
 | 
					import { CoreDatabaseTable } from '@classes/database/database-table';
 | 
				
			||||||
 | 
					import { CoreDatabaseCachingStrategy } from '@classes/database/database-table-proxy';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Service to handle offline SCORM.
 | 
					 * Service to handle offline SCORM.
 | 
				
			||||||
@ -47,8 +50,36 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    protected logger: CoreLogger;
 | 
					    protected logger: CoreLogger;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected tracksTables: LazyMap<
 | 
				
			||||||
 | 
					        AsyncInstance<CoreDatabaseTable<AddonModScormTrackDBRecord, 'scormid' | 'userid' | 'attempt' | 'scoid' | 'element'>>
 | 
				
			||||||
 | 
					    >;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected attemptsTables: LazyMap<
 | 
				
			||||||
 | 
					        AsyncInstance<CoreDatabaseTable<AddonModScormAttemptDBRecord, 'scormid' | 'userid' | 'attempt'>>
 | 
				
			||||||
 | 
					    >;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor() {
 | 
					    constructor() {
 | 
				
			||||||
        this.logger = CoreLogger.getInstance('AddonModScormOfflineProvider');
 | 
					        this.logger = CoreLogger.getInstance('AddonModScormOfflineProvider');
 | 
				
			||||||
 | 
					        this.tracksTables = lazyMap(
 | 
				
			||||||
 | 
					            siteId => asyncInstance(
 | 
				
			||||||
 | 
					                () => CoreSites.getSiteTable(TRACKS_TABLE_NAME, {
 | 
				
			||||||
 | 
					                    siteId,
 | 
				
			||||||
 | 
					                    primaryKeyColumns: ['scormid', 'userid', 'attempt', 'scoid', 'element'],
 | 
				
			||||||
 | 
					                    config: { cachingStrategy: CoreDatabaseCachingStrategy.None },
 | 
				
			||||||
 | 
					                    onDestroy: () => delete this.tracksTables[siteId],
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        this.attemptsTables = lazyMap(
 | 
				
			||||||
 | 
					            siteId => asyncInstance(
 | 
				
			||||||
 | 
					                () => CoreSites.getSiteTable(ATTEMPTS_TABLE_NAME, {
 | 
				
			||||||
 | 
					                    siteId,
 | 
				
			||||||
 | 
					                    primaryKeyColumns: ['scormid', 'userid', 'attempt'],
 | 
				
			||||||
 | 
					                    config: { cachingStrategy: CoreDatabaseCachingStrategy.None },
 | 
				
			||||||
 | 
					                    onDestroy: () => delete this.tracksTables[siteId],
 | 
				
			||||||
 | 
					                }),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@ -76,40 +107,43 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.logger.debug(`Change attempt number from ${attempt} to ${newAttempt} in SCORM ${scormId}`);
 | 
					        this.logger.debug(`Change attempt number from ${attempt} to ${newAttempt} in SCORM ${scormId}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Update the attempt number.
 | 
					 | 
				
			||||||
        const db = site.getDb();
 | 
					 | 
				
			||||||
        const currentAttemptConditions: AddonModScormOfflineDBCommonData = {
 | 
					 | 
				
			||||||
            scormid: scormId,
 | 
					 | 
				
			||||||
            userid: userId,
 | 
					 | 
				
			||||||
            attempt,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        const newAttemptConditions: AddonModScormOfflineDBCommonData = {
 | 
					 | 
				
			||||||
            scormid: scormId,
 | 
					 | 
				
			||||||
            userid: userId,
 | 
					 | 
				
			||||||
            attempt: newAttempt,
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        const newAttemptData: Partial<AddonModScormAttemptDBRecord> = {
 | 
					 | 
				
			||||||
            attempt: newAttempt,
 | 
					 | 
				
			||||||
            timemodified: CoreTimeUtils.timestamp(),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Block the SCORM so it can't be synced.
 | 
					        // Block the SCORM so it can't be synced.
 | 
				
			||||||
        CoreSync.blockOperation(AddonModScormProvider.COMPONENT, scormId, 'changeAttemptNumber', site.id);
 | 
					        CoreSync.blockOperation(AddonModScormProvider.COMPONENT, scormId, 'changeAttemptNumber', site.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            await db.updateRecords(ATTEMPTS_TABLE_NAME, newAttemptData, currentAttemptConditions);
 | 
					            const currentAttemptConditions = {
 | 
				
			||||||
 | 
					                sql: 'scormid = ? AND userid = ? AND attempt = ?',
 | 
				
			||||||
 | 
					                sqlParams: [scormId, userId, attempt],
 | 
				
			||||||
 | 
					                js: (record: AddonModScormOfflineDBCommonData) =>
 | 
				
			||||||
 | 
					                    record.scormid === scormId &&
 | 
				
			||||||
 | 
					                    record.userid === userId &&
 | 
				
			||||||
 | 
					                    record.attempt === attempt,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            await this.attemptsTables[site.id].updateWhere(
 | 
				
			||||||
 | 
					                { attempt: newAttempt, timemodified: CoreTimeUtils.timestamp() },
 | 
				
			||||||
 | 
					                currentAttemptConditions,
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            try {
 | 
					            try {
 | 
				
			||||||
                // Now update the attempt number of all the tracks and mark them as not synced.
 | 
					                // Now update the attempt number of all the tracks and mark them as not synced.
 | 
				
			||||||
                const newTrackData: Partial<AddonModScormTrackDBRecord> = {
 | 
					                await this.tracksTables[site.id].updateWhere(
 | 
				
			||||||
                    attempt: newAttempt,
 | 
					                    { attempt: newAttempt, synced: 0 },
 | 
				
			||||||
                    synced: 0,
 | 
					                    currentAttemptConditions,
 | 
				
			||||||
                };
 | 
					                );
 | 
				
			||||||
 | 
					 | 
				
			||||||
                await db.updateRecords(TRACKS_TABLE_NAME, newTrackData, currentAttemptConditions);
 | 
					 | 
				
			||||||
            } catch (error) {
 | 
					            } catch (error) {
 | 
				
			||||||
                // Failed to update the tracks, restore the old attempt number.
 | 
					                // Failed to update the tracks, restore the old attempt number.
 | 
				
			||||||
                await db.updateRecords(ATTEMPTS_TABLE_NAME, { attempt }, newAttemptConditions);
 | 
					                await this.attemptsTables[site.id].updateWhere(
 | 
				
			||||||
 | 
					                    { attempt },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                        sql: 'scormid = ? AND userid = ? AND attempt = ?',
 | 
				
			||||||
 | 
					                        sqlParams: [scormId, userId, newAttempt],
 | 
				
			||||||
 | 
					                        js: (attempt) =>
 | 
				
			||||||
 | 
					                            attempt.scormid === scormId &&
 | 
				
			||||||
 | 
					                            attempt.userid === userId &&
 | 
				
			||||||
 | 
					                            attempt.attempt === newAttempt,
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                throw error;
 | 
					                throw error;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -148,7 +182,6 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
        CoreSync.blockOperation(AddonModScormProvider.COMPONENT, scorm.id, 'createNewAttempt', site.id);
 | 
					        CoreSync.blockOperation(AddonModScormProvider.COMPONENT, scorm.id, 'createNewAttempt', site.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Create attempt in DB.
 | 
					        // Create attempt in DB.
 | 
				
			||||||
        const db = site.getDb();
 | 
					 | 
				
			||||||
        const entry: AddonModScormAttemptDBRecord = {
 | 
					        const entry: AddonModScormAttemptDBRecord = {
 | 
				
			||||||
            scormid: scorm.id,
 | 
					            scormid: scorm.id,
 | 
				
			||||||
            userid: userId,
 | 
					            userid: userId,
 | 
				
			||||||
@ -166,7 +199,7 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            await db.insertRecord(ATTEMPTS_TABLE_NAME, entry);
 | 
					            await this.attemptsTables[site.id].insert(entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Store all the data in userData.
 | 
					            // Store all the data in userData.
 | 
				
			||||||
            const promises: Promise<void>[] = [];
 | 
					            const promises: Promise<void>[] = [];
 | 
				
			||||||
@ -204,16 +237,15 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.logger.debug(`Delete offline attempt ${attempt} in SCORM ${scormId}`);
 | 
					        this.logger.debug(`Delete offline attempt ${attempt} in SCORM ${scormId}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const db = site.getDb();
 | 
					        const conditions = {
 | 
				
			||||||
        const conditions: AddonModScormOfflineDBCommonData = {
 | 
					 | 
				
			||||||
            scormid: scormId,
 | 
					            scormid: scormId,
 | 
				
			||||||
            userid: userId,
 | 
					            userid: userId,
 | 
				
			||||||
            attempt,
 | 
					            attempt,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await Promise.all([
 | 
					        await Promise.all([
 | 
				
			||||||
            db.deleteRecords(ATTEMPTS_TABLE_NAME, conditions),
 | 
					            this.attemptsTables[site.id].delete(conditions),
 | 
				
			||||||
            db.deleteRecords(TRACKS_TABLE_NAME, conditions),
 | 
					            this.tracksTables[site.id].delete(conditions),
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -280,9 +312,9 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
     * @returns Promise resolved when the offline attempts are retrieved.
 | 
					     * @returns Promise resolved when the offline attempts are retrieved.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    async getAllAttempts(siteId?: string): Promise<AddonModScormOfflineAttempt[]> {
 | 
					    async getAllAttempts(siteId?: string): Promise<AddonModScormOfflineAttempt[]> {
 | 
				
			||||||
        const db = await CoreSites.getSiteDb(siteId);
 | 
					        siteId ??= CoreSites.getCurrentSiteId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const attempts = await db.getAllRecords<AddonModScormAttemptDBRecord>(ATTEMPTS_TABLE_NAME);
 | 
					        const attempts = await this.attemptsTables[siteId].getMany();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return attempts.map((attempt) => this.parseAttempt(attempt));
 | 
					        return attempts.map((attempt) => this.parseAttempt(attempt));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -300,7 +332,7 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
        const site = await CoreSites.getSite(siteId);
 | 
					        const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
        userId = userId || site.getUserId();
 | 
					        userId = userId || site.getUserId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const attemptRecord = await site.getDb().getRecord<AddonModScormAttemptDBRecord>(ATTEMPTS_TABLE_NAME, {
 | 
					        const attemptRecord = await this.attemptsTables[site.id].getOneByPrimaryKey({
 | 
				
			||||||
            scormid: scormId,
 | 
					            scormid: scormId,
 | 
				
			||||||
            userid: userId,
 | 
					            userid: userId,
 | 
				
			||||||
            attempt,
 | 
					            attempt,
 | 
				
			||||||
@ -340,7 +372,7 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
        const site = await CoreSites.getSite(siteId);
 | 
					        const site = await CoreSites.getSite(siteId);
 | 
				
			||||||
        userId = userId || site.getUserId();
 | 
					        userId = userId || site.getUserId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const attempts = await site.getDb().getRecords<AddonModScormAttemptDBRecord>(ATTEMPTS_TABLE_NAME, {
 | 
					        const attempts = await this.attemptsTables[site.id].getMany({
 | 
				
			||||||
            scormid: scormId,
 | 
					            scormid: scormId,
 | 
				
			||||||
            userid: userId,
 | 
					            userid: userId,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
@ -428,7 +460,7 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
            conditions.synced = 1;
 | 
					            conditions.synced = 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const tracks = await site.getDb().getRecords<AddonModScormTrackDBRecord>(TRACKS_TABLE_NAME, conditions);
 | 
					        const tracks = await this.tracksTables[site.id].getMany(conditions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return this.parseTracks(tracks);
 | 
					        return this.parseTracks(tracks);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -598,7 +630,6 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
        userId = userId || site.getUserId();
 | 
					        userId = userId || site.getUserId();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const scoUserData = scoData?.userdata || {};
 | 
					        const scoUserData = scoData?.userdata || {};
 | 
				
			||||||
        const db = site.getDb();
 | 
					 | 
				
			||||||
        let lessonStatusInserted = false;
 | 
					        let lessonStatusInserted = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (forceCompleted) {
 | 
					        if (forceCompleted) {
 | 
				
			||||||
@ -611,7 +642,16 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
                if (scoUserData['cmi.core.lesson_status'] == 'incomplete') {
 | 
					                if (scoUserData['cmi.core.lesson_status'] == 'incomplete') {
 | 
				
			||||||
                    lessonStatusInserted = true;
 | 
					                    lessonStatusInserted = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    await this.insertTrackToDB(db, userId, scormId, scoId, attempt, 'cmi.core.lesson_status', 'completed');
 | 
					                    await this.tracksTables[site.id].insert({
 | 
				
			||||||
 | 
					                        userid: userId,
 | 
				
			||||||
 | 
					                        scormid: scormId,
 | 
				
			||||||
 | 
					                        scoid: scoId,
 | 
				
			||||||
 | 
					                        attempt,
 | 
				
			||||||
 | 
					                        element: 'cmi.core.lesson_status',
 | 
				
			||||||
 | 
					                        value: JSON.stringify('completed'),
 | 
				
			||||||
 | 
					                        timemodified: CoreTimeUtils.timestamp(),
 | 
				
			||||||
 | 
					                        synced: 0,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -622,78 +662,32 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            await this.insertTrackToDB(db, userId, scormId, scoId, attempt, element, value);
 | 
					            await this.tracksTables[site.id].insert({
 | 
				
			||||||
        } catch (error) {
 | 
					 | 
				
			||||||
            if (lessonStatusInserted) {
 | 
					 | 
				
			||||||
                // Rollback previous insert.
 | 
					 | 
				
			||||||
                await this.insertTrackToDB(db, userId, scormId, scoId, attempt, 'cmi.core.lesson_status', 'incomplete');
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            throw error;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Insert a track in the DB.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param db Site's DB.
 | 
					 | 
				
			||||||
     * @param userId User ID.
 | 
					 | 
				
			||||||
     * @param scormId SCORM ID.
 | 
					 | 
				
			||||||
     * @param scoId SCO ID.
 | 
					 | 
				
			||||||
     * @param attempt Attempt number.
 | 
					 | 
				
			||||||
     * @param element Name of the element to insert.
 | 
					 | 
				
			||||||
     * @param value Value of the element to insert.
 | 
					 | 
				
			||||||
     * @param synchronous True if insert should NOT return a promise. Please use it only if synchronous is a must.
 | 
					 | 
				
			||||||
     * @returns Returns a promise if synchronous=false, otherwise returns a boolean.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    protected insertTrackToDB(
 | 
					 | 
				
			||||||
        db: SQLiteDB,
 | 
					 | 
				
			||||||
        userId: number,
 | 
					 | 
				
			||||||
        scormId: number,
 | 
					 | 
				
			||||||
        scoId: number,
 | 
					 | 
				
			||||||
        attempt: number,
 | 
					 | 
				
			||||||
        element: string,
 | 
					 | 
				
			||||||
        value: AddonModScormDataValue | undefined,
 | 
					 | 
				
			||||||
        synchronous: true,
 | 
					 | 
				
			||||||
    ): boolean;
 | 
					 | 
				
			||||||
    protected insertTrackToDB(
 | 
					 | 
				
			||||||
        db: SQLiteDB,
 | 
					 | 
				
			||||||
        userId: number,
 | 
					 | 
				
			||||||
        scormId: number,
 | 
					 | 
				
			||||||
        scoId: number,
 | 
					 | 
				
			||||||
        attempt: number,
 | 
					 | 
				
			||||||
        element: string,
 | 
					 | 
				
			||||||
        value?: AddonModScormDataValue,
 | 
					 | 
				
			||||||
        synchronous?: false,
 | 
					 | 
				
			||||||
    ): Promise<number>;
 | 
					 | 
				
			||||||
    protected insertTrackToDB(
 | 
					 | 
				
			||||||
        db: SQLiteDB,
 | 
					 | 
				
			||||||
        userId: number,
 | 
					 | 
				
			||||||
        scormId: number,
 | 
					 | 
				
			||||||
        scoId: number,
 | 
					 | 
				
			||||||
        attempt: number,
 | 
					 | 
				
			||||||
        element: string,
 | 
					 | 
				
			||||||
        value?: AddonModScormDataValue,
 | 
					 | 
				
			||||||
        synchronous?: boolean,
 | 
					 | 
				
			||||||
    ): boolean | Promise<number> {
 | 
					 | 
				
			||||||
        const entry: AddonModScormTrackDBRecord = {
 | 
					 | 
				
			||||||
                userid: userId,
 | 
					                userid: userId,
 | 
				
			||||||
                scormid: scormId,
 | 
					                scormid: scormId,
 | 
				
			||||||
                scoid: scoId,
 | 
					                scoid: scoId,
 | 
				
			||||||
                attempt,
 | 
					                attempt,
 | 
				
			||||||
            element: element,
 | 
					                element,
 | 
				
			||||||
                value: value === undefined ? null : JSON.stringify(value),
 | 
					                value: value === undefined ? null : JSON.stringify(value),
 | 
				
			||||||
                timemodified: CoreTimeUtils.timestamp(),
 | 
					                timemodified: CoreTimeUtils.timestamp(),
 | 
				
			||||||
                synced: 0,
 | 
					                synced: 0,
 | 
				
			||||||
        };
 | 
					            });
 | 
				
			||||||
 | 
					        } catch (error) {
 | 
				
			||||||
 | 
					            if (lessonStatusInserted) {
 | 
				
			||||||
 | 
					                // Rollback previous insert.
 | 
				
			||||||
 | 
					                await this.tracksTables[site.id].insert({
 | 
				
			||||||
 | 
					                    userid: userId,
 | 
				
			||||||
 | 
					                    scormid: scormId,
 | 
				
			||||||
 | 
					                    scoid: scoId,
 | 
				
			||||||
 | 
					                    attempt,
 | 
				
			||||||
 | 
					                    element: 'cmi.core.lesson_status',
 | 
				
			||||||
 | 
					                    value: JSON.stringify('incomplete'),
 | 
				
			||||||
 | 
					                    timemodified: CoreTimeUtils.timestamp(),
 | 
				
			||||||
 | 
					                    synced: 0,
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (synchronous) {
 | 
					            throw error;
 | 
				
			||||||
            // The insert operation is always asynchronous, always return true.
 | 
					 | 
				
			||||||
            db.insertRecord(TRACKS_TABLE_NAME, entry);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            return db.insertRecord(TRACKS_TABLE_NAME, entry);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -730,8 +724,7 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const scoUserData = scoData?.userdata || {};
 | 
					        const scoUserData = scoData?.userdata || {};
 | 
				
			||||||
        const db = CoreSites.getRequiredCurrentSite().getDb();
 | 
					        const siteId = CoreSites.getRequiredCurrentSite().id;
 | 
				
			||||||
        let lessonStatusInserted = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (forceCompleted) {
 | 
					        if (forceCompleted) {
 | 
				
			||||||
            if (element == 'cmi.core.lesson_status' && value == 'incomplete') {
 | 
					            if (element == 'cmi.core.lesson_status' && value == 'incomplete') {
 | 
				
			||||||
@ -741,11 +734,16 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            if (element == 'cmi.core.score.raw') {
 | 
					            if (element == 'cmi.core.score.raw') {
 | 
				
			||||||
                if (scoUserData['cmi.core.lesson_status'] == 'incomplete') {
 | 
					                if (scoUserData['cmi.core.lesson_status'] == 'incomplete') {
 | 
				
			||||||
                    lessonStatusInserted = true;
 | 
					                    this.tracksTables[siteId].syncInsert({
 | 
				
			||||||
 | 
					                        userid: userId,
 | 
				
			||||||
                    if (!this.insertTrackToDB(db, userId, scormId, scoId, attempt, 'cmi.core.lesson_status', 'completed', true)) {
 | 
					                        scormid: scormId,
 | 
				
			||||||
                        return false;
 | 
					                        scoid: scoId,
 | 
				
			||||||
                    }
 | 
					                        attempt,
 | 
				
			||||||
 | 
					                        element: 'cmi.core.lesson_status',
 | 
				
			||||||
 | 
					                        value: JSON.stringify('completed'),
 | 
				
			||||||
 | 
					                        timemodified: CoreTimeUtils.timestamp(),
 | 
				
			||||||
 | 
					                        synced: 0,
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -755,15 +753,16 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!this.insertTrackToDB(db, userId, scormId, scoId, attempt, element, value, true)) {
 | 
					        this.tracksTables[siteId].syncInsert({
 | 
				
			||||||
            // Insert failed.
 | 
					            userid: userId,
 | 
				
			||||||
            if (lessonStatusInserted) {
 | 
					            scormid: scormId,
 | 
				
			||||||
                // Rollback previous insert.
 | 
					            scoid: scoId,
 | 
				
			||||||
                this.insertTrackToDB(db, userId, scormId, scoId, attempt, 'cmi.core.lesson_status', 'incomplete', true);
 | 
					            attempt,
 | 
				
			||||||
            }
 | 
					            element: element,
 | 
				
			||||||
 | 
					            value: value === undefined ? null : JSON.stringify(value),
 | 
				
			||||||
            return false;
 | 
					            timemodified: CoreTimeUtils.timestamp(),
 | 
				
			||||||
        }
 | 
					            synced: 0,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -784,7 +783,7 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        this.logger.debug(`Mark SCO ${scoId} as synced for attempt ${attempt} in SCORM ${scormId}`);
 | 
					        this.logger.debug(`Mark SCO ${scoId} as synced for attempt ${attempt} in SCORM ${scormId}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await site.getDb().updateRecords(TRACKS_TABLE_NAME, { synced: 1 }, <Partial<AddonModScormTrackDBRecord>> {
 | 
					        await this.tracksTables[site.id].update({ synced: 1 }, {
 | 
				
			||||||
            scormid: scormId,
 | 
					            scormid: scormId,
 | 
				
			||||||
            userid: userId,
 | 
					            userid: userId,
 | 
				
			||||||
            attempt,
 | 
					            attempt,
 | 
				
			||||||
@ -971,10 +970,13 @@ export class AddonModScormOfflineProvider {
 | 
				
			|||||||
            snapshot: JSON.stringify(this.removeDefaultData(userData)),
 | 
					            snapshot: JSON.stringify(this.removeDefaultData(userData)),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await site.getDb().updateRecords(ATTEMPTS_TABLE_NAME, newData, <Partial<AddonModScormAttemptDBRecord>> {
 | 
					        await this.attemptsTables[site.id].updateWhere(newData, {
 | 
				
			||||||
            scormid: scormId,
 | 
					            sql: 'scormid = ? AND userid = ? AND attempt = ?',
 | 
				
			||||||
            userid: userId,
 | 
					            sqlParams: [scormId, userId, attempt],
 | 
				
			||||||
            attempt,
 | 
					            js: (record: AddonModScormOfflineDBCommonData) =>
 | 
				
			||||||
 | 
					                record.scormid === scormId &&
 | 
				
			||||||
 | 
					                record.userid === userId &&
 | 
				
			||||||
 | 
					                record.attempt === attempt,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -258,6 +258,18 @@ export class CoreDatabaseTable<
 | 
				
			|||||||
        await this.database.insertRecord(this.tableName, record);
 | 
					        await this.database.insertRecord(this.tableName, record);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Insert a new record synchronously.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param record Database record.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    syncInsert(record: DBRecord): void {
 | 
				
			||||||
 | 
					        // The current database architecture does not support synchronous operations,
 | 
				
			||||||
 | 
					        // so calling this method will mean that errors will be silenced. Because of that,
 | 
				
			||||||
 | 
					        // this should only be called if using the asynchronous alternatives is not possible.
 | 
				
			||||||
 | 
					        this.insert(record);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Update records matching the given conditions.
 | 
					     * Update records matching the given conditions.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user