| 1 |
<?php |
| 2 |
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly |
| 3 |
|
| 4 |
// select taking records for an exam |
| 5 |
function watu_takings($in_shortcode = false, $atts = null) { |
| 6 |
global $wpdb, $post; |
| 7 |
|
| 8 |
if($in_shortcode) { |
| 9 |
$_GET['exam_id'] = intval($atts['quiz_id'] ?? 0); |
| 10 |
} |
| 11 |
|
| 12 |
$is_preview_request = ( is_preview() || isset( $_GET['preview'] ) || isset( $_GET['_ppp'] ) ); |
| 13 |
|
| 14 |
// block preview for unauthorized |
| 15 |
if ( $in_shortcode && $is_preview_request && ! current_user_can( 'manage_options' ) && ! current_user_can( 'watu_manage' ) ) { |
| 16 |
return ''; |
| 17 |
} |
| 18 |
|
| 19 |
// if Namaste! LMS is installed we'll also select courses |
| 20 |
if(class_exists('NamasteLMSCourseModel')) { |
| 21 |
$_course = new NamasteLMSCourseModel(); |
| 22 |
$namaste_courses = $_course->select(); |
| 23 |
} |
| 24 |
|
| 25 |
// select exam |
| 26 |
$exam = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".WATU_EXAMS." WHERE ID=%d", intval($_GET['exam_id']))); |
| 27 |
$grades = $wpdb->get_results($wpdb->prepare("SELECT * FROM ".WATU_GRADES." WHERE exam_id=%d order by gtitle ", $exam->ID) ); |
| 28 |
|
| 29 |
// delete a taking |
| 30 |
if(!empty($_GET['del_taking']) and check_admin_referer('watu_del_taking')) { |
| 31 |
$wpdb->query($wpdb->prepare("DELETE FROM ".WATU_TAKINGS." WHERE ID=%d", intval($_GET['id']))); |
| 32 |
watu_redirect("admin.php?page=watu_takings&exam_id=".$exam->ID); |
| 33 |
} |
| 34 |
|
| 35 |
// mass cleanup |
| 36 |
if(!empty($_POST['delete_all_takings']) and check_admin_referer('watu_delete_all')) { |
| 37 |
$wpdb->query($wpdb->prepare("DELETE FROM ".WATU_TAKINGS." WHERE exam_id=%d", $exam->ID)); |
| 38 |
} |
| 39 |
|
| 40 |
// mass delete selected takings |
| 41 |
if(!empty($_POST['del_takings']) and check_admin_referer('watu_del_takings') and !empty($_POST['ids'])) { |
| 42 |
$ids = array_map('intval', $_POST['ids']); |
| 43 |
|
| 44 |
$wpdb->query("DELETE FROM ".WATU_TAKINGS." WHERE ID IN (". implode(', ', $ids) .")"); |
| 45 |
} |
| 46 |
|
| 47 |
// select taking records |
| 48 |
$ob = empty($_GET['ob'])? "tT.id" : sanitize_text_field($_GET['ob']); |
| 49 |
if(!in_array($ob, ['tT.id', 'tT.date', 'tU.user_login', 'tT.points', 'tT.percent_correct'])) $ob = 'tT.id'; |
| 50 |
$dir = !empty($_GET['dir'])? $_GET['dir'] : "DESC"; |
| 51 |
|
| 52 |
|
| 53 |
$offset = empty($_GET['offset']) ? 0 : intval($_GET['offset']); |
| 54 |
$limit_sql = empty($_GET['watu_export']) ? "LIMIT $offset, 10" : ""; |
| 55 |
|
| 56 |
// ob, dir and limit can be overwritten by shortcode atts. When limit is passed we will not show pagination (leaderboard) |
| 57 |
if(!empty($atts['ob']) and in_array($atts['ob'], ['points', 'percent_correct', 'date'] ) ) $ob = 'tT.'.esc_attr($atts['ob']); |
| 58 |
if(!empty($atts['dir'])) $dir = esc_attr($atts['dir']); |
| 59 |
if(!empty($atts['num'])) $limit_sql = $wpdb->prepare(" LIMIT %d ", intval($atts['num'])); |
| 60 |
|
| 61 |
if(strtoupper($dir) != 'ASC' and strtoupper($dir) != 'DESC') $dir = 'DESC'; |
| 62 |
$odir = ($dir=='ASC')?'DESC':'ASC'; |
| 63 |
|
| 64 |
// filter / search? |
| 65 |
$filters = $joins = array(); |
| 66 |
$filter_sql = $left_join_sql = $role_join_sql = $group_join_sql = $left_join = ""; |
| 67 |
$join_sql="LEFT JOIN {$wpdb->users} tU ON tU.ID=tT.user_id"; |
| 68 |
|
| 69 |
// display name |
| 70 |
if(!empty($_GET['dn'])) { |
| 71 |
$_GET['dn'] = sanitize_text_field($_GET['dn']); |
| 72 |
switch($_GET['dnf']) { |
| 73 |
case 'contains': $like="%$_GET[dn]%"; break; |
| 74 |
case 'starts': $like="$_GET[dn]%"; break; |
| 75 |
case 'ends': $like="%$_GET[dn]"; break; |
| 76 |
case 'equals': |
| 77 |
default: $like=$_GET['dn']; break; |
| 78 |
} |
| 79 |
|
| 80 |
$joins[]= " display_name LIKE '$like' "; |
| 81 |
} |
| 82 |
|
| 83 |
// email |
| 84 |
if(!empty($_GET['email'])) { |
| 85 |
$_GET['email'] = sanitize_email($_GET['email']); |
| 86 |
switch($_GET['emailf']) { |
| 87 |
case 'contains': $like="%$_GET[email]%"; break; |
| 88 |
case 'starts': $like="$_GET[email]%"; break; |
| 89 |
case 'ends': $like="%$_GET[email]"; break; |
| 90 |
case 'equals': |
| 91 |
default: $like=$_GET['email']; break; |
| 92 |
} |
| 93 |
|
| 94 |
$joins[]=$wpdb->prepare(" user_email LIKE %s ", $like); |
| 95 |
$filters[]=$wpdb->prepare(" ((user_id=0 AND email LIKE %s) OR (user_id!=0 AND user_email LIKE %s)) ", $like, $like); |
| 96 |
$left_join = 'LEFT'; // when email is selected, do left join because it might be without logged user |
| 97 |
} |
| 98 |
|
| 99 |
// IP |
| 100 |
if(!empty($_GET['ip'])) { |
| 101 |
$_GET['ip'] = filter_var($_GET['ip'], FILTER_VALIDATE_IP); |
| 102 |
switch($_GET['ipf']) { |
| 103 |
case 'contains': $like="%$_GET[ip]%"; break; |
| 104 |
case 'starts': $like="$_GET[ip]%"; break; |
| 105 |
case 'ends': $like="%$_GET[ip]"; break; |
| 106 |
case 'equals': |
| 107 |
default: $like=$_GET['ip']; break; |
| 108 |
} |
| 109 |
|
| 110 |
$filters[]=$wpdb->prepare(" ip LIKE %s ", $like); |
| 111 |
} |
| 112 |
|
| 113 |
// Date |
| 114 |
if(!empty($_GET['date'])) { |
| 115 |
$_GET['date'] = sanitize_text_field($_GET['date']); |
| 116 |
switch($_GET['datef']) { |
| 117 |
case 'after': $filters[]=$wpdb->prepare(" date>%s ", $_GET['date']); break; |
| 118 |
case 'before': $filters[]=$wpdb->prepare(" date<%s ", $_GET['date']); break; |
| 119 |
case 'equals': |
| 120 |
default: $filters[]=$wpdb->prepare(" date=%s ", $_GET['date']); break; |
| 121 |
} |
| 122 |
} |
| 123 |
|
| 124 |
// Points |
| 125 |
if(!empty($_GET['points'])) { |
| 126 |
$_GET['points'] = floatval($_GET['points']); |
| 127 |
switch($_GET['pointsf']) { |
| 128 |
case 'less': $filters[]=$wpdb->prepare(" points < %f ", $_GET['points']); break; |
| 129 |
case 'more': $filters[]=$wpdb->prepare(" points > %f ", $_GET['points']); break; |
| 130 |
case 'equals': |
| 131 |
default: $filters[]=$wpdb->prepare(" points=%d ", $_GET['points']); break; |
| 132 |
} |
| 133 |
} |
| 134 |
|
| 135 |
// grade |
| 136 |
if(!empty($_GET['grade_id'])) { |
| 137 |
$filters[] = $wpdb->prepare(" grade_id=%d ", intval($_GET['grade_id'])); |
| 138 |
} |
| 139 |
|
| 140 |
// source URL |
| 141 |
if(!empty($_GET['source_url'])) { |
| 142 |
$filters[] = $wpdb->prepare(" source_url=%s ", esc_url_raw($_GET['source_url'])); |
| 143 |
} |
| 144 |
|
| 145 |
// Namaste! LMS Course |
| 146 |
if(!empty($_GET['namaste_course_id']) and !empty($namaste_courses)) { |
| 147 |
// let's select here as a subquery might be slower (is it?) |
| 148 |
$namaste_uids = array(-1); |
| 149 |
$namaste_uids1 = $wpdb->get_results($wpdb->prepare("SELECT user_id FROM ".NAMASTE_STUDENT_COURSES." |
| 150 |
WHERE course_id=%d AND (status='enrolled' OR status='completed')", intval($_GET['namaste_course_id']))); |
| 151 |
foreach($namaste_uids1 as $nu) $namaste_uids[] = intval($nu->user_id); |
| 152 |
|
| 153 |
// Use prepared statement for IN clause to prevent SQL injection |
| 154 |
$namaste_placeholders = implode(',', array_fill(0, count($namaste_uids), '%d')); |
| 155 |
$filters[] = $wpdb->prepare(" tT.user_id IN ($namaste_placeholders) ", $namaste_uids); |
| 156 |
} |
| 157 |
|
| 158 |
// construct filter & join SQLs |
| 159 |
if(count($filters)) { |
| 160 |
$filter_sql=" AND ".implode(" AND ", $filters); |
| 161 |
} |
| 162 |
|
| 163 |
if(count($joins)) { |
| 164 |
$join_sql=" $left_join JOIN {$wpdb->users} tU ON tU.ID=tT.user_id AND " |
| 165 |
.implode(" AND ", $joins); |
| 166 |
} |
| 167 |
|
| 168 |
// select unique source URLs in this quiz |
| 169 |
$source_urls = $wpdb->get_results($wpdb->prepare("SELECT DISTINCT(source_url) FROM ".WATU_TAKINGS." |
| 170 |
WHERE exam_id=%d AND source_url != ''", intval($_GET['exam_id']))); |
| 171 |
|
| 172 |
$takings = $wpdb->get_results("SELECT SQL_CALC_FOUND_ROWS tT.*, tU.user_login as user_login, tU.user_email as user_email, |
| 173 |
tG.gtitle as grade_title |
| 174 |
FROM ".WATU_TAKINGS." tT |
| 175 |
LEFT JOIN ".WATU_GRADES." tG ON tG.ID = tT.grade_id |
| 176 |
$join_sql |
| 177 |
WHERE tT.exam_id={$exam->ID} $filter_sql |
| 178 |
ORDER BY $ob $dir $limit_sql"); |
| 179 |
|
| 180 |
$count = $wpdb->get_var("SELECT FOUND_ROWS()"); |
| 181 |
|
| 182 |
$delim = get_option('watu_csv_delim'); |
| 183 |
if(empty($delim)) $delim = ','; |
| 184 |
|
| 185 |
// export CSV |
| 186 |
if(!empty($_GET['watu_export'])) { |
| 187 |
$newline=watu_define_newline(); |
| 188 |
|
| 189 |
$rows=array(); |
| 190 |
|
| 191 |
if($delim == 'tab') $delim = "\t"; |
| 192 |
|
| 193 |
$quotes = get_option('watu_csv_quotes'); |
| 194 |
$quote = ($quotes === '0') ? '' : '"'; |
| 195 |
|
| 196 |
$rows[]=__('User or IP Address', 'watu').$delim.__('Email address', 'watu').$delim.__('Date', 'watu').$delim.__('Points', 'watu').$delim.__('% Correct Answers', 'watu'). |
| 197 |
$delim.__('Num Correct Answers', 'watu').$delim.__('Num Wrong Answers', 'watu').$delim.__('Num Unanswered Questions', 'watu'). |
| 198 |
$delim.__('Result/Grade', 'watu'); |
| 199 |
foreach($takings as $taking) { |
| 200 |
if(empty($taking->email) and !empty($taking->user_email)) $taking->email = $taking->user_email; |
| 201 |
$row = ($taking->user_id ? $taking->user_login : $taking->ip).$delim.$taking->email.$delim.$quote.date(get_option('date_format'), strtotime($taking->date)).$quote.$delim. |
| 202 |
$taking->points.$delim.$taking->percent_correct.$delim.$taking->num_correct.$delim |
| 203 |
.$taking->num_wrong.$delim.$taking->num_empty.$delim.$quote.$taking->result.$quote; |
| 204 |
$rows[] = $row; |
| 205 |
} // end foreach taking |
| 206 |
$csv=implode($newline,$rows); |
| 207 |
|
| 208 |
$now = gmdate('D, d M Y H:i:s') . ' GMT'; |
| 209 |
$filename = 'exam-'.$exam->ID.'-results.csv'; |
| 210 |
header('Content-Type: ' . watu_get_mime_type()); |
| 211 |
header('Expires: ' . $now); |
| 212 |
header('Content-Disposition: attachment; filename="'.$filename.'"'); |
| 213 |
header('Pragma: no-cache'); |
| 214 |
echo $csv; |
| 215 |
exit; |
| 216 |
} |
| 217 |
|
| 218 |
// this var will be added to links at the view |
| 219 |
$filters_url="dn=".esc_attr($_GET['dn'] ?? '')."&dnf=".esc_attr($_GET['dnf'] ?? '')."&email=".esc_attr($_GET['email'] ?? '') |
| 220 |
."&emailf=".esc_attr($_GET['emailf'] ?? '')."&ip=".esc_attr($_GET['ip'] ?? '' )."&ipf=".esc_attr($_GET['ipf'] ?? '')."&date=" |
| 221 |
.esc_attr($_GET['date'] ?? '')."&datef=".esc_attr($_GET['datef'] ?? '')."&points=".esc_attr($_GET['points'] ?? '') |
| 222 |
."&pointsf=".esc_attr($_GET['pointsf'] ?? '')."&grade_id=".esc_attr($_GET['grade_id'] ?? '')."&source_url=".esc_attr($_GET['source_url'] ?? ''); |
| 223 |
|
| 224 |
if(!empty($namaste_courses) and !empty($_GET['namaste_course_id'])) { |
| 225 |
$filters_url .= "&namaste_course_id=".intval($_GET['namaste_course_id']); |
| 226 |
} |
| 227 |
|
| 228 |
// if in shortcode prepare the target URL |
| 229 |
if($in_shortcode) { |
| 230 |
$permalink = get_permalink($post->ID); |
| 231 |
$params = array('exam_id' => $exam->ID); |
| 232 |
$target_url = add_query_arg( $params, $permalink ); |
| 233 |
} |
| 234 |
else $target_url = "?page=watu_takings&exam_id=" . $exam->ID; |
| 235 |
|
| 236 |
$display_filters=(!sizeof($filters) and !sizeof($joins)) ? false : true; |
| 237 |
|
| 238 |
// shortcode params |
| 239 |
$show_email = isset($atts['show_email']) ? intval($atts['show_email']) : 1; |
| 240 |
$show_points = isset($atts['show_points']) ? intval($atts['show_points']) : 1; |
| 241 |
$show_percent = isset($atts['show_percent']) ? intval($atts['show_percent']) : 1; |
| 242 |
|
| 243 |
wp_enqueue_script('thickbox',null,array('jquery')); |
| 244 |
wp_enqueue_style('thickbox.css', '/'.WPINC.'/js/thickbox/thickbox.css', null, '1.0'); |
| 245 |
if(@file_exists(get_stylesheet_directory().'/watu/takings.php')) include get_stylesheet_directory().'/watu/takings.php'; |
| 246 |
else include(WATU_PATH . '/views/takings.php'); |
| 247 |
} |
| 248 |
|
| 249 |
// display taking details by ajax |
| 250 |
function watu_taking_details() { |
| 251 |
global $wpdb, $user_ID; |
| 252 |
|
| 253 |
$view_level = current_user_can('watu_manage') ? 'watu_manage' : 'manage_options'; |
| 254 |
|
| 255 |
// select taking |
| 256 |
$taking=$wpdb->get_row($wpdb->prepare("SELECT * FROM ".WATU_TAKINGS." |
| 257 |
WHERE id=%d", intval($_REQUEST['id']))); |
| 258 |
|
| 259 |
// select user |
| 260 |
$student=$wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->users} |
| 261 |
WHERE id=%d", $taking->user_id)); |
| 262 |
|
| 263 |
if(empty($taking->email) and !empty($student->ID)) $taking->email = $student->user_email; |
| 264 |
|
| 265 |
// make sure I'm admin or that's me |
| 266 |
if(!current_user_can($view_level) and $student->ID != $user_ID) { |
| 267 |
wp_die( __('You do not have sufficient permissions to access this page', 'watu') ); |
| 268 |
} |
| 269 |
|
| 270 |
// select exam |
| 271 |
$exam=$wpdb->get_row($wpdb->prepare("SELECT * FROM ".WATU_EXAMS." WHERE id=%d", $taking->exam_id)); |
| 272 |
|
| 273 |
if(@file_exists(get_stylesheet_directory().'/watu/taking_details.html.php')) include get_stylesheet_directory().'/watu/taking_details.html.php'; |
| 274 |
else include(WATU_PATH . '/views/taking_details.html.php'); |
| 275 |
exit; |
| 276 |
} |
| 277 |
|
| 278 |
// shortcode for showing the basic barchart included in the core WatuPRO |
| 279 |
// call this ONLY in the Final Screen of the quiz |
| 280 |
function watu_basic_chart($atts) { |
| 281 |
$taking_id = intval($GLOBALS['watu_taking_id']); |
| 282 |
$content = watu_barchart($taking_id, $atts); |
| 283 |
return $content; |
| 284 |
} |
| 285 |
|
| 286 |
// basic barchart your points vs avg points, your % vs avg % |
| 287 |
// this chart will be loaded by variable or shortcode in the Final screen |
| 288 |
// this function uses globals so it will work properly only when called on controllers/show_exam.php or a shortcode on the Final screen |
| 289 |
function watu_barchart($taking_id, $atts) { |
| 290 |
global $wpdb, $achieved; |
| 291 |
|
| 292 |
// normalize params |
| 293 |
$show = empty($atts['show']) ? 'both' : $atts['show']; |
| 294 |
if(!in_array($show, array('both', 'points', 'percent'))) $show = 'both'; |
| 295 |
$your_color = empty($atts['your_color']) ? "blue" : esc_attr($atts['your_color']); |
| 296 |
$avg_color = empty($atts['avg_color']) ? "gray" : esc_attr($atts['avg_color']); |
| 297 |
$your_percent_text = empty($atts['your_percent_text']) ? __('You: %d%% correct', 'watu') : esc_attr($atts['your_percent_text']); |
| 298 |
$avg_percent_text = empty($atts['avg_percent_text']) ? __('Avg. %d%% correct', 'watu') : esc_attr($atts['your_percent_text']); |
| 299 |
$your_points_text = empty($atts['your_points_text']) ? __('Your points: %s', 'watu') : esc_attr($atts['your_points_text']); |
| 300 |
$avg_points_text = empty($atts['avg_points_text']) ? __('Avg. points: %s', 'watu') : esc_attr($atts['avg_points_text']); |
| 301 |
$step = 2; |
| 302 |
|
| 303 |
// select taking |
| 304 |
$taking = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".WATU_TAKINGS." WHERE ID=%d", $taking_id)); |
| 305 |
|
| 306 |
// get average points |
| 307 |
$all_point_rows = $wpdb->get_results($wpdb->prepare("SELECT points FROM ".WATU_TAKINGS." WHERE exam_id=%d", $taking->exam_id)); |
| 308 |
$all_points = 0; |
| 309 |
foreach($all_point_rows as $r) $all_points += $r->points; |
| 310 |
$all_points += $achieved; |
| 311 |
$avg_points = round($all_points / ($wpdb->num_rows + 1), 1); |
| 312 |
|
| 313 |
// the points step should rougly make the higher points bar 200px high |
| 314 |
$more_points = ($avg_points > $taking->points) ? $avg_points : $taking->points; |
| 315 |
if(!$more_points) $more_points = 1; // set to non-zero for division |
| 316 |
$points_step = round(200 / $more_points, 2); |
| 317 |
|
| 318 |
// create & return the chart HTML |
| 319 |
$content = '<table class="watu-basic-chart"><tr>'; |
| 320 |
|
| 321 |
if($show == 'points' or $show == 'both') { |
| 322 |
$your_points_text = sprintf($your_points_text, $taking->points); |
| 323 |
$avg_points_text = sprintf($avg_points_text, $avg_points); |
| 324 |
|
| 325 |
// normalize points here, shouldn't be less than zero when calculating the bar height |
| 326 |
if($taking->points < 0) $taking->points = 0; |
| 327 |
|
| 328 |
$content .= '<td style="vertical-align:bottom;"><table class="watu-basic-chart-points"><tr><td align="center" style="vertical-align:bottom;">'; |
| 329 |
$content .= '<div style="background-color:'.$your_color.';width:100px;height:'.round($points_step * $taking->points). 'px;"> </div>'; |
| 330 |
$content .='</td><td align="center" style="vertical-align:bottom;">'; |
| 331 |
$content .= '<div style="background-color:'.$avg_color.';width:100px;height:'.round($points_step * $avg_points). 'px;"> </div>'; |
| 332 |
$content .='</td></tr><tr><td align="center">' . $your_points_text . '</td><td align="center">'. $avg_points_text .'</td></tr>'; |
| 333 |
$content .= '</table></td>'; |
| 334 |
} |
| 335 |
$content .= '</tr></table>'; |
| 336 |
|
| 337 |
return $content; |
| 338 |
} |
| 339 |
|
| 340 |
function watu_shortcode_takings($atts) { |
| 341 |
ob_start(); |
| 342 |
watu_takings(true, $atts); |
| 343 |
$content = ob_get_clean(); |
| 344 |
return $content; |
| 345 |
} |
| 346 |
|
| 347 |
// handle MoolaMojo integration if enabled |
| 348 |
function watu_taking_transfer_moola($taking_id, $exam, $user_id, $points, $grade_id) { |
| 349 |
global $wpdb; |
| 350 |
|
| 351 |
if(empty($user_id)) return false; |
| 352 |
if(empty($points) and empty($grade_id)) return false; |
| 353 |
if(get_option('watu_integrate_moolamojo') != 1) return false; |
| 354 |
|
| 355 |
$advanced_settings = unserialize(stripslashes($exam->advanced_settings)); |
| 356 |
if(empty($advanced_settings['transfer_moola'])) return false; |
| 357 |
|
| 358 |
|
| 359 |
if($advanced_settings['transfer_moola_mode'] == 'equal') $credits = $points; |
| 360 |
else { |
| 361 |
// select grade points |
| 362 |
if($grade_id == 0) return false; |
| 363 |
$credits = $wpdb->get_var($wpdb->prepare("SELECT moola FROM ".WATU_GRADES." WHERE ID=%d", $grade_id)); |
| 364 |
} |
| 365 |
|
| 366 |
if($credits == 0) return false; |
| 367 |
|
| 368 |
// actually transfer the moola |
| 369 |
if($credits > 0 ) $reward = true; |
| 370 |
else { |
| 371 |
$reward = false; |
| 372 |
$credits = abs($credits); |
| 373 |
} |
| 374 |
do_action("moolamojo_transaction", $reward, $credits, __('submitted test', 'watu'), $user_id, WATU_TAKINGS, $taking_id); |
| 375 |
|
| 376 |
} // end transfer_moola |
| 377 |
|
| 378 |
// register personal data eraser |
| 379 |
function watu_register_eraser($erasers) { |
| 380 |
$erasers['watu'] = array( |
| 381 |
'eraser_friendly_name' => __( 'Watu Quiz', 'watu' ), |
| 382 |
'callback' => 'watu_erase_data' |
| 383 |
); |
| 384 |
|
| 385 |
return $erasers; |
| 386 |
} |
| 387 |
|
| 388 |
// again deleting user data but this time when called from the WP erase data hook |
| 389 |
function watu_erase_data($email_address, $page = 1) { |
| 390 |
global $wpdb; |
| 391 |
|
| 392 |
$number = 200; // Limit us to avoid timing out |
| 393 |
$page = (int) $page; |
| 394 |
$email_address = sanitize_email($email_address); |
| 395 |
|
| 396 |
// find student |
| 397 |
$user = get_user_by('email', $email_address); |
| 398 |
|
| 399 |
if(empty($user->ID)) { |
| 400 |
// delete exam results |
| 401 |
$wpdb->query($wpdb->prepare("DELETE FROM ".WATU_TAKINGS." WHERE email=%s", $email_address)); |
| 402 |
} |
| 403 |
else { |
| 404 |
$wpdb->query($wpdb->prepare("DELETE FROM ".WATU_TAKINGS." WHERE user_id=%d", $user->ID)); |
| 405 |
} |
| 406 |
|
| 407 |
return array( 'items_removed' => true, |
| 408 |
'items_retained' => false, |
| 409 |
'messages' => array(), // no messages |
| 410 |
'done' => true, |
| 411 |
); |
| 412 |
} // end data eraser |
| 413 |
|
| 414 |
|