PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / trunk
Tutor LMS – eLearning and online course solution vtrunk
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 11 months ago Admin.php 2 months ago Ajax.php 9 months ago Announcements.php 1 year ago Assets.php 2 months ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 11 months ago Container.php 11 months ago Course.php 2 months ago Course_Embed.php 3 years ago Course_Filter.php 1 year ago Course_List.php 5 months ago Course_Settings_Tabs.php 1 year ago Course_Widget.php 1 year ago Custom_Validation.php 3 years ago Dashboard.php 1 year ago Earnings.php 9 months ago FormHandler.php 2 years ago Frontend.php 1 year ago Gutenberg.php 1 year ago Icon.php 8 months ago Input.php 1 year ago Instructor.php 2 months ago Instructors_List.php 2 months ago Lesson.php 2 weeks ago Options_V2.php 7 months ago Permalink.php 2 years ago Post_types.php 1 year ago Private_Course_Access.php 1 year ago Q_And_A.php 10 months ago Question_Answers_List.php 11 months ago Quiz.php 2 weeks ago QuizBuilder.php 2 days ago Quiz_Attempts_List.php 9 months ago RestAPI.php 2 years ago Reviews.php 9 months ago Rewrite_Rules.php 2 years ago Shortcode.php 9 months ago Singleton.php 1 year ago Student.php 2 months ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 9 months ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 3 weeks ago Tutor.php 2 months ago TutorEDD.php 1 year ago Tutor_Base.php 2 years ago Tutor_Setup.php 8 months ago Upgrader.php 9 months ago User.php 4 months ago Utils.php 2 days ago Video_Stream.php 3 years ago WhatsNew.php 9 months ago Withdraw.php 2 days ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 2 days ago
Quiz_Attempts_List.php
301 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 /**
38 * Bulk Action
39 *
40 * @var $bulk_action
41 */
42 public $bulk_action = true;
43
44 /**
45 * Handle dependencies
46 *
47 * @since 1.0.0
48 *
49 * @param boolean $register_hook should register hook or not.
50 */
51 public function __construct( $register_hook = true ) {
52 if ( ! $register_hook ) {
53 return;
54 }
55
56 /**
57 * Handle bulk action
58 *
59 * @since 2.0.0
60 */
61 add_action( 'wp_ajax_tutor_quiz_attempts_bulk_action', array( $this, 'quiz_attempts_bulk_action' ) );
62 add_action( 'wp_ajax_tutor_quiz_attempts_count', array( $this, 'get_quiz_attempts_stat' ) );
63
64 /**
65 * Delete quiz attempt cache
66 *
67 * @since 2.1.0
68 */
69 add_action( 'tutor_quiz/attempt_ended', array( new QuizAttempts(), 'delete_cache' ) );
70 add_action( 'tutor_quiz/attempt_deleted', array( new QuizAttempts(), 'delete_cache' ) );
71 add_action( 'tutor_quiz/answer/review/after', array( new QuizAttempts(), 'delete_cache' ) );
72 }
73
74 /**
75 * Page title fallback
76 *
77 * @since 3.5.0
78 *
79 * @param string $name Property name.
80 *
81 * @return string
82 */
83 public function __get( $name ) {
84 if ( 'page_title' === $name ) {
85 return esc_html__( 'Quiz Attempts', 'tutor' );
86 }
87 }
88
89 /**
90 * Get the attempts stat from specific instructor context
91 *
92 * @since 2.0.0
93 * @since 3.8.0 refactor and query optimize.
94 *
95 * @return array
96 */
97 public function get_quiz_attempts_stat() {
98 global $wpdb;
99
100 if ( wp_doing_ajax() ) {
101 tutor_utils()->checking_nonce();
102 }
103
104 $count_obj = (object) array(
105 'pass' => 0,
106 'fail' => 0,
107 'pending' => 0,
108 );
109
110 $is_ajax_action = 'tutor_quiz_attempts_count' === Input::post( 'action' );
111 $user_id = get_current_user_id();
112 $course_id = Input::post( 'course_id', 0, Input::TYPE_INT );
113 $date = Input::post( 'date', '' );
114 $search = Input::post( 'search', '' );
115
116 if ( $is_ajax_action ) {
117 $current_params = compact( 'course_id', 'date', 'search' );
118 $attempt_cache = new QuizAttempts( $current_params );
119
120 $cached_attempts = $attempt_cache->get_cache();
121 if ( $attempt_cache->has_cache() && $attempt_cache->is_same_query() && isset( $cached_attempts['result'] ) ) {
122 $count_obj = $cached_attempts['result'];
123 } else {
124
125 $course_filter = $course_id ? $wpdb->prepare( ' AND quiz_attempts.course_id = %d', $course_id ) : '';
126 $date_filter = empty( $date ) ? '' : $wpdb->prepare( ' AND DATE(quiz_attempts.attempt_started_at) = %s ', $date );
127 $user_clause = User::is_admin() ? '' : $wpdb->prepare( ' AND quiz.post_author = %d', $user_id );
128
129 $search_term_raw = $search;
130 $search_filter = '%' . $wpdb->esc_like( $search ) . '%';
131
132 //phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
133 $results = $wpdb->get_results(
134 $wpdb->prepare(
135 "SELECT result, COUNT( DISTINCT attempt_id) AS total
136 FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
137 INNER JOIN {$wpdb->posts} quiz ON quiz_attempts.quiz_id = quiz.ID
138 INNER JOIN {$wpdb->users} AS users ON quiz_attempts.user_id = users.ID
139 INNER JOIN {$wpdb->posts} AS course ON course.ID = quiz_attempts.course_id
140 WHERE result IS NOT NULL
141 AND (
142 users.user_email = %s
143 OR users.display_name LIKE %s
144 OR quiz.post_title LIKE %s
145 OR course.post_title LIKE %s
146 )
147 {$user_clause}
148 {$course_filter}
149 {$date_filter}
150 GROUP BY result",
151 $search_term_raw,
152 $search_filter,
153 $search_filter,
154 $search_filter
155 )
156 );
157 //phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
158
159 foreach ( $results as $row ) {
160 if ( isset( $count_obj->{$row->result} ) ) {
161 $count_obj->{$row->result} = (int) $row->total;
162 }
163 }
164
165 $attempt_cache->data = $count_obj;
166 $attempt_cache->set_cache();
167 }
168 }
169
170 $all = $count_obj->pass + $count_obj->fail + $count_obj->pending;
171 $pass = $count_obj->pass;
172 $fail = $count_obj->fail;
173 $pending = $count_obj->pending;
174 $response = compact( 'all', 'pass', 'fail', 'pending' );
175
176 return $is_ajax_action ? wp_send_json_success( $response ) : $response;
177 }
178
179 /**
180 * Available tabs that will visible on the right side of page navbar
181 *
182 * @since 2.0.0
183 *
184 * @param string $user_id selected quiz_attempts id | optional.
185 * @param int $course_id selected quiz_attempts id | optional.
186 * @param string $date selected date | optional.
187 * @param string $search search by user name or email | optional.
188 *
189 * @return array
190 */
191 public function tabs_key_value( $user_id, $course_id, $date, $search ): array {
192 $url = apply_filters( 'tutor_data_tab_base_url', get_pagenum_link() );
193 $stats = $this->get_quiz_attempts_stat();
194
195 $tabs = array(
196 array(
197 'key' => '',
198 'title' => __( 'All', 'tutor' ),
199 'value' => $stats['all'],
200 'url' => $url . '&data=all',
201 ),
202 array(
203 'key' => 'pass',
204 'title' => __( 'Pass', 'tutor' ),
205 'value' => $stats['pass'],
206 'url' => $url . '&data=pass',
207 ),
208 array(
209 'key' => 'fail',
210 'title' => __( 'Fail', 'tutor' ),
211 'value' => $stats['fail'],
212 'url' => $url . '&data=fail',
213 ),
214 array(
215 'key' => 'pending',
216 'title' => __( 'Pending', 'tutor' ),
217 'value' => $stats['pending'],
218 'url' => $url . '&data=pending',
219 ),
220 );
221
222 return $tabs;
223 }
224
225 /**
226 * Prepare bulk actions that will show on dropdown options
227 *
228 * @since 2.0.0
229 *
230 * @return array
231 */
232 public function prepare_bulk_actions(): array {
233 $actions = array(
234 $this->bulk_action_default(),
235 $this->bulk_action_delete(),
236 );
237 return $actions;
238 }
239
240
241 /**
242 * Handle bulk action for instructor delete
243 *
244 * @since 2.0.0
245 *
246 * @return void send wp_json response
247 */
248 public function quiz_attempts_bulk_action() {
249 // check nonce.
250 tutor_utils()->checking_nonce();
251
252 // Check if user is privileged.
253 if ( ! User::has_any_role( array( User::ADMIN, User::INSTRUCTOR ) ) ) {
254 wp_send_json_error( tutor_utils()->error_message() );
255 }
256
257 $bulk_action = Input::post( 'bulk-action', '' );
258 $bulk_ids = Input::post( 'bulk-ids', '' );
259 $bulk_ids = explode( ',', $bulk_ids );
260 $bulk_ids = array_map(
261 function( $id ) {
262 return (int) trim( $id );
263 },
264 $bulk_ids
265 );
266
267 // prevent instructor to remove quiz attempt from admin.
268 $bulk_ids = array_filter(
269 $bulk_ids,
270 function ( $attempt_id ) {
271 $attempt = tutor_utils()->get_attempt( $attempt_id );
272 $user_id = get_current_user_id();
273 $course_id = $attempt && is_object( $attempt ) ? $attempt->course_id : 0;
274 return $course_id && tutor_utils()->can_user_edit_course( $user_id, $course_id );
275 }
276 );
277
278 switch ( $bulk_action ) {
279 case 'delete':
280 QuizModel::delete_quiz_attempt( $bulk_ids );
281 break;
282 }
283
284 wp_send_json_success();
285 }
286
287 /**
288 * Get bulk action as an array
289 *
290 * @since 2.0.0
291 *
292 * @return array
293 */
294 public function get_bulk_actions() {
295 $actions = array(
296 'delete' => 'Delete',
297 );
298 return $actions;
299 }
300 }
301