Browse Source

Add ajax call to save exercise duration when page unload see BT#14149

jmontoyaa 7 years ago
parent
commit
2e091a9b2f

+ 2 - 0
main/exercise/exercise.php

@@ -72,6 +72,8 @@ Session::erase('objAnswer');
 Session::erase('questionList');
 Session::erase('exerciseResult');
 Session::erase('firstTime');
+Session::erase('duration_time_previous');
+Session::erase('duration_time');
 
 //General POST/GET/SESSION/COOKIES parameters recovery
 $origin = api_get_origin();

+ 4 - 0
main/exercise/exercise_result.php

@@ -203,6 +203,8 @@ if ($origin != 'learnpath') {
     if (api_is_allowed_to_session_edit()) {
         Session::erase('objExercise');
         Session::erase('exe_id');
+        Session::erase('duration_time_previous');
+        Session::erase('duration_time');
     }
     Display::display_footer();
 } else {
@@ -213,6 +215,8 @@ if ($origin != 'learnpath') {
     if (api_is_allowed_to_session_edit()) {
         Session::erase('objExercise');
         Session::erase('exe_id');
+        Session::erase('duration_time_previous');
+        Session::erase('duration_time');
     }
 
     Session::write('attempt_remaining', $remainingMessage);

+ 24 - 5
main/exercise/exercise_submit.php

@@ -95,7 +95,6 @@ $endExercise = isset($_REQUEST['end_exercise']) && $_REQUEST['end_exercise'] ==
 
 // Error message
 $error = '';
-
 $exercise_attempt_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
 
 /*  Teacher takes an exam and want to see a preview,
@@ -186,7 +185,15 @@ $current_expired_time_key = ExerciseLib::get_time_control_key(
     $learnpath_item_id
 );
 
-$_SESSION['duration_time'][$current_expired_time_key] = $current_timestamp;
+Session::write('duration_time_previous', [$current_expired_time_key => $current_timestamp]);
+$durationTime = Session::read('duration_time');
+if (!empty($durationTime) && isset($durationTime[$current_expired_time_key])) {
+    Session::write(
+        'duration_time_previous',
+        [$current_expired_time_key => $durationTime[$current_expired_time_key]]
+    );
+}
+Session::write('duration_time', [$current_expired_time_key => $current_timestamp]);
 
 if ($time_control) {
     // Get the expired time of the current exercise in track_e_exercises
@@ -412,6 +419,7 @@ if (empty($exercise_stat_info)) {
     }
 }
 
+$saveDurationUrl = api_get_path(WEB_AJAX_PATH).'exercise.ajax.php?a=update_duration&exe_id='.$exe_id.'&'.api_get_cidreq();
 $questionListInSession = Session::read('questionList');
 
 if (!isset($questionListInSession)) {
@@ -1069,9 +1077,7 @@ if (!empty($error)) {
             });*/
 
             $(\'form#exercise_form\').prepend($(\'#exercise-description\'));
-        });
-
-        $(document).on(\'ready\', function () {
+        
             $(\'button[name="previous_question_and_save"]\').on(\'click\', function (e) {
                 e.preventDefault();
                 e.stopPropagation();
@@ -1113,6 +1119,19 @@ if (!empty($error)) {
                 
                 validate_all();
             });
+            
+            var saveDurationUrl = "'.$saveDurationUrl.'";
+            
+            // Save attempt duration
+            $(window).on(\'beforeunload\', function () {
+                // Logout of course just in case
+                $.ajax({
+                    url: saveDurationUrl,
+                    success: function (data) {
+                        return 1;
+                    }
+                });
+            });
         });
 
         function previous_question(question_num) {

+ 2 - 0
main/exercise/overview.php

@@ -16,6 +16,8 @@ $current_course_tool = TOOL_QUIZ;
 
 // Clear the exercise session just in case
 Session::erase('objExercise');
+Session::erase('duration_time_previous');
+Session::erase('duration_time');
 
 $this_section = SECTION_COURSES;
 

+ 88 - 3
main/inc/ajax/exercise.ajax.php

@@ -21,6 +21,89 @@ $session_id = isset($_REQUEST['session_id']) ? intval($_REQUEST['session_id']) :
 $course_code = isset($_REQUEST['cidReq']) ? $_REQUEST['cidReq'] : api_get_course_id();
 
 switch ($action) {
+    case 'update_duration':
+        $debug = true;
+        $exeId = isset($_REQUEST['exe_id']) ? $_REQUEST['exe_id'] : 0;
+        /** @var Exercise $exerciseInSession */
+        $exerciseInSession = Session::read('objExercise');
+        if (!empty($exeId) && !empty($exerciseInSession)) {
+            $em = Database::getManager();
+            /** @var \Chamilo\CoreBundle\Entity\TrackEExercises $attempt */
+            $attempt = $em->getRepository('ChamiloCoreBundle:TrackEExercises')->find($exeId);
+            $onlyUpdateValue = 10;
+            $nowObject = api_get_utc_datetime(null, false, true);
+            $now = $nowObject->getTimestamp();
+            $exerciseId = $attempt->getExeExoId();
+            $userId = $attempt->getExeUserId();
+            $currentUserId = api_get_user_id();
+
+            if ($exerciseInSession->id != $exerciseId) {
+                if ($debug) {
+                    error_log("Cannot update exercise are different.");
+                }
+                exit;
+            }
+
+            if ($attempt->getStatus() != 'incomplete') {
+                if ($debug) {
+                    error_log("Cannot update exercise is already completed.");
+                }
+                exit;
+            }
+
+            // Check if we are dealing with the same exercise.
+            if ($attempt && $userId == $currentUserId) {
+                $timeWithOutUpdate = $now - $attempt->getExeDate()->getTimestamp();
+                if ($timeWithOutUpdate > $onlyUpdateValue) {
+                    $key = ExerciseLib::get_time_control_key(
+                        $exerciseId,
+                        $attempt->getOrigLpId(),
+                        $attempt->getOrigLpItemId()
+                    );
+                    $durationFromObject = $attempt->getExeDuration();
+                    $previousTime = Session::read('duration_time_previous');
+                    if (isset($previousTime[$key]) &&
+                        !empty($previousTime[$key])
+                    ) {
+                        $sessionTime = $previousTime[$key];
+                        $duration = $now - $sessionTime;
+                        if ($debug) {
+                            //error_log("Now in UTC: ".$nowObject->format('Y-m-d H:i:s'));
+                            //error_log("Session time in UTC: ".api_get_utc_datetime($sessionTime));
+                            error_log("Time spent in exercise: $duration just before an update");
+                        }
+                        if (!empty($durationFromObject)) {
+                            $duration += $durationFromObject;
+                        }
+                        $duration = (int) $duration;
+                        if (!empty($duration)) {
+                            if ($debug) {
+                                error_log("Exe_id: #".$exeId);
+                                error_log("Key: $key");
+                                error_log("Exercise to update: #$exerciseId for user: #$userId");
+                                error_log("Accumulate duration to save in DB: $duration");
+                                error_log("End date to save in DB: ".$nowObject->format('Y-m-d H:i:s'));
+                            }
+                            $attempt
+                                ->setExeDuration($duration)
+                                ->setExeDate($nowObject);
+                            $em->merge($attempt);
+                            $em->flush();
+                        }
+                    } else {
+                        if ($debug) {
+                            error_log("Nothing to update, 'duration_time_previous' session not set");
+                            error_log("Key: $key");
+                        }
+                    }
+                } else {
+                    if ($debug) {
+                        error_log("Cannot update, latest time diff is just $timeWithOutUpdate seconds");
+                    }
+                }
+            }
+        }
+        break;
     case 'get_live_stats':
         if (!api_is_allowed_to_edit(null, true)) {
             break;
@@ -485,8 +568,10 @@ switch ($action) {
                     $exercise_stat_info['orig_lp_item_id']
                 );
 
-                if (isset($_SESSION['duration_time'][$key]) && !empty($_SESSION['duration_time'][$key])) {
-                    $duration = $now - $_SESSION['duration_time'][$key];
+                $durationTime = Session::read('duration_time');
+
+                if (isset($durationTime[$key]) && !empty($durationTime[$key])) {
+                    $duration = $now - $durationTime[$key];
                     if (!empty($exercise_stat_info['exe_duration'])) {
                         $duration += $exercise_stat_info['exe_duration'];
                     }
@@ -497,7 +582,7 @@ switch ($action) {
                     }
                 }
 
-                $_SESSION['duration_time'][$key] = time();
+                Session::write('duration_time', [$key => time()]);
 
                 Event::updateEventExercise(
                     $exe_id,

+ 12 - 11
main/inc/lib/internationalization.lib.php

@@ -409,29 +409,29 @@ function api_get_timezone()
  * Returns the given date as a DATETIME in UTC timezone.
  * This function should be used before entering any date in the DB.
  *
- * @param mixed $time                        The date to be converted (can be a string supported by date() or a timestamp)
- * @param bool  $return_null_if_invalid_date if the date is not correct return null instead of the current date
+ * @param mixed $time                    date to be converted (can be a string supported by date() or a timestamp)
+ * @param bool  $returnNullIfInvalidDate if the date is not correct return null instead of the current date
  * @param bool  $returnObj
  *
- * @return string The DATETIME in UTC to be inserted in the DB,
+ * @return string|DateTime The DATETIME in UTC to be inserted in the DB,
  *                or null if the format of the argument is not supported
+ *                or datetime
  *
  * @author Julio Montoya - Adding the 2nd parameter
  * @author Guillaume Viguier <guillaume.viguier@beeznest.com>
  */
 function api_get_utc_datetime(
     $time = null,
-    $return_null_if_invalid_date = false,
+    $returnNullIfInvalidDate = false,
     $returnObj = false
 ) {
-    $from_timezone = api_get_timezone();
-    $to_timezone = 'UTC';
+    $fromTimezone = api_get_timezone();
     if (is_null($time) || empty($time) || $time === '0000-00-00 00:00:00') {
-        if ($return_null_if_invalid_date) {
+        if ($returnNullIfInvalidDate) {
             return null;
         }
         if ($returnObj) {
-            return $date = new DateTime(gmdate('Y-m-d H:i:s'));
+            return new DateTime(gmdate('Y-m-d H:i:s'), new DateTimeZone('UTC'));
         }
 
         return gmdate('Y-m-d H:i:s');
@@ -439,13 +439,14 @@ function api_get_utc_datetime(
 
     // If time is a timestamp, return directly in utc
     if (is_numeric($time)) {
-        $time = intval($time);
+        $time = (int) $time;
 
         return gmdate('Y-m-d H:i:s', $time);
     }
+
     try {
-        $date = new DateTime($time, new DateTimezone($from_timezone));
-        $date->setTimezone(new DateTimeZone($to_timezone));
+        $date = new DateTime($time, new DateTimezone($fromTimezone));
+        $date->setTimezone(new DateTimeZone('UTC'));
         if ($returnObj) {
             return $date;
         } else {

+ 9 - 0
main/lp/learnpathItem.class.php

@@ -3404,6 +3404,10 @@ class learnpathItem
                 if ($debug) {
                     error_log('found asset - set time to '.$myTime);
                 }
+            } else {
+                if ($debug) {
+                    error_log('Time not set');
+                }
             }
         } else {
             switch ($format) {
@@ -3422,11 +3426,16 @@ class learnpathItem
                         $totalSec = $hour * 3600 + $min * 60 + $sec;
                         if ($debug) {
                             error_log("totalSec : $totalSec");
+                            error_log("Now calling to scorm_update_time()");
                         }
                         $this->scorm_update_time($totalSec);
                     }
                     break;
                 case 'int':
+                    if ($debug) {
+                        error_log("scorm_time = $scorm_time");
+                        error_log("Now calling to scorm_update_time()");
+                    }
                     $this->scorm_update_time($scorm_time);
                     break;
             }

+ 1 - 1
main/lp/lp_ajax_save_item.php

@@ -61,7 +61,7 @@ function save_item(
     $statusSignalReceived = 0
 ) {
     //global $debug;
-    $debug = 0;
+    $debug = false;
     $return = null;
 
     if ($debug > 0) {

+ 2 - 0
main/lp/lp_view.php

@@ -148,6 +148,8 @@ if (isset($exerciseResult) || isset($_SESSION['exerciseResult'])) {
     Session::erase('exerciseResult');
     Session::erase('objExercise');
     Session::erase('questionList');
+    Session::erase('duration_time_previous');
+    Session::erase('duration_time');
 }
 
 // additional APIs

+ 2 - 0
main/session/index.php

@@ -37,6 +37,8 @@ Session::write('id_session', $session_id);
 
 // Clear the exercise session just in case
 Session::erase('objExercise');
+Session::erase('duration_time_previous');
+Session::erase('duration_time');
 
 $userId = api_get_user_id();
 $session_info = SessionManager::fetch($session_id);