PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.7.4
Tutor LMS – eLearning and online course solution v2.7.4
3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Quiz_Attempts_List.php
tutor / classes Last commit date
Addons.php 2 years ago Admin.php 2 years ago Ajax.php 1 year ago Announcements.php 3 years ago Assets.php 2 years ago Backend_Page_Trait.php 3 years ago Course.php 1 year ago Course_Embed.php 3 years ago Course_Filter.php 1 year ago Course_List.php 1 year ago Course_Settings_Tabs.php 3 years ago Course_Widget.php 3 years ago Custom_Validation.php 3 years ago Dashboard.php 3 years ago FormHandler.php 2 years ago Frontend.php 2 years ago Gutenberg.php 3 years ago Input.php 3 years ago Instructor.php 2 years ago Instructors_List.php 1 year ago Lesson.php 1 year ago Options_V2.php 1 year ago Permalink.php 2 years ago Post_types.php 2 years ago Private_Course_Access.php 3 years ago Q_And_A.php 1 year ago Question_Answers_List.php 3 years ago Quiz.php 1 year ago Quiz_Attempts_List.php 2 years ago RestAPI.php 2 years ago Reviews.php 3 years ago Rewrite_Rules.php 2 years ago Shortcode.php 1 year ago Student.php 2 years ago Students_List.php 3 years ago Taxonomies.php 3 years ago Template.php 2 years ago Theme_Compatibility.php 3 years ago Tools.php 3 years ago Tools_V2.php 2 years ago Tutor.php 2 years ago TutorEDD.php 2 years ago Tutor_Base.php 2 years ago Tutor_Setup.php 2 years ago Upgrader.php 2 years ago User.php 2 years ago Utils.php 1 year ago Video_Stream.php 3 years ago WhatsNew.php 2 years ago Withdraw.php 2 years ago Withdraw_Requests_List.php 3 years ago WooCommerce.php 2 years ago
Quiz_Attempts_List.php
303 lines
1 <?php
2 /**
3 * Quiz attempt list management
4 *
5 * @package Tutor\QuestionAnswer
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 namespace TUTOR;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 use Tutor\Cache\QuizAttempts;
18 use Tutor\Models\QuizModel;
19
20 /**
21 * Quiz attempt class
22 *
23 * @since 1.0.0
24 */
25 class Quiz_Attempts_List {
26
27 const QUIZ_ATTEMPT_PAGE = 'tutor_quiz_attempts';
28
29 /**
30 * Trait for utilities
31 *
32 * @var $page_title
33 */
34
35 use Backend_Page_Trait;
36 /**
37 * Page Title
38 *
39 * @var $page_title
40 */
41 public $page_title;
42
43 /**
44 * Bulk Action
45 *
46 * @var $bulk_action
47 */
48 public $bulk_action = true;
49
50 /**
51 * Handle dependencies
52 *
53 * @since 1.0.0
54 *
55 * @param boolean $register_hook should register hook or not.
56 */
57 public function __construct( $register_hook = true ) {
58
59 $this->page_title = __( 'Quiz Attempts', 'tutor' );
60 if ( ! $register_hook ) {
61 return;
62 }
63
64 /**
65 * Handle bulk action
66 *
67 * @since 2.0.0
68 */
69 add_action( 'wp_ajax_tutor_quiz_attempts_bulk_action', array( $this, 'quiz_attempts_bulk_action' ) );
70 add_action( 'wp_ajax_tutor_quiz_attempts_count', array( $this, 'get_quiz_attempts_stat' ) );
71
72 /**
73 * Delete quiz attempt cache
74 *
75 * @since 2.1.0
76 */
77 add_action( 'tutor_quiz/attempt_ended', array( new QuizAttempts(), 'delete_cache' ) );
78 add_action( 'tutor_quiz/attempt_deleted', array( new QuizAttempts(), 'delete_cache' ) );
79 add_action( 'tutor_quiz/answer/review/after', array( new QuizAttempts(), 'delete_cache' ) );
80 }
81
82 /**
83 * Get the attempts stat from specific instructor context
84 *
85 * @since 2.0.0
86 *
87 * @return array
88 */
89 public function get_quiz_attempts_stat() {
90 global $wpdb;
91
92 /**
93 * Parse `passing_grade` value from `attempt_info` serialized data.
94 *
95 * Data Format : "passing_grade";s:2:"80" or "passing_grade";s:3:"100"
96 * Expected Output : 80 or 100
97 *
98 * TODO: Optimize SQL query.
99 */
100 $pass_mark = "((( SUBSTRING_INDEX(
101 SUBSTRING_INDEX(
102 attempt_info,
103 CONCAT(
104 '\"passing_grade\";s:',
105 SUBSTRING_INDEX(SUBSTRING_INDEX(attempt_info, '\"passing_grade\";s:', -1), ':\"', 1),
106 ':\"'
107 ),
108 -1
109 ),
110 '\"',
111 1
112 ))/100) * quiz_attempts.total_marks)";
113
114 $pending_count = "(SELECT COUNT(DISTINCT attempt_answer_id) FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE quiz_attempt_id=quiz_attempts.attempt_id AND is_correct IS NULL)";
115 $pass_clause = " AND quiz_attempts.earned_marks >= {$pass_mark} ";
116 $fail_clause = " AND quiz_attempts.earned_marks < {$pass_mark} AND {$pending_count} < 1 ";
117 $pending_clause = " AND {$pending_count} > 0 ";
118
119 $user_id = get_current_user_id();
120 $user_clause = '';
121 if ( ! current_user_can( 'administrator' ) ) {
122 $user_clause = "AND quiz.post_author = {$user_id}";
123 }
124
125 $count_obj = (object) array(
126 'pass' => 0,
127 'fail' => 0,
128 'pending' => 0,
129 );
130
131 $is_ajax_action = 'tutor_quiz_attempts_count' === Input::post( 'action' );
132
133 if ( $is_ajax_action ) {
134 $attempt_cache = new QuizAttempts();
135
136 if ( $attempt_cache->has_cache() && ! is_null( $attempt_cache->get_cache()->pass ) ) {
137 $count_obj = $attempt_cache->get_cache();
138 } else {
139 $select_stmt = "SELECT COUNT( DISTINCT attempt_id)
140 FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
141 INNER JOIN {$wpdb->posts} quiz ON quiz_attempts.quiz_id = quiz.ID
142 INNER JOIN {$wpdb->prefix}tutor_quiz_attempt_answers AS ans
143 ON quiz_attempts.attempt_id = ans.quiz_attempt_id";
144
145 $count_obj->pass = (int) $wpdb->get_var(
146 $wpdb->prepare(
147 "{$select_stmt}
148 WHERE attempt_status != %s
149 {$pass_clause}
150 {$user_clause}
151 ",
152 'attempt_started'
153 )
154 );
155
156 $count_obj->fail = (int) $wpdb->get_var(
157 $wpdb->prepare(
158 "{$select_stmt}
159 WHERE attempt_status != %s
160 {$fail_clause}
161 {$user_clause}
162 ",
163 'attempt_started'
164 )
165 );
166
167 $count_obj->pending = (int) $wpdb->get_var(
168 $wpdb->prepare(
169 "{$select_stmt}
170 WHERE attempt_status != %s
171 {$pending_clause}
172 {$user_clause}
173 ",
174 'attempt_started'
175 )
176 );
177
178 $attempt_cache->data = $count_obj;
179 $attempt_cache->set_cache();
180 }
181 }
182
183 $all = $count_obj->pass + $count_obj->fail + $count_obj->pending;
184 $pass = $count_obj->pass;
185 $fail = $count_obj->fail;
186 $pending = $count_obj->pending;
187 $response = compact( 'all', 'pass', 'fail', 'pending' );
188
189 return $is_ajax_action ? wp_send_json_success( $response ) : $response;
190 }
191
192 /**
193 * Available tabs that will visible on the right side of page navbar
194 *
195 * @since 2.0.0
196 *
197 * @param string $user_id selected quiz_attempts id | optional.
198 * @param int $course_id selected quiz_attempts id | optional.
199 * @param string $date selected date | optional.
200 * @param string $search search by user name or email | optional.
201 *
202 * @return array
203 */
204 public function tabs_key_value( $user_id, $course_id, $date, $search ): array {
205 $url = get_pagenum_link();
206 $stats = $this->get_quiz_attempts_stat();
207
208 $tabs = array(
209 array(
210 'key' => 'all',
211 'title' => __( 'All', 'tutor' ),
212 'value' => $stats['all'],
213 'url' => $url . '&data=all',
214 ),
215 array(
216 'key' => 'pass',
217 'title' => __( 'Pass', 'tutor' ),
218 'value' => $stats['pass'],
219 'url' => $url . '&data=pass',
220 ),
221 array(
222 'key' => 'fail',
223 'title' => __( 'Fail', 'tutor' ),
224 'value' => $stats['fail'],
225 'url' => $url . '&data=fail',
226 ),
227 array(
228 'key' => 'pending',
229 'title' => __( 'Pending', 'tutor' ),
230 'value' => $stats['pending'],
231 'url' => $url . '&data=pending',
232 ),
233 );
234
235 return $tabs;
236 }
237
238 /**
239 * Prepare bulk actions that will show on dropdown options
240 *
241 * @since 2.0.0
242 *
243 * @return array
244 */
245 public function prpare_bulk_actions(): array {
246 $actions = array(
247 $this->bulk_action_default(),
248 $this->bulk_action_delete(),
249 );
250 return $actions;
251 }
252
253
254 /**
255 * Handle bulk action for instructor delete
256 *
257 * @since 2.0.0
258 *
259 * @return void send wp_json response
260 */
261 public function quiz_attempts_bulk_action() {
262 // check nonce.
263 tutor_utils()->checking_nonce();
264
265 // Check if user is privileged.
266 if ( ! current_user_can( 'administrator' ) ) {
267 wp_send_json_error( tutor_utils()->error_message() );
268 }
269
270 $bulk_action = Input::post( 'bulk-action', '' );
271 $bulk_ids = Input::post( 'bulk-ids', '' );
272 $bulk_ids = explode( ',', $bulk_ids );
273 $bulk_ids = array_map(
274 function( $id ) {
275 return (int) trim( $id );
276 },
277 $bulk_ids
278 );
279
280 switch ( $bulk_action ) {
281 case 'delete':
282 QuizModel::delete_quiz_attempt( $bulk_ids );
283 break;
284 }
285
286 wp_send_json_success();
287 }
288
289 /**
290 * Get bulk action as an array
291 *
292 * @since 2.0.0
293 *
294 * @return array
295 */
296 public function get_bulk_actions() {
297 $actions = array(
298 'delete' => 'Delete',
299 );
300 return $actions;
301 }
302 }
303