Beispiel #1
0
/**
 * Creates a box to show that a unit is currently pending.
 * 
 * @param Object $parentData A copy of the parent course and module details for this unit.
 * @param Integer $unitID The ID of the unit that's currently pending.
 */
function WPCW_units_getCompletionBox_pending($parentData, $unitID)
{
    // See if we have a quiz for this unit? If so, render it and allow the trainee to complete it.
    $quizDetails = WPCW_quizzes_getAssociatedQuizForUnit($unitID);
    $html = false;
    // See if we have a quiz for this unit, if we do, see if the user has completed it or not.
    if ($quizDetails && $quizDetails->questions && count($quizDetails) > 0) {
        // Got the user progress, determine if it's pending marking or not.
        $quizProgress = WPCW_quizzes_getUserResultsForQuiz(get_current_user_id(), $unitID, $quizDetails->quiz_id);
        if ($quizProgress && 'retake_quiz' == $quizProgress->quiz_next_step_type) {
            // Show a generic message that the quiz needs to be re-taken.
            $messageToShow = wpautop(__('The course instructor has required that you retake this quiz.'));
            $messageToShow .= '<p>' . sprintf(__('Your previous grade was: <b>%s</b>'), number_format($quizProgress->quiz_grade, 1) . '%') . '</p>';
            // Add the custom message if there was one, which is personalised from the instructor.
            if ($quizProgress->quiz_next_step_msg) {
                $messageToShow .= wpautop($quizProgress->quiz_next_step_msg);
            }
            $html .= WPCW_units_createWarningMessage($messageToShow);
        }
        // User has completed this quiz, so we need to indicate if it's been marked or not. If it's not been marked
        // we show a message saying they are blocked until it's marked.
        if ($quizProgress && $quizProgress->quiz_needs_marking > 0) {
            // Blocking quiz - show a status message saying that they can't continue until the quiz is graded.
            if ('quiz_block' == $quizDetails->quiz_type) {
                $html .= WPCW_units_createSuccessMessage($parentData->course_message_quiz_open_grading_blocking);
            }
        } else {
            $html .= WPCW_quizzes_handleQuizRendering($unitID, $quizDetails);
        }
    } else {
        // Render the message
        $html .= sprintf('
			<div class="wpcw_fe_progress_box_wrap" id="wpcw_fe_unit_complete_%d">
				<div class="wpcw_fe_progress_box wpcw_fe_progress_box_pending wpcw_fe_progress_box_updating">
					<div class="wpcw_fe_progress_box_mark">
						<img src="%s/ajax_loader.gif" class="wpcw_loader" style="display: none;" />
						<a href="#" class="fe_btn fe_btn_completion btn_completion" id="unit_complete_%d">%s</a>
					</div>
				%s</div>
			</div>', $unitID, WPCW_plugin_getPluginPath() . 'img', $unitID, __('Mark as Completed', 'wp_courseware'), $parentData->course_message_unit_pending);
    }
    return $html;
}
/**
 * Function that shows details to the admin telling them what to do next.
 */
function WPCW_showPage_UserProgess_quizAnswers_whatsNext($quizDetails, $results, $page, $userID, $unitID)
{
    // Tell admin still questions that need marking
    if ($results->quiz_needs_marking > 0) {
        printf('<div id="message" class="wpcw_msg wpcw_msg_info"><span class="wpcw_icon_pending"><b>%s</b></span></div>', __('This quiz has questions that need grading.', 'wp_courseware'));
    } else {
        // Show the form only if the quiz is blocking and they've failed.
        if ('quiz_block' == $quizDetails->quiz_type && $results->quiz_grade < $quizDetails->quiz_pass_mark) {
            $showAdminProgressForm = true;
            $showAdminMessageCustom = false;
            // Show admin which method was selected.
            if ($results->quiz_next_step_type) {
                switch ($results->quiz_next_step_type) {
                    case 'progress_anyway':
                        printf('<div id="message" class="wpcw_msg wpcw_msg_info">%s</span></div>', __('You have allowed the user to <b>progress anyway</b>, despite failing the quiz.', 'wp_courseware'));
                        $showAdminProgressForm = false;
                        break;
                    case 'retake_quiz':
                        printf('<div id="message" class="wpcw_msg wpcw_msg_info">%s</span></div>', __('You have requested that the user <b>re-takes the quiz</b>.', 'wp_courseware'));
                        $showAdminProgressForm = false;
                        break;
                    case 'retake_waiting':
                        printf('<div id="message" class="wpcw_msg wpcw_msg_info">%s</span></div>', __('The user has requested a retake, but they have not yet completed the quiz.', 'wp_courseware'));
                        $showAdminProgressForm = false;
                        break;
                    case 'quiz_fail_no_retakes':
                        $showAdminMessageCustom = __('The user has <b>exhausted all of their retakes</b>.', 'wp_courseware');
                        $showAdminProgressForm = true;
                        break;
                }
            }
            // Next step has not been specified, allow the admin to choose one.
            if ($showAdminProgressForm) {
                $attempts_taken = WPCW_quizzes_getUserResultsForQuiz($userID, $unitID, $quizDetails->quiz_id);
                $unitQuizDetails = WPCW_quizzes_getAssociatedQuizForUnit($unitID, true, $userID);
                printf('<div class="wpcw_user_progress_failed"><form method="POST">');
                // Show the main message or a custom message from above.
                printf('<div id="message" class="wpcw_msg wpcw_msg_error">%s %s</span></div>', $showAdminMessageCustom, __('Since this is a <b>blocking quiz</b>, and the user has <b>failed</b>, what would you like to do?', 'wp_courseware'));
                printf('
					<div class="wpcw_user_progress_failed_next_action">
						<label><input type="radio" name="wpcw_user_continue_action" class="wpcw_next_action_progress_anyway" value="progress_anyway" checked="checked" /> <span><b>%s</b> %s</span></label><br/>
					', __('Allow the user to continue anyway.', 'wp_courseware'), __(' (User is emailed saying they can continue)', 'wp_courseware'));
                //if ($results->quiz_next_step_type == 'quiz_fail_no_retakes'){
                if ($attempts_taken->attempt_count >= $unitQuizDetails->quiz_attempts_allowed && $unitQuizDetails->quiz_attempts_allowed != -1) {
                    printf('
							<label><input type="radio" name="wpcw_user_continue_action" class="wpcw_next_action_retake_quiz" value="retake_quiz" /> <span><b>%s</b> %s</span></label>
						', __('Allow the user one more attempt.', 'wp_courseware'), __(' (User is emailed saying they need to re-take the quiz)', 'wp_courseware'));
                } else {
                    printf('
						<label><input type="radio" name="wpcw_user_continue_action" class="wpcw_next_action_retake_quiz" value="retake_quiz" /> <span><b>%s</b> %s</span></label>
					', __('Require the user to re-take the quiz.', 'wp_courseware'), __(' (User is emailed saying they need to re-take the quiz)', 'wp_courseware'));
                }
                printf('
					</div>
					
					<div class="wpcw_user_progress_failed_reason" style="display: none;">
						<label><b>%s</b></label><br/>
						<textarea name="wpcw_user_progress_failed_reason"></textarea><br/>
						<small>%s</small>
					</div>
					
					<div class="wpcw_user_progress_failed_btns">
						<input type="submit" name="failed_quiz_next_action" value="%s" class="button-primary" />
					</div>
				', __('Require the user to re-take the quiz.', 'wp_courseware'), __(' (User is emailed saying they need to re-take the quiz)', 'wp_courseware'), __('Custom Message:', 'wp_courseware'), __('Custom message for the user that\'s sent to the user when asking them to retake the quiz.', 'wp_courseware'), __('Save Preference', 'wp_courseware'));
                printf('</form></div>');
            }
        }
    }
}
 /**
  * In paging mode, check the answers that have been provided and update the status in the 
  * database if we're still progressing through getting answers to all questions.
  * 
  * @param Array $potentialAnswers The potential answers that need checking. 
  * 
  * @return Boolean Returns true when we have all of our answers, and we're allowed to carry on for grading.
  */
 function check_quizzes_canWeContinue_checkAnswersFromPaging($potentialAnswers)
 {
     global $wpdb, $wpcwdb;
     $wpdb->show_errors();
     // Check the raw data to see what questions we have.
     $resultsList = $this->check_quizzes_canWeContinue_extractAnswerData($potentialAnswers);
     // Need to build the data for the quiz progress, which should show that the quiz hasn't been graded as yet.
     $data = array();
     $data['user_id'] = $this->currentUserID;
     $data['unit_id'] = $this->unitPost->ID;
     $data['quiz_id'] = $this->unitQuizDetails->quiz_id;
     $data['quiz_completed_date'] = current_time('mysql');
     $data['quiz_correct_questions'] = 0;
     $data['quiz_question_total'] = count($this->unitQuizDetails->questions);
     // Total number of incomplete questions matches one less than question count (-1 to remove this Q).
     $data['quiz_paging_incomplete'] = $data['quiz_question_total'] - 1;
     // Showing the next question if we've got here.
     $data['quiz_paging_next_q'] = 1;
     // We're still working on this quiz, so it's incomplete.
     $data['quiz_paging_status'] = 'incomplete';
     // Set to false, we'll fill it in later.
     $data['quiz_data'] = false;
     // Do we have a progress item already? Such as a prior attempt or previous question (when paging).
     $SQL = $wpdb->prepare("\n\t\t\tSELECT * \n\t\t\tFROM {$wpcwdb->user_progress_quiz}\n\t\t\tWHERE user_id = %d\n\t\t\t  AND unit_id = %d\n\t\t\t  AND quiz_id = %d\n\t\t\tORDER BY quiz_attempt_id DESC \n\t\t\tLIMIT 1\n\t\t", $this->currentUserID, $this->unitPost->ID, $this->unitQuizDetails->quiz_id);
     $updateExistingProgress = false;
     // Already exists, so we just need to update the progress with where we're at.
     // If it doesn't exist, we'll just use the database default of 0.
     if ($existingProgress = $wpdb->get_row($SQL)) {
         // Got an existing incomplete paging progress, carry on working with it.
         if ('incomplete' == $existingProgress->quiz_paging_status) {
             $updateExistingProgress = true;
             // Need to progress to next item - BUT If the index is goes to the end of the list,
             // then don't change it. This allows to detect if we're running through skipped questions.
             if ($existingProgress->quiz_paging_next_q < $existingProgress->quiz_question_total) {
                 $data['quiz_paging_next_q'] = $existingProgress->quiz_paging_next_q + 1;
             } else {
                 $data['quiz_paging_next_q'] = $existingProgress->quiz_paging_next_q;
             }
             // Migrate data from the existing progress that's important.
             foreach ($existingProgress as $fieldName => $fieldDetails) {
                 if (!isset($data[$fieldName])) {
                     $data[$fieldName] = $fieldDetails;
                 }
             }
         } else {
             // Mark all previous progress items as not being the latest.
             $SQL = $wpdb->prepare("\n\t\t\t\t\tUPDATE {$wpcwdb->user_progress_quiz}\n\t\t\t\t\tSET quiz_is_latest = ''\n\t\t\t\t\tWHERE user_id = %d\n\t\t\t\t\t  AND unit_id = %d\n\t\t\t\t\t  AND quiz_id = %d\n\t\t\t\t", $this->currentUserID, $this->unitPost->ID, $this->unitQuizDetails->quiz_id);
             $wpdb->query($SQL);
             // Ensure this new progress marked as the latest.
             $data['quiz_is_latest'] = 'latest';
             $data['quiz_attempt_id'] = $existingProgress->quiz_attempt_id + 1;
         }
     }
     // Do Insert or Update as needed.
     if ($updateExistingProgress) {
         // Fetch the existing quiz data, as we need to merge the new complete data with
         // the existing data.
         $data['quiz_data'] = maybe_unserialize($existingProgress->quiz_data);
         if (!empty($data['quiz_data'])) {
             $newData = $this->fetch_quizzes_extractQuizStatusFromAnswers($resultsList['answer_list']);
             if (!empty($newData)) {
                 // We're assuming that if the new data is complete, then we overwrite the old
                 // data, as that should be incomplete.
                 foreach ($newData as $thisQuestionID => $thisAnswerDetails) {
                     // Got a new complete item, so overwrite details
                     if ($thisAnswerDetails['is_incomplete'] == 0) {
                         $data['quiz_data'][$thisQuestionID] = $thisAnswerDetails;
                     }
                 }
             }
             // Count up the total number of incomplete questions left.
             $data['quiz_paging_incomplete'] = 0;
             foreach ($data['quiz_data'] as $thisQuestionID => $thisAnswerDetails) {
                 // Found another question that's not complete, so add 1 to count of incomplete questions.
                 if ($thisAnswerDetails['is_incomplete'] == 1) {
                     $data['quiz_paging_incomplete']++;
                 }
             }
         } else {
             $data['quiz_data'] = $this->fetch_quizzes_extractQuizStatusFromAnswers($resultsList['answer_list']);
         }
         // Need to reserialize the data
         $data['quiz_data'] = serialize($data['quiz_data']);
         $SQL = arrayToSQLUpdate($wpcwdb->user_progress_quiz, $data, array('user_id', 'unit_id', 'quiz_id', 'quiz_attempt_id'));
     } else {
         // Extract all quiz data including placeholders for questions not yet answered.
         $data['quiz_data'] = serialize($this->fetch_quizzes_extractQuizStatusFromAnswers($resultsList['answer_list']));
         $SQL = arrayToSQLInsert($wpcwdb->user_progress_quiz, $data);
     }
     $wpdb->query($SQL);
     // Update internal store of results once saved to database.
     $this->unitQuizProgress = WPCW_quizzes_getUserResultsForQuiz($this->currentUserID, $this->unitPost->ID, $this->unitQuizDetails->quiz_id);
     // Try to work out which questions are still incomplete.
     $this->updateInternalVariable_quizzes_getIncompleteQuestions();
     // Reload any raw answers that we have into the internal raw answer object.
     $this->fetch_quizzes_loadRawAnswersSoFarForThisQuiz($data['quiz_data']);
     // We can only continue if we no longer have any incomplete questions.
     return $this->unitQuizProgress->quiz_paging_incomplete == 0 && !$this->check_paging_shouldWeShowReviewPage();
 }
/**
 * Handles the grading of the quiz questions.
 */
function WPCW_showPage_UserProgess_quizAnswers_handingGrading($quizDetails, $results, $page, $userID, $unitID)
{
    if (isset($_POST['grade_answers_submitted']) && 'true' == $_POST['grade_answers_submitted']) {
        $listOfQuestionsToMark = $results->quiz_needs_marking_list;
        // Switch array so values become keys.
        if (!empty($listOfQuestionsToMark)) {
            $listOfQuestionsToMark = array_flip($listOfQuestionsToMark);
        } else {
            $listOfQuestionsToMark = array();
        }
        // Check $_POST keys for the graded results.
        foreach ($_POST as $key => $value) {
            // Check that we have a question ID and a matching grade for the quiz. Only want grades that are greater than 0.
            if (preg_match('/^grade_quiz_([0-9]+)$/', $key, $keyMatches) && preg_match('/^[0-9]+$/', $value) && $value > 0) {
                $questionID = $keyMatches[1];
                // Remove from list to be marked, if found
                unset($listOfQuestionsToMark[$questionID]);
                // Add the grade information to the quiz
                if (isset($results->quiz_data[$questionID])) {
                    $results->quiz_data[$questionID]['their_grade'] = $value;
                }
            }
        }
        // Update the database with the list of questions to mark, plus the updated quiz grading information.
        // Return to a simple list again, hence using array flip (ID => index) becomes (index => ID)
        $results->quiz_needs_marking_list = array_flip($listOfQuestionsToMark);
        // Update the results in the database.
        WPCW_quizzes_updateQuizResults($results);
        // Success message
        $page->showMessage(__('Grades have been successfully updated for this user.', 'wp_courseware'));
        // Refresh the results - now that we've made changes
        $results = WPCW_quizzes_getUserResultsForQuiz($userID, $unitID, $quizDetails->quiz_id);
        // All items are marked, so email user, and tell admin that user has been notified.
        if ($results->quiz_needs_marking == 0) {
            // Send out email only if not a blocking test, or blocking and passed.
            if ('quiz_block' == $quizDetails->quiz_type && $results->quiz_grade < $quizDetails->quiz_pass_mark) {
                $results->sendOutEmails = false;
            } else {
                $results->sendOutEmails = true;
            }
            // Check if the user has passed or not to indicate what to do next.
            if ($results->quiz_grade >= $quizDetails->quiz_pass_mark) {
                // Just a little note to mark as complete
                $results->extraEmailDetail = __('You have passed the quiz.', 'wp_courseware');
                printf('<div id="message" class="wpcw_msg wpcw_msg_success">%s</span></div>', __('The user has <b>PASSED</b> this quiz, and the associated unit has been marked as complete.', 'wp_courseware'));
                WPCW_units_saveUserProgress_Complete($userID, $unitID);
                // Unit complete, check if course/module is complete too.
                do_action('wpcw_user_completed_unit', $userID, $unitID, WPCW_units_getAssociatedParentData($unitID));
            }
        }
        // Set flag that the quiz has just literally been graded for use in code around this.
        // Doing this after the results have been updated above.
        $results->quiz_has_just_been_graded = true;
    }
    return $results;
}
Beispiel #5
0
/**
 * Handles saving what the admin wants to do for the user next.
 */
function WPCW_showPage_UserProgess_quizAnswers_whatsNext_savePreferences($quizDetails, $results, $page, $userID, $unitID)
{
    // Admin wants to save the next action to this progress.
    if (isset($_POST['failed_quiz_next_action']) && $_POST['failed_quiz_next_action']) {
        global $wpdb, $wpcwdb;
        $wpdb->show_errors();
        $userNextAction = WPCW_arrays_getValue($_POST, 'wpcw_user_continue_action');
        $userRetakeMsg = filter_var(WPCW_arrays_getValue($_POST, 'wpcw_user_progress_failed_reason'), FILTER_SANITIZE_STRING);
        // Check action is valid. Abort if not
        if (!in_array($userNextAction, array('retake_quiz', 'progress_anyway'))) {
            return $results;
        }
        // Sort out the SQL statement for what to update
        switch ($userNextAction) {
            // User needs to retake the course.
            case 'retake_quiz':
                break;
                // User is allowed to progress
            // User is allowed to progress
            case 'progress_anyway':
                $userRetakeMsg = false;
                // Mark the unit as completed.
                WPCW_units_saveUserProgress_Complete($userID, $unitID);
                // Unit complete, check if course/module is complete too.
                do_action('wpcw_user_completed_unit', $userID, $unitID, WPCW_units_getAssociatedParentData($unitID));
                break;
        }
        // Update the progress item
        $SQL = $wpdb->prepare("\n\t\t    \tUPDATE {$wpcwdb->user_progress_quiz}\n\t\t    \t  SET quiz_next_step_type = '%s', \n\t\t    \t      quiz_next_step_msg = %s  \n\t\t    \tWHERE user_id = %d \n\t\t    \t  AND unit_id = %d \n\t\t    \t  AND quiz_id = %d\n\t\t    \tORDER BY quiz_attempt_id DESC\n\t\t    \tLIMIT 1\n\t   \t\t", $userNextAction, $userRetakeMsg, $userID, $unitID, $quizDetails->quiz_id);
        $wpdb->query($SQL);
        // Need to update the results object for use later.
        $results = WPCW_quizzes_getUserResultsForQuiz($userID, $unitID, $quizDetails->quiz_id);
        switch ($userNextAction) {
            // User needs to retake the course.
            case 'retake_quiz':
                $results->extraEmailDetail = __('Since you didn\'t pass the quiz, the instructor has asked that you re-take this quiz.', 'wp_courseware');
                if ($userRetakeMsg) {
                    $results->extraEmailDetail .= "\n\n" . $userRetakeMsg;
                }
                break;
                // User is allowed to progress
            // User is allowed to progress
            case 'progress_anyway':
                $results->extraEmailDetail = __('Although you didn\'t pass the quiz, the instructor is allowing you to continue on to the next unit.', WPCW_showPage_UserProgess_quizAnswers_handingGrading);
                // Mark the unit as completed.
                WPCW_units_saveUserProgress_Complete($userID, $unitID);
                // Unit complete, check if course/module is complete too.
                do_action('wpcw_user_completed_unit', $userID, $unitID, WPCW_units_getAssociatedParentData($unitID));
                break;
        }
        // Tell code to send out emails
        $results->sendOutEmails = true;
    }
    return $results;
}