From 2b9fcbd041f6644c03a763f8deaadb63aa9d891c Mon Sep 17 00:00:00 2001 From: David Date: Wed, 4 Oct 2017 19:07:37 -0700 Subject: [PATCH 1/2] Absolute minimal fix for logging error, fixes #2253, fixes #2089. Removes log at exit (beforedestroy). --- .../learn/assets/src/views/assessment-wrapper/index.vue | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue b/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue index 216c63f238..1b527c9253 100644 --- a/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue +++ b/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue @@ -323,10 +323,6 @@ oriented data synchronization. this.$emit('stopTracking', ...args); }, }, - beforeDestroy() { - // Make sure any unsaved data is captured before tear down. - this.saveAttemptLogMasterLog(); - }, computed: { canLogInteractions() { return !this.isSuperuser && this.isUserLoggedIn; From ac2857eb9e748ec577b6ddc199285909457fc2a0 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 5 Oct 2017 10:15:52 -0700 Subject: [PATCH 2/2] Beefing up logic to handle last minute attempt logs beforeDestroy without race conditions. Wiping logging information clean on content page load for safety reasons. --- kolibri/core/assets/src/state/actions.js | 32 +++++++++++++------ .../plugins/learn/assets/src/state/actions.js | 2 ++ .../src/views/assessment-wrapper/index.vue | 27 ++++++++++++---- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/kolibri/core/assets/src/state/actions.js b/kolibri/core/assets/src/state/actions.js index fe0f9f510c..b2903b6b14 100644 --- a/kolibri/core/assets/src/state/actions.js +++ b/kolibri/core/assets/src/state/actions.js @@ -534,10 +534,13 @@ function saveMasteryLog(store) { const coreApp = require('kolibri'); const masteryLogModel = coreApp.resources.MasteryLog.getModel( store.state.core.logging.mastery.id); - masteryLogModel.save(_masteryLogModel(store)).only( + return masteryLogModel.save(_masteryLogModel(store)); +} + +function saveAndStoreMasteryLog(store) { + return saveMasteryLog(store).only( samePageCheckGenerator(store), - (newMasteryLog) => { - // Update store in case an id has been set. + newMasteryLog => { store.dispatch('SET_LOGGING_MASTERY_STATE', newMasteryLog); } ); @@ -602,12 +605,21 @@ function saveAttemptLog(store) { const attemptLogModel = coreApp.resources.AttemptLog.findModel({ item: store.state.core.logging.attempt.item }); - const promise = attemptLogModel.save(_attemptLogModel(store)); - promise.then((newAttemptLog) => { - // mainly we want to set the attemplot id, so we can PATCH subsequent save on this attemptLog - store.dispatch('SET_LOGGING_ATTEMPT_STATE', _attemptLoggingState(newAttemptLog)); - }); - return promise; + + if (attemptLogModel) { + return attemptLogModel.save(_attemptLogModel(store)); + } + return Promise.resolve(); +} + +function saveAndStoreAttemptLog(store) { + return saveAttemptLog(store).only( + samePageCheckGenerator(store), + newAttemptLog => { + // mainly we want to set the attemplot id, so we can PATCH subsequent save on this attemptLog + store.dispatch('SET_LOGGING_ATTEMPT_STATE', _attemptLoggingState(newAttemptLog)); + } + ); } function createAttemptLog(store, itemId) { @@ -726,10 +738,12 @@ module.exports = { samePageCheckGenerator, initMasteryLog, saveMasteryLog, + saveAndStoreMasteryLog, setMasteryLogComplete, createDummyMasteryLog, createAttemptLog, saveAttemptLog, + saveAndStoreAttemptLog, updateMasteryAttemptState, updateAttemptLogInteractionHistory, fetchPoints, diff --git a/kolibri/plugins/learn/assets/src/state/actions.js b/kolibri/plugins/learn/assets/src/state/actions.js index 27a1382b2b..ad34c306ef 100644 --- a/kolibri/plugins/learn/assets/src/state/actions.js +++ b/kolibri/plugins/learn/assets/src/state/actions.js @@ -235,6 +235,7 @@ function showExploreChannel(store, channelId) { function showExploreContent(store, channelId, id) { + store.dispatch('SET_EMPTY_LOGGING_STATE'); store.dispatch('CORE_SET_PAGE_LOADING', true); store.dispatch('SET_PAGE_NAME', PageNames.EXPLORE_CONTENT); @@ -325,6 +326,7 @@ function showLearnChannel(store, channelId, page = 1) { function showLearnContent(store, channelId, id) { + store.dispatch('SET_EMPTY_LOGGING_STATE'); store.dispatch('CORE_SET_PAGE_LOADING', true); store.dispatch('SET_PAGE_NAME', PageNames.LEARN_CONTENT); const channelPayload = { channel_id: channelId }; diff --git a/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue b/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue index 1b527c9253..37acbfa1a0 100644 --- a/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue +++ b/kolibri/plugins/learn/assets/src/views/assessment-wrapper/index.vue @@ -169,13 +169,21 @@ oriented data synchronization. simpleAnswer, }); }, - saveAttemptLogMasterLog() { - this.saveAttemptLogAction().then(() => { - if (this.canLogInteractions && this.success) { - this.setMasteryLogCompleteAction(now()); - this.saveMasteryLogAction(); - } - }); + saveAttemptLogMasterLog(updateStore = true) { + if (updateStore) { + this.saveAndStoreAttemptLogAction().then(() => { + if (this.canLogInteractions && this.success) { + this.setMasteryLogCompleteAction(now()); + this.saveAndStoreMasteryLogAction(); + } + }); + } else { + this.saveAttemptLogAction().then(() => { + if (this.canLogInteractions && this.success) { + this.saveMasteryLogAction(); + } + }); + } }, checkAnswer() { if (!this.checkingAnswer) { @@ -323,6 +331,9 @@ oriented data synchronization. this.$emit('stopTracking', ...args); }, }, + beforeDestroy() { + this.saveAttemptLogMasterLog(false); + }, computed: { canLogInteractions() { return !this.isSuperuser && this.isUserLoggedIn; @@ -380,9 +391,11 @@ oriented data synchronization. initMasteryLogAction: actions.initMasteryLog, createDummyMasteryLogAction: actions.createDummyMasteryLog, saveMasteryLogAction: actions.saveMasteryLog, + saveAndStoreMasteryLogAction: actions.saveAndStoreMasteryLog, setMasteryLogCompleteAction: actions.setMasteryLogComplete, createAttemptLogAction: actions.createAttemptLog, saveAttemptLogAction: actions.saveAttemptLog, + saveAndStoreAttemptLogAction: actions.saveAndStoreAttemptLog, updateMasteryAttemptStateAction: actions.updateMasteryAttemptState, updateAttemptLogInteractionHistoryAction: actions.updateAttemptLogInteractionHistory, updateExerciseProgress: actions.updateExerciseProgress,