PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.1.4
Tutor LMS – eLearning and online course solution v2.1.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 3 years ago Admin.php 3 years ago Ajax.php 3 years ago Announcements.php 3 years ago Assets.php 3 years ago Backend_Page_Trait.php 3 years ago Course.php 3 years ago Course_Embed.php 3 years ago Course_Filter.php 3 years ago Course_List.php 3 years 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 3 years ago Frontend.php 3 years ago Gutenberg.php 3 years ago Input.php 3 years ago Instructor.php 3 years ago Instructors_List.php 3 years ago Lesson.php 3 years ago Options_V2.php 3 years ago Post_types.php 3 years ago Private_Course_Access.php 3 years ago Q_and_A.php 3 years ago Question_Answers_List.php 3 years ago Quiz.php 3 years ago Quiz_Attempts_List.php 3 years ago RestAPI.php 3 years ago Reviews.php 3 years ago Rewrite_Rules.php 3 years ago Shortcode.php 3 years ago Student.php 3 years ago Students_List.php 3 years ago Taxonomies.php 3 years ago Template.php 3 years ago Theme_Compatibility.php 3 years ago Tools.php 3 years ago Tools_V2.php 3 years ago Tutor.php 3 years ago TutorEDD.php 3 years ago Tutor_Base.php 3 years ago Tutor_Setup.php 3 years ago Upgrader.php 3 years ago User.php 3 years ago Utils.php 3 years ago Video_Stream.php 3 years ago Withdraw.php 3 years ago Withdraw_Requests_List.php 3 years ago WooCommerce.php 3 years ago
Quiz_Attempts_List.php
289 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 $user_id = get_current_user_id();
93 // Set query based on action tab.
94 $pass_mark = "(((SUBSTRING_INDEX(SUBSTRING_INDEX(quiz_attempts.attempt_info, '\"passing_grade\";s:2:\"', -1), '\"', 1))/100)*quiz_attempts.total_marks)";
95 $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)";
96
97 $pass_clause = " AND quiz_attempts.earned_marks >= {$pass_mark} ";
98
99 $fail_clause = " AND quiz_attempts.earned_marks < {$pass_mark} ";
100
101 $pending_clause = " AND {$pending_count} > 0 ";
102
103 $user_clause = '';
104 if ( ! current_user_can( 'administrator' ) ) {
105 $user_clause = "AND quiz.post_author = {$user_id}";
106 }
107
108 $count = array();
109 $is_ajax_action = 'tutor_quiz_attempts_count' === Input::post( 'action' );
110 if ( $is_ajax_action ) {
111 $attempt_cache = new QuizAttempts();
112
113 if ( $attempt_cache->has_cache() ) {
114 $count = $attempt_cache->get_cache();
115 } else {
116 // TODO: need to fix prepare violation.
117 $count = $wpdb->get_col(
118 $wpdb->prepare(
119 "SELECT COUNT( DISTINCT attempt_id)
120 FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
121 INNER JOIN {$wpdb->posts} quiz
122 ON quiz_attempts.quiz_id = quiz.ID
123 INNER JOIN {$wpdb->prefix}tutor_quiz_attempt_answers AS ans
124 ON quiz_attempts.attempt_id = ans.quiz_attempt_id
125
126 WHERE attempt_status != %s
127 {$pass_clause}
128 {$user_clause}
129
130 UNION
131
132 SELECT COUNT( DISTINCT attempt_id)
133 FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
134 INNER JOIN {$wpdb->posts} quiz
135 ON quiz_attempts.quiz_id = quiz.ID
136 INNER JOIN {$wpdb->prefix}tutor_quiz_attempt_answers AS ans
137 ON quiz_attempts.attempt_id = ans.quiz_attempt_id
138
139 WHERE attempt_status != %s
140 {$fail_clause}
141 {$user_clause}
142
143 UNION
144
145 SELECT COUNT( DISTINCT attempt_id)
146 FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
147 INNER JOIN {$wpdb->posts} quiz
148 ON quiz_attempts.quiz_id = quiz.ID
149 INNER JOIN {$wpdb->prefix}tutor_quiz_attempt_answers AS ans
150 ON quiz_attempts.attempt_id = ans.quiz_attempt_id
151
152 WHERE attempt_status != %s
153 {$pending_clause}
154 {$user_clause}
155
156 ",
157 'attempt_started',
158 'attempt_started',
159 'attempt_started'
160 )
161 );
162 $attempt_cache->data = array(
163 $count[0] ?? 0, // Pass.
164 $count[1] ?? 0, // Fail.
165 $count[2] ?? 0, // Pending.
166 );
167 $attempt_cache->set_cache();
168 }
169 }
170
171 $count_pass = $count[0] ?? 0;
172 $count_fail = $count[1] ?? 0;
173 $count_pending = $count[2] ?? 0;
174
175 $all = $count_pass + $count_fail + $count_pending;
176 $pass = $count_pass;
177 $fail = $count_fail;
178 $pending = $count_pending;
179 $response = compact( 'all', 'pass', 'fail', 'pending' );
180 return $is_ajax_action ? wp_send_json_success( $response ) : $response;
181 }
182
183 /**
184 * Available tabs that will visible on the right side of page navbar
185 *
186 * @since 2.0.0
187 *
188 * @param string $user_id selected quiz_attempts id | optional.
189 * @param int $course_id selected quiz_attempts id | optional.
190 * @param string $date selected date | optional.
191 * @param string $search search by user name or email | optional.
192 *
193 * @return array
194 */
195 public function tabs_key_value( $user_id, $course_id, $date, $search ): array {
196 $url = get_pagenum_link();
197 $stats = $this->get_quiz_attempts_stat();
198
199 $tabs = array(
200 array(
201 'key' => 'all',
202 'title' => __( 'All', 'tutor' ),
203 'value' => $stats['all'],
204 'url' => $url . '&data=all',
205 ),
206 array(
207 'key' => 'pass',
208 'title' => __( 'Pass', 'tutor' ),
209 'value' => $stats['pass'],
210 'url' => $url . '&data=pass',
211 ),
212 array(
213 'key' => 'fail',
214 'title' => __( 'Fail', 'tutor' ),
215 'value' => $stats['fail'],
216 'url' => $url . '&data=fail',
217 ),
218 array(
219 'key' => 'pending',
220 'title' => __( 'Pending', 'tutor' ),
221 'value' => $stats['pending'],
222 'url' => $url . '&data=pending',
223 ),
224 );
225
226 return $tabs;
227 }
228
229 /**
230 * Prepare bulk actions that will show on dropdown options
231 *
232 * @since 2.0.0
233 *
234 * @return array
235 */
236 public function prpare_bulk_actions(): array {
237 $actions = array(
238 $this->bulk_action_default(),
239 $this->bulk_action_delete(),
240 );
241 return $actions;
242 }
243
244
245 /**
246 * Handle bulk action for instructor delete
247 *
248 * @since 2.0.0
249 *
250 * @return void send wp_json response
251 */
252 public function quiz_attempts_bulk_action() {
253 // check nonce.
254 tutor_utils()->checking_nonce();
255
256 $bulk_action = Input::post( 'bulk-action', '' );
257 $bulk_ids = Input::post( 'bulk-ids', '' );
258 $bulk_ids = explode( ',', $bulk_ids );
259 $bulk_ids = array_map(
260 function( $id ) {
261 return (int) trim( $id );
262 },
263 $bulk_ids
264 );
265
266 switch ( $bulk_action ) {
267 case 'delete':
268 QuizModel::delete_quiz_attempt( $bulk_ids );
269 break;
270 }
271
272 wp_send_json_success();
273 }
274
275 /**
276 * Get bulk action as an array
277 *
278 * @since 2.0.0
279 *
280 * @return array
281 */
282 public function get_bulk_actions() {
283 $actions = array(
284 'delete' => 'Delete',
285 );
286 return $actions;
287 }
288 }
289