PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.2
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.2
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / rest-api / v1 / frontend / class-lp-rest-users-controller.php

class-lp-rest-users-controller.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.2, at inc/rest-api/v1/frontend/class-lp-rest-users-controller.php

456 lines 13.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use LearnPress\Models\CourseModel;
4 use LearnPress\Models\Question\QuestionPostModel;
5 use LearnPress\Models\Quiz\QuizQuestionModel;
6 use LearnPress\Models\UserItems\UserQuizModel;
7
8 /**
9 * Class LP_REST_Users_Controller
10 *
11 * @since 3.3.0
12 */
13 class LP_REST_Users_Controller extends LP_Abstract_REST_Controller {
14 /**
15 * @var LP_User
16 */
17 protected $user = null;
18
19 /**
20 * @var LP_Course
21 */
22 protected $course = null;
23
24 /**
25 * @var LP_Course_Item|LP_Quiz|LP_Lesson
26 */
27 protected $item = null;
28
29 /**
30 * @var LP_User_Item_Course
31 */
32 protected $user_course = null;
33
34 /**
35 * @var LP_User_Item|LP_User_Item_Quiz
36 */
37 protected $user_item = null;
38
39 public function __construct() {
40 $this->namespace = 'lp/v1';
41 $this->rest_base = 'users';
42 parent::__construct();
43 }
44
45 /**
46 * Register rest routes.
47 */
48 public function register_routes() {
49 $this->routes = array(
50 'start-quiz' => array(
51 array(
52 'methods' => WP_REST_Server::EDITABLE,
53 'callback' => array( $this, 'start_quiz' ),
54 // 'permission_callback' => array( $this, 'check_admin_permission' ),
55 'permission_callback' => '__return_true',
56 'args' => $this->get_item_endpoint_args(),
57 ),
58 ),
59 'submit-quiz' => array(
60 array(
61 'methods' => WP_REST_Server::EDITABLE,
62 'callback' => array( $this, 'submit_quiz' ),
63 'permission_callback' => '__return_true',
64 'args' => $this->get_item_endpoint_args(),
65 ),
66 ),
67 'check-answer' => array(
68 array(
69 'methods' => WP_REST_Server::EDITABLE,
70 'callback' => array( $this, 'check_answer' ),
71 // 'permission_callback' => array( $this, 'check_admin_permission' ),
72 'permission_callback' => '__return_true',
73 'args' => $this->get_item_endpoint_args(),
74 ),
75 ),
76 );
77
78 parent::register_routes();
79 }
80
81 /**
82 * Get args for user item endpoints.
83 *
84 * @return array
85 */
86 public function get_item_endpoint_args() {
87 return array(
88 'item_id' => array(
89 'description' => __( 'The ID of the course item object.', 'learnpress' ),
90 'type' => 'int',
91 'validate_callback' => array( $this, 'validate_arg' ),
92 'required' => true,
93 ),
94 'course_id' => array(
95 'description' => __( 'The ID of the course object.', 'learnpress' ),
96 'type' => 'int',
97 'validate_callback' => array( $this, 'validate_arg' ),
98 'required' => true,
99 ),
100 );
101 }
102
103 /**
104 * Validation callback to verify rest args.
105 *
106 * @param mixed $value
107 * @param WP_REST_Request $request
108 * @param string $param
109 *
110 * @return bool|WP_Error
111 */
112 public function validate_arg( $value, $request, $param ) {
113 $attributes = $request->get_attributes();
114
115 if ( ! isset( $attributes['args'][ $param ] ) ) {
116 return new WP_Error( 'rest_invalid_param', sprintf( __( '%s was not registered as a request argument.', 'learnpress' ), $param ), array( 'status' => 400 ) );
117 }
118
119 return true;
120 }
121
122 public function check_admin_permission() {
123 return LP_Abstract_API::check_admin_permission();
124 }
125
126 /**
127 * User starts a quiz.
128 *
129 * @param WP_REST_Request $request
130 *
131 * @editor tungnx
132 * @version 1.0.3
133 * @sicne 4.0.0
134 * @return WP_REST_Response
135 */
136 public function start_quiz( WP_REST_Request $request ): WP_REST_Response {
137 $user_id = get_current_user_id();
138 $item_id = $request['item_id'] ?? 0;
139 $course_id = $request['course_id'] ?? 0;
140 $results = array(
141 'question_ids' => array(),
142 'questions' => array(),
143 'total_time' => 0,
144 );
145 $response = array(
146 'status' => 'error',
147 'message' => '',
148 );
149
150 try {
151 $user = learn_press_get_user( $user_id );
152 $course = learn_press_get_course( $course_id );
153 $quiz = learn_press_get_quiz( $item_id );
154
155 $courseModel = CourseModel::find( $course_id, true );
156 if ( ! $courseModel ) {
157 throw new Exception( 'The course is invalid', 'learnrpess' );
158 }
159
160 $quizPostModel = $courseModel->get_item_model( $item_id, LP_QUIZ_CPT );
161 if ( ! $quizPostModel ) {
162 throw new Exception( 'The quiz is invalid', 'learnrpess' );
163 }
164
165 $quiz->set_course( $course );
166
167 do_action( 'learn-press/user/before/start-quiz', $item_id, $course_id, $user_id );
168
169 $link = LP_Helper::get_link_no_cache( $courseModel->get_item_link( $item_id, LP_QUIZ_CPT ) );
170
171 // For no required enroll course (no need login)
172 if ( $user->is_guest() && $course->is_no_required_enroll() ) {
173 $no_required_enroll = new LP_Course_No_Required_Enroll( $course );
174 $response = $no_required_enroll->guest_start_quiz( $quiz );
175 $response['redirect_url'] = $link;
176
177 return rest_ensure_response( $response );
178 }
179
180 /**
181 * Require enroll course
182 *
183 * @var UserQuizModel $user_quiz
184 */
185 $retaken_count = 0;
186 $attempts = [];
187 $filter_user_quiz = new LP_User_Items_Filter();
188 $filter_user_quiz->user_id = $user_id;
189 $filter_user_quiz->item_id = $item_id;
190 $filter_user_quiz->ref_id = $course_id;
191 $user_quiz_exists = UserQuizModel::get_user_item_model_from_db( $filter_user_quiz );
192 if ( $user_quiz_exists instanceof UserQuizModel
193 && $user_quiz_exists->status === LP_ITEM_COMPLETED ) {
194 $user_quiz = $user_quiz_exists;
195 $user_quiz->retake();
196 $results['answered'] = []; // Reset answered for js
197 $retaken_count = $user_quiz->get_retaken_count();
198 $attempts = $user_quiz->get_attempts();
199 } else { // Create new user quiz and insert to database.
200 $user_quiz_new = new UserQuizModel();
201 $user_quiz_new->user_id = $user_id;
202 $user_quiz_new->item_id = $item_id;
203 $user_quiz_new->ref_id = $course_id;
204 $user_quiz_new->start_quiz();
205 $user_quiz = $user_quiz_new;
206 }
207
208 $user_item_id = $user_quiz->get_user_item_id();
209
210 /**
211 * Clear cache result quiz
212 * Cache set on @see LP_User_Item_Quiz::get_results
213 */
214 $lp_quiz_cache = LP_Quiz_Cache::instance();
215 $key_cache = sprintf( '%d/user/%d/course/%d', $item_id, $user_id, $course_id );
216 $lp_quiz_cache->clear( $key_cache );
217 // End
218
219 $show_check = $quiz->get_instant_check();
220 $duration = $quiz->get_duration();
221 $show_correct_review = $quiz->get_show_correct_review();
222 $question_ids = $quiz->get_question_ids();
223 $status = $user_quiz->get_status();
224 $time_remaining = $user_quiz->get_time_remaining();
225
226 $questions = learn_press_rest_prepare_user_questions(
227 $question_ids,
228 array(
229 'instant_check' => $show_check,
230 //'quiz_status' => $status,
231 //'checked_questions' => $checked_questions,
232 //'hinted_questions' => $hinted_questions,
233 'answered' => [],
234 'show_correct_review' => $show_correct_review,
235 )
236 );
237
238 $results['question_ids'] = $question_ids;
239 $results['questions'] = $questions;
240 $results['total_time'] = $time_remaining;
241 $results['duration'] = $duration ? $duration->get() : false;
242 $results['status'] = $status; // Must be started
243 $results['retaken'] = $retaken_count;
244 $results['attempts'] = $attempts;
245 $results['user_item_id'] = $user_item_id;
246 $response['status'] = 'success';
247 $response['results'] = $results;
248 $response['redirect_url'] = $link;
249 } catch ( Throwable $e ) {
250 $response['message'] = $e->getMessage();
251 }
252
253 return rest_ensure_response( $response );
254 }
255
256 /**
257 * Submit quiz answer
258 *
259 * @param WP_REST_Request $request
260 *
261 * @return WP_Error|WP_HTTP_Response|WP_REST_Response
262 * @editor tungnx
263 * @modify 4.1.4.1
264 * @version 1.0.3
265 */
266 public function submit_quiz( WP_REST_Request $request ) {
267 //$response = new LP_REST_Response();
268 $response = array(
269 'status' => 'error',
270 'message' => '',
271 );
272
273 try {
274 $user_id = get_current_user_id();
275 $item_id = $request['item_id'] ?? 0;
276 $course_id = $request['course_id'] ?? 0;
277 $answered = $request['answered'] ?? [];
278 $time_spend = $request['time_spend'] ?? 0;
279 $user = learn_press_get_user( $user_id );
280 $course = learn_press_get_course( $course_id );
281
282 $courseModel = CourseModel::find( $course_id, true );
283 if ( ! $courseModel ) {
284 throw new Exception( 'The course is invalid', 'learnrpess' );
285 }
286
287 $quizPostModel = $courseModel->get_item_model( $item_id, LP_QUIZ_CPT );
288 if ( ! $quizPostModel ) {
289 throw new Exception( 'The quiz is invalid', 'learnrpess' );
290 }
291
292 // Use for Review Quiz.
293 $quiz = learn_press_get_quiz( $item_id );
294 if ( ! $quiz ) {
295 throw new Exception( __( 'The quiz is invalid!', 'learnpress' ) );
296 }
297 $quiz->set_course( $course );
298
299 // Course is no required enroll (no need login)
300 if ( $course->is_no_required_enroll() ) {
301 $no_required_enroll = new LP_Course_No_Required_Enroll( $course );
302
303 $result = $no_required_enroll->get_result_quiz( $quiz, $answered );
304
305 // Set time spent
306 $interval = new LP_Duration( $time_spend );
307 $interval = $interval->to_timer();
308 $result['time_spend'] = $interval;
309 // End
310
311 $result['status'] = LP_ITEM_COMPLETED;
312 //$result['answered'] = $result['questions'];
313 $result['attempts'] = [];
314 $result['results'] = $result;
315 $response['status'] = 'success';
316 $response['results'] = $result;
317
318 return rest_ensure_response( $response );
319 }
320
321 $user_course = $user->get_course_data( $course_id );
322
323 // Course required enroll
324 if ( ! $user_course ) {
325 throw new Exception( 'User not enrolled course!' );
326 }
327
328 /**
329 * @var LP_User_Item_Quiz $user_quiz
330 */
331 $user_quiz = $user_course->get_item( $item_id );
332 if ( ! $user_quiz ) {
333 throw new Exception();
334 }
335
336 // For case save result when check instant answer
337 $result_instant_check = LP_User_Items_Result_DB::instance()->get_result( $user_quiz->get_user_item_id() );
338 if ( $result_instant_check ) {
339 foreach ( $result_instant_check['questions'] as $question_answer_id => $question_answer ) {
340 if ( ! empty( $question_answer['answered'] ) ) {
341 $answered[ $question_answer_id ] = $question_answer['answered'];
342 }
343 }
344 }
345
346 // Set end time.
347 $start_time = $user_quiz->get_start_time()->getTimestamp();
348 $user_quiz->set_end_time( $start_time + $time_spend );
349
350 // Calculate quiz result and save.
351 $result = $user_quiz->calculate_quiz_result( $answered );
352 // Save
353 LP_User_Items_Result_DB::instance()->update( $user_quiz->get_user_item_id(), wp_json_encode( $result ) );
354
355 if ( $result['pass'] ) {
356 $user_quiz->set_graduation( LP_COURSE_GRADUATION_PASSED );
357 } else {
358 $user_quiz->set_graduation( LP_COURSE_GRADUATION_FAILED );
359 }
360
361 $user_quiz->complete();
362
363 do_action( 'learn-press/user/quiz-finished', $item_id, $course_id, $user_id, $user_quiz );
364
365 $result['status'] = $user_quiz->get_status(); // Must be completed
366 $result['attempts'] = $user_quiz->get_attempts();
367 $result['answered'] = $result['questions'];
368 $result['results'] = $result;
369 $response['status'] = 'success';
370 $response['results'] = $result;
371 } catch ( Throwable $e ) {
372 $response['message'] = $e->getMessage();
373 }
374
375 return rest_ensure_response( $response );
376 }
377
378 /**
379 * Check answer
380 *
381 * @param WP_REST_Request $request
382 * @return WP_Error|WP_HTTP_Response|WP_REST_Response
383 * @since 4.1.4.1
384 * @version 1.0.2
385 */
386 public function check_answer( WP_REST_Request $request ) {
387 $response = array(
388 'status' => 'error',
389 'message' => '',
390 );
391
392 try {
393 $question_id = $request['question_id'] ?? 0;
394 $answered = $request['answered'] ?? '';
395 $course_id = $request['course_id'] ?? 0;
396 $quiz_id = $request['item_id'] ?? 0;
397 $course = learn_press_get_course( $course_id );
398 $checked = [];
399
400 $courseModel = CourseModel::find( $course_id, true );
401 if ( ! $courseModel ) {
402 throw new Exception( 'The course is invalid', 'learnrpess' );
403 }
404
405 $quizPostModel = $courseModel->get_item_model( $quiz_id, LP_QUIZ_CPT );
406 if ( ! $quizPostModel ) {
407 throw new Exception( 'The quiz is invalid', 'learnrpess' );
408 }
409
410 // Check question has in quiz
411 $quizQuestionModel = QuizQuestionModel::find( $quiz_id, $question_id );
412 if ( ! $quizQuestionModel ) {
413 throw new Exception( 'The quiz question is invalid', 'learnrpess' );
414 }
415
416 $questionModel = QuestionPostModel::find( $question_id, true );
417 if ( ! $questionModel ) {
418 throw new Exception( 'The question is invalid', 'learnrpess' );
419 }
420
421 // For case user not login
422 if ( $course->is_no_required_enroll() ) {
423 $no_required_enroll = new LP_Course_No_Required_Enroll( $course );
424 $checked = $no_required_enroll->guest_check_question( $question_id, $answered );
425 } else { // For case user logged in
426 $user = learn_press_get_current_user();
427 if ( $user->is_guest() ) {
428 throw new Exception( 'The user is invalid', 'learnrpess' );
429 }
430
431 $user_course = $user->get_course_data( $course_id );
432 if ( ! $user_course ) {
433 throw new Exception( 'User\'s course no data!', 'learnrpess' );
434 }
435
436 $user_quiz = $user_course->get_item( $quiz_id );
437 if ( ! $user_quiz ) {
438 throw new Exception( 'User\'s quiz no data!', 'learnrpess' );
439 }
440
441 $checked = $user_quiz->instant_check_question( $question_id, $answered );
442 }
443
444 $question = learn_press_get_question( $question_id );
445 $response['explanation'] = $question->get_explanation();
446 $response['options'] = learn_press_get_question_options_for_js( $question, array( 'answer' => $answered ) );
447 $response['result'] = $checked;
448 $response['status'] = 'success';
449 } catch ( Throwable $e ) {
450 $response['message'] = $e->getMessage();
451 }
452
453 return rest_ensure_response( $response );
454 }
455 }
456