function watupro_my_exams($passed_cat_ids = "", $orderby = "tE.ID") { global $wpdb, $user_ID; // admin can see this for every student if (!empty($_GET['user_id']) and current_user_can(WATUPRO_MANAGE_CAPS)) { $user_id = $_GET['user_id']; } else { $user_id = $user_ID; } $user = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->users} WHERE ID=%d", $user_id)); // select what categories I have access to get_currentuserinfo(); $cat_ids = WTPCategory::user_cats($user_id); if (!empty($passed_cat_ids)) { $passed_cat_ids = explode(",", $passed_cat_ids); $cat_ids = array_intersect($cat_ids, $passed_cat_ids); } $cat_id_sql = implode(",", $cat_ids); list($my_exams, $takings, $num_taken) = WTPExam::my_exams($user_id, $cat_id_sql, $orderby); // intelligence dependencies if (watupro_intel()) { require_once WATUPRO_PATH . "/i/models/dependency.php"; $my_exams = WatuPRODependency::mark($my_exams, $takings); } $num_to_take = sizeof($my_exams) - $num_taken; $dateformat = get_option('date_format'); wp_enqueue_script('thickbox', null, array('jquery')); wp_enqueue_style('thickbox.css', '/' . WPINC . '/js/thickbox/thickbox.css', null, '1.0'); wp_enqueue_style('style.css', plugins_url() . '/watupro/style.css', null, '1.0'); if (@file_exists(get_stylesheet_directory() . '/watupro/my_exams.php')) { require get_stylesheet_directory() . '/watupro/my_exams.php'; } else { require WATUPRO_PATH . "/views/my_exams.php"; } }
function watupro_question_cats() { global $wpdb, $user_ID; $multiuser_access = 'all'; if (watupro_intel()) { $multiuser_access = WatuPROIMultiUser::check_access('qcats_access'); } $error = false; if (!empty($_POST['add'])) { if (!WTPCategory::add($_POST['name'], $_POST['description'])) { $error = __('Another category with this name already exists.', 'watupro'); } } if (!empty($_POST['save'])) { if ($multiuser_access == 'own') { $cat = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . WATUPRO_QCATS . " WHERE ID=%d", $_POST['id'])); if ($cat->editor_id != $user_ID) { wp_die(__('You can manage only your own categories', 'watupro')); } } if (!WTPCategory::save($_POST['name'], $_POST['id'], $_POST['description'])) { $error = __('Another category with this name already exists.', 'watupro'); } } if (!empty($_POST['del'])) { if ($multiuser_access == 'own') { $cat = $wpdb->get_row($wpdb->prepare("SELECT * FROM " . WATUPRO_QCATS . " WHERE ID=%d", $_POST['id'])); if ($cat->editor_id != $user_ID) { wp_die(__('You can manage only your own categories', 'watupro')); } } WTPCategory::delete($_POST['id']); } // select all question categories $own_sql = $multiuser_access == 'own' ? $wpdb->prepare(" WHERE editor_id = %d ", $user_ID) : ""; $cats = $wpdb->get_results("SELECT * FROM " . WATUPRO_QCATS . " {$own_sql} ORDER BY ID"); if (@file_exists(get_stylesheet_directory() . '/watupro/question_cats.php')) { require get_stylesheet_directory() . '/watupro/question_cats.php'; } else { require WATUPRO_PATH . "/views/question_cats.php"; } }
static function skills($report_user_id, $has_tabs = true) { global $wpdb; // select exam categories that I can access $cat_ids = WTPCategory::user_cats($report_user_id); $cat_id_sql = implode(",", $cat_ids); $exam_cats = $wpdb->get_results("SELECT * FROM " . WATUPRO_CATS . " WHERE ID IN ({$cat_id_sql}) ORDER BY name"); // question categories $q_cats = $wpdb->get_results("SELECT * FROM " . WATUPRO_QCATS . " ORDER BY name"); // add uncategorized $q_cats[] = (object) array("ID" => 0, "name" => __('Uncategorized', 'watupro')); // exam category filter? $exam_cat_sql = @$_POST['cat'] < 0 ? $cat_id_sql : @$_POST['cat']; // now select all exams I have access to list($my_exams) = WTPExam::my_exams($report_user_id, $exam_cat_sql); $skill_filter = empty($_POST['skill_filter']) ? "all" : $_POST['skill_filter']; // practiced only? if ($skill_filter == 'practiced') { $final_exams = array(); foreach ($my_exams as $exam) { if (!empty($exam->taking->ID)) { $final_exams[] = $exam; } } $my_exams = $final_exams; } // proficiency filter selected? If yes, we'll need to limit exams // to those that are taken with at least $_POST['proficiency_goal'] % correct answers if ($skill_filter == 'proficient') { $final_exams = array(); foreach ($my_exams as $exam) { if (!empty($exam->taking->ID) and $exam->taking->percent_correct >= $_POST['proficiency_goal']) { $final_exams[] = $exam; } } // end exams loop $my_exams = $final_exams; } // for each exam select match answers and fill % correct info by category $taking_ids = array(0); foreach ($my_exams as $my_exam) { if (!empty($my_exam->taking->ID)) { $taking_ids[] = $my_exam->taking->ID; } } $user_answers = $wpdb->get_results("SELECT tA.is_correct as is_correct, tA.taking_id as taking_id, tQ.cat_id as cat_id \n\t\t\tFROM " . WATUPRO_STUDENT_ANSWERS . " tA JOIN " . WATUPRO_QUESTIONS . " tQ ON tQ.ID = tA.question_id\n\t\t\tWHERE tA.taking_id IN (" . implode(',', $taking_ids) . ") ORDER BY tA.ID"); foreach ($my_exams as $cnt => $my_exam) { if (empty($my_exam->taking->ID)) { continue; } $cats = array(); foreach ($user_answers as $answer) { if ($answer->taking_id != $my_exam->taking->ID) { continue; } $correct_key = $answer->is_correct ? 'num_correct' : 'num_incorrect'; if (isset($cats[$answer->cat_id][$correct_key])) { $cats[$answer->cat_id][$correct_key]++; } else { $cats[$answer->cat_id][$correct_key] = 1; } } // now foreach cat calculate the correctness foreach ($cats as $cat_id => $cat) { $num_correct = isset($cat['num_correct']) ? $cat['num_correct'] : 0; $num_incorrect = isset($cat['num_incorrect']) ? $cat['num_incorrect'] : 0; $total = $num_correct + $num_incorrect; $percentage = $total ? round(100 * $num_correct / $total) : 0; $cats[$cat_id]['percentage'] = $percentage; } // finally add cats to exam $my_exams[$cnt]->cats = $cats; } // group exams by question category $skills = array(); // skills equal question categories $num_proficient = 0; foreach ($q_cats as $q_cat) { // skill filter (question category) selected in the drop-down? if (@$_POST['q_cat'] > -1 and $q_cat->ID != @$_POST['q_cat']) { continue; } // now construct array of this category along with the exams in it // then add in $skills. $skills is the final array that we'll use in the view $exams = array(); foreach ($my_exams as $exam) { $has_questions = $wpdb->get_var($wpdb->prepare("SELECT ID FROM " . WATUPRO_QUESTIONS . " \n\t\t\t\t \tWHERE exam_id=%d AND cat_id=%d AND is_inactive=0 AND is_survey=0", $exam->ID, $q_cat->ID)); if (!$has_questions) { continue; } $exams[] = $exam; } $skills[] = array("category" => $q_cat, "exams" => $exams, "id" => $q_cat->ID); if (sizeof($exams)) { $num_proficient++; } // proficient in X skills } // by default $skills is ordered by category (name). Do we have to reorder? // NOT SURE THIS MAKES SENSE, SO FOR NOW NYI if (!empty($_POST['sort_skills']) and $_POST['sort_skills'] == 'proficiency') { // Sort by sum of proficiency of latest taking of the exams in this category // let's create an array that'll contain only cat ID and cumulative proficiency // for easier sorting $cat_ids = array(); foreach ($skills as $skill) { // NYI } } if (@file_exists(get_stylesheet_directory() . '/watupro/reports/skills.php')) { require get_stylesheet_directory() . '/watupro/reports/skills.php'; } else { require WATUPRO_PATH . "/modules/reports/views/skills.php"; } }
function watupro_import_question($data, &$cats) { global $wpdb; if ($_POST['file_type'] == 'new') { $cat_id = WTPCategory::discover(@$data[3], $cats); // handle true/false subtype $truefalse = 0; if ($data[1] == 'true/false') { $truefalse = 1; $data[1] = 'radio'; } // only new questions and answers $stripfrom = 6; $question_array = array("content" => $data[0], "answer_type" => $data[1], "sort_order" => $data[2], "cat_id" => $cat_id, "explain_answer" => $data[4], "is_required" => $data[5], "quiz" => $_GET['quiz']); $stripfrom = 13; $question_array['correct_condition'] = $data[6]; $gapdata = explode("/", $data[7]); // handle both gap & sort $question_array['correct_gap_points'] = $question_array['correct_sort_points'] = @$gapdata[0]; $question_array['incorrect_gap_points'] = $question_array['incorrect_sort_points'] = @$gapdata[1]; $question_array['sorting_answers'] = $data[8]; $question_array['max_selections'] = $data[9]; $question_array['is_inactive'] = $data[10]; $question_array['is_survey'] = $data[11]; $question_array['elaborate_explanation'] = $data[12]; $question_array['truefalse'] = $truefalse; $question_array['feedback_label'] = ''; // temp as it's not yet included in export // sorting answers may contain ||| or |||||| for new lines separator $question_array['sorting_answers'] = str_replace('||||||', "\n", $question_array['sorting_answers']); $question_array['sorting_answers'] = str_replace('|||', "\n", $question_array['sorting_answers']); $qid = WTPQuestion::add($question_array); // extract answers $data = array_slice($data, $stripfrom); $answers = array(); $step = 1; foreach ($data as $cnt => $d) { if ($step == 1) { $answer = array(); $answer['answer'] = $d; $answer['is_correct'] = 0; $step = 2; } else { $answer['points'] = $d; $step = 1; $answers[] = $answer; } } // now we have the answers in the array, let's identify which ones are correct if ($data[1] == 'radio') { // for 'single answer' it's the one with most points $top_points = 0; foreach ($answers as $answer) { if ($answer['points'] > $top_points) { $top_points = $answer['points']; } } // once again foreach ($answers as $cnt => $answer) { if ($answer['points'] == $top_points) { $answers[$cnt]['is_correct'] = 1; break; } } } else { // for other types answer with positive points is correct foreach ($answers as $cnt => $answer) { if ($answer['points'] > 0) { $answers[$cnt]['is_correct'] = 1; } } } // finally insert them $vals = array(); foreach ($answers as $cnt => $answer) { if ($answer['answer'] === '') { continue; } $cnt++; $vals[] = $wpdb->prepare("(%d, %s, %s, %s, %d)", $qid, $answer['answer'], $answer['is_correct'], $answer['points'], $cnt); } $values_sql = implode(",", $vals); if (sizeof($answers)) { $wpdb->query("INSERT INTO " . WATUPRO_ANSWERS . " (question_id,answer,correct,point, sort_order) \n\t\t\tVALUES {$values_sql}"); } } else { // for old files import if ($row == 1 or empty($data[1])) { continue; } // skip first line $cat_id = WTPCategory::discover($data[4], $cats); $stripfrom = 14; $gapdata = explode("/", $data[8]); if (empty($data[0])) { $question_array = array("content" => $data[1], "answer_type" => $data[2], "sort_order" => $data[3], "cat_id" => $cat_id, "explain_answer" => $data[5], "is_required" => $data[6], "quiz" => $_GET['quiz']); $question_array['correct_condition'] = $data[7]; $question_array['correct_gap_points'] = $gapdata[0]; $question_array['incorrect_gap_points'] = $gapdata[1]; $question_array['sorting_answers'] = $data[9]; $question_array['max_selections'] = $data[10]; $question_array['is_inactive'] = $data[11]; $question_array['is_survey'] = $data[12]; $question_array['elaborate_explanation'] = $data[13]; $question_array['feedback_label'] = ''; // temp as it's not yet included in export // sorting answers may contain ||| or |||||| for new lines separator $question_array['sorting_answers'] = str_replace('||||||', "\n", $question_array['sorting_answers']); $question_array['sorting_answers'] = str_replace('|||', "\n", $question_array['sorting_answers']); $qid = WTPQuestion::add($question_array); } else { $wpdb->query($wpdb->prepare("UPDATE " . WATUPRO_QUESTIONS . " SET question=%s, answer_type=%s,\n \t\t\t\tsort_order=%d, cat_id=%d, explain_answer=%s, is_required=%d, correct_condition=%s,\n \t\t\t\tcorrect_gap_points=%s, incorrect_gap_points=%s, sorting_answers = %s, max_selections = %d,\n \t\t\t\tis_inactive=%d, is_survey = %d, elaborate_explanation = %s\n \t\t\t\tWHERE ID=%d", $data[1], $data[2], $data[3], $cat_id, $data[5], $data[6], $data[7], $gapdata[0], $gapdata[1], $data[9], $data[10], $data[11], $data[12], $data[13], $data[0])); $qid = $data[0]; } // now answers, first extract them similar to the "new file" option $data = array_slice($data, $stripfrom); $answers = array(); $step = 1; foreach ($data as $cnt => $d) { switch ($step) { case 1: $answer = array(); $answer['id'] = $d; $step = 2; break; case 2: $answer['answer'] = $d; $step = 3; break; case 3: $answer['points'] = $d; $step = 1; $answers[] = $answer; break; } } // end foreach // now insert or update foreach ($answers as $cnt => $answer) { if ($answer['answer'] === '') { continue; } $cnt++; // assume 1st is correct if ($cnt == 1) { $correct = 1; } else { $correct = 0; } if ($answer['id']) { $wpdb->query($wpdb->prepare("UPDATE " . WATUPRO_ANSWERS . " SET answer=%s, point=%d WHERE ID=%d", $answer['answer'], $answer['points'], $answer['id'])); } else { $wpdb->query($wpdb->prepare("INSERT INTO " . WATUPRO_ANSWERS . "\n \t\t\t\t\t\t(question_id,answer,correct,point, sort_order) VALUES (%d, %s, %s, %s, %d) ", $qid, $answer['answer'], $correct, $answer['points'], $cnt)); } } // end foreach } // end else pf $_POST['file_type']=='new' }
static function import_question_advanced($data, $quiz, &$cats) { global $wpdb; // handle true/false subtype $truefalse = 0; if ($data[1] == 'true/false') { $truefalse = 1; $data[1] = 'radio'; } $cat_id = WTPCategory::discover(@$data[3], $cats); $question_array = array("content" => $data[0], "answer_type" => $data[1], "quiz" => $quiz->ID, "cat_id" => $cat_id, 'explain_answer' => $data[4], 'is_required' => $data[5], 'truefalse' => $truefalse); $question_array['correct_condition'] = $data[6]; $gapdata = explode("/", $data[7]); // handle both gap & sort $question_array['correct_gap_points'] = $question_array['correct_sort_points'] = @$gapdata[0]; $question_array['incorrect_gap_points'] = $question_array['incorrect_sort_points'] = @$gapdata[1]; $question_array['sorting_answers'] = $data[8]; $question_array['max_selections'] = $data[9]; $question_array['is_inactive'] = $data[10]; $question_array['is_survey'] = $data[11]; $question_array['elaborate_explanation'] = $data[12]; $question_array['open_end_mode'] = $data[13]; $question_array['tags'] = $data[14]; $question_array['open_end_display'] = $data[15]; $question_array['exclude_on_final_screen'] = $data[16]; $question_array['hints'] = $data[17]; $question_array['compact_format'] = $data[18]; $question_array['round_points'] = $data[19]; $question_array['importance'] = $data[20]; $question_array['feedback_label'] = ''; // temp as it's not yet included in export // sorting answers may contain ||| or |||||| for new lines separator $question_array['sorting_answers'] = str_replace('||||||', "\n", $question_array['sorting_answers']); $question_array['sorting_answers'] = str_replace('|||', "\n", $question_array['sorting_answers']); $qid = WTPQuestion::add($question_array); // add answers $data = array_slice($data, 21); $answers = array(); $step = 1; foreach ($data as $cnt => $d) { if ($step == 1) { $answer = array(); $answer['answer'] = $d; $step = 2; continue; } if ($step == 2) { $answer['is_correct'] = $d; $step = 3; continue; } if ($step == 3) { $answer['points'] = $d; $step = 1; $answers[] = $answer; } } // end filling answers array // finally insert them $vals = array(); foreach ($answers as $cnt => $answer) { if ($answer['answer'] === '') { continue; } $cnt++; $vals[] = $wpdb->prepare("(%d, %s, %s, %s, %d)", $qid, $answer['answer'], $answer['is_correct'], $answer['points'], $cnt); } $values_sql = implode(",", $vals); if (sizeof($answers)) { $wpdb->query("INSERT INTO " . WATUPRO_ANSWERS . " (question_id,answer,correct,point, sort_order) \n\t\t\t\tVALUES {$values_sql}"); } }
static function can_access($exam) { // always access public exams if (!$exam->require_login) { return true; } if ($exam->require_login and !is_user_logged_in()) { return false; } // admin can always access if (current_user_can('manage_options') or current_user_can('watupro_manage_exams')) { if (empty($_POST['action']) and $exam->fee > 0) { echo "<b>" . __('Note: This quiz requires payment, but you are administrator and do not need to go through it.', 'watupro') . "</b>"; } return true; } // USER GROUP CHECKS $allowed = WTPCategory::has_access($exam); if (!$allowed) { echo "<!-- not in allowed user group -->"; return false; } // INTELLIGENCE MODULE RESTRICTIONS if (watupro_intel()) { if ($exam->fee > 0) { require_once WATUPRO_PATH . "/i/models/payment.php"; if (!empty($_POST['stripe_pay'])) { WatuPROPayment::Stripe(); } // process Stripe payment if any if (!WatuPROPayment::valid_payment($exam)) { self::$output_sent = WatuPROPayment::render($exam); return false; } } require_once WATUPRO_PATH . "/i/models/dependency.php"; if (!WatuPRODependency::check($exam)) { echo "<!-- WATUPROCOMMENT unsatisfied dependencies -->"; return false; } } return true; }