PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.5
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.5
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 / jwt / rest-api / version1 / class-lp-rest-lessons-v1-controller.php

class-lp-rest-lessons-v1-controller.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.5, at inc/jwt/rest-api/version1/class-lp-rest-lessons-v1-controller.php

636 lines 17.4 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\LessonPostModel;
5 use LearnPress\Models\UserItems\UserLessonModel;
6 use LearnPress\Models\UserModel;
7
8 class LP_Jwt_Lessons_V1_Controller extends LP_REST_Jwt_Posts_Controller {
9 protected $namespace = 'learnpress/v1';
10
11 protected $rest_base = 'lessons';
12
13 protected $post_type = LP_LESSON_CPT;
14
15 protected $hierarchical = true;
16
17 public function register_routes() {
18 register_rest_route(
19 $this->namespace,
20 '/' . $this->rest_base,
21 array(
22 array(
23 'methods' => WP_REST_Server::READABLE,
24 'callback' => array( $this, 'get_items' ),
25 'permission_callback' => array( $this, 'get_items_permissions_check' ),
26 'args' => $this->get_collection_params(),
27 ),
28 'schema' => array( $this, 'get_public_item_schema' ),
29 )
30 );
31
32 register_rest_route(
33 $this->namespace,
34 '/' . $this->rest_base . '/(?P<id>[\d]+)',
35 array(
36 'args' => array(
37 'id' => array(
38 'description' => esc_html__( 'A unique identifier for the resource.', 'learnpress' ),
39 'type' => 'integer',
40 ),
41 ),
42 array(
43 'methods' => WP_REST_Server::READABLE,
44 'callback' => array( $this, 'get_item' ),
45 'permission_callback' => array( $this, 'get_item_permissions_check' ),
46 'args' => array(
47 'context' => $this->get_context_param(
48 array(
49 'default' => 'view',
50 )
51 ),
52 ),
53 ),
54 'schema' => array( $this, 'get_public_item_schema' ),
55 )
56 );
57
58 register_rest_route(
59 $this->namespace,
60 '/' . $this->rest_base . '/finish',
61 array(
62 'args' => array(
63 'id' => array(
64 'description' => esc_html__( 'A unique identifier for the resource.', 'learnpress' ),
65 'type' => 'integer',
66 ),
67 ),
68 array(
69 'methods' => WP_REST_Server::CREATABLE,
70 'callback' => array( $this, 'finish_lesson' ),
71 'permission_callback' => array( $this, 'get_item_permissions_check' ),
72 'args' => array(
73 'context' => $this->get_context_param(
74 array(
75 'default' => 'edit',
76 )
77 ),
78 ),
79 ),
80 )
81 );
82 }
83
84 /**
85 * Checks if a course can be read.
86 *
87 * Correctly handles courses with the inherit status.
88 *
89 * @author Nhamdv
90 *
91 * @return bool Whether the post can be read.
92 * */
93 public function check_read_permission( $post_id ) {
94 if ( empty( absint( $post_id ) ) ) {
95 return false;
96 }
97
98 $post = get_post( $post_id );
99
100 if ( ! $post ) {
101 return false;
102 }
103
104 if ( lp_rest_check_post_permissions( $this->post_type, 'read', $post_id ) ) {
105 return true;
106 }
107
108 $post_status_obj = get_post_status_object( $post->post_status );
109 if ( ! $post_status_obj || ! $post_status_obj->public ) {
110 return false;
111 }
112
113 $user_id = get_current_user_id();
114
115 if ( ! $user_id ) {
116 return false;
117 }
118
119 $user = learn_press_get_user( $user_id );
120
121 // Get course ID by lesson ID assigned.
122 $course_id = $this->get_course_by_item_id( $post_id );
123
124 if ( empty( $course_id ) ) {
125 return false;
126 }
127
128 $can_view_content_course = $user->can_view_content_course( $course_id );
129
130 $can_view_item = $user->can_view_item( $post_id, $can_view_content_course );
131
132 if ( ! $can_view_item->flag ) {
133 return false;
134 }
135
136 // Can we read the parent if we're inheriting?
137 if ( 'inherit' === $post->post_status && $post->post_parent > 0 ) {
138 $parent = get_post( $post->post_parent );
139
140 if ( $parent ) {
141 return $this->check_read_permission( $parent );
142 }
143 }
144
145 return true;
146 }
147
148 protected function get_object( $lesson = 0 ) {
149 global $post;
150
151 if ( false === $lesson && isset( $post, $post->ID ) && LP_LESSON_CPT === get_post_type( $post->ID ) ) {
152 $id = absint( $post->ID );
153 } elseif ( is_numeric( $lesson ) ) {
154 $id = $lesson;
155 } elseif ( $lesson instanceof LP_Lesson ) {
156 $id = $lesson->get_id();
157 } elseif ( ! empty( $lesson->ID ) ) {
158 $id = $lesson->ID;
159 }
160
161 return LP_Course_Item::get_item( $id );
162 }
163
164 /**
165 * Get course ID by lesson ID assigned.
166 *
167 * @param [type] $item_id
168 * @return void
169 */
170 protected function get_course_by_item_id( $item_id ) {
171 static $output;
172
173 global $wpdb;
174
175 if ( empty( $item_id ) ) {
176 return false;
177 }
178
179 if ( ! isset( $output ) ) {
180 $output = $wpdb->get_var(
181 $wpdb->prepare(
182 "SELECT c.ID FROM {$wpdb->posts} c
183 INNER JOIN {$wpdb->learnpress_sections} s ON c.ID = s.section_course_id
184 INNER JOIN {$wpdb->learnpress_section_items} si ON si.section_id = s.section_id
185 WHERE si.item_id = %d ORDER BY si.section_id DESC LIMIT 1
186 ",
187 $item_id
188 )
189 );
190 }
191
192 if ( $output ) {
193 return absint( $output );
194 }
195
196 return false;
197 }
198
199 public function finish_lesson( $request ) {
200 $response = new LP_REST_Response();
201
202 try {
203 $id = isset( $request['id'] ) ? absint( $request['id'] ) : '';
204 if ( empty( $id ) ) {
205 throw new Exception( esc_html__( 'Error: No lesson available!.', 'learnpress' ) );
206 }
207
208 $lessonModel = LessonPostModel::find( $id, true );
209 if ( ! $lessonModel ) {
210 throw new Exception( esc_html__( 'Error: Lesson is invalid!', 'learnpress' ) );
211 }
212
213 $course_id = $this->get_course_by_item_id( $id );
214 if ( empty( $course_id ) ) {
215 throw new Exception( esc_html__( 'Error: This lesson is not assigned in the Course.', 'learnpress' ) );
216 }
217
218 $courseModel = CourseModel::find( $course_id, true );
219 $userModel = UserModel::find( get_current_user_id(), true );
220
221 if ( empty( $courseModel ) || empty( $userModel ) ) {
222 throw new Exception( esc_html__( 'Error: No Course or User available.', 'learnpress' ) );
223 }
224
225 $userLessonModel = UserLessonModel::find_user_item(
226 get_current_user_id(),
227 $id,
228 $lessonModel->post_type,
229 $course_id,
230 LP_COURSE_CPT,
231 true
232 );
233 if ( ! $userLessonModel instanceof UserLessonModel ) {
234 throw new Exception( __( 'You have not started lesson', 'learnpress' ) );
235 }
236
237 $userLessonModel->set_complete();
238 $response->status = 'success';
239 $response->message = esc_html__( 'Congrats! You have completed the lesson successfully', 'learnpress' );
240 } catch ( Throwable $th ) {
241 $response->message = $th->getMessage();
242 }
243
244 return rest_ensure_response( $response );
245 }
246
247 public function prepare_object_for_response( $object, $request ) {
248 $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
249 $data = $this->get_lesson_data( $object, $context, $request );
250
251 $response = rest_ensure_response( $data );
252
253 return apply_filters( "lp_jwt_rest_prepare_{$this->post_type}_object", $response, $object, $request );
254 }
255
256 protected function get_lesson_data( $object, $context = 'view' ) {
257 $request = func_num_args() >= 2 ? func_get_arg( 2 ) : new WP_REST_Request( '', '', array( 'context' => $context ) );
258 $fields = $this->get_fields_for_response( $request );
259
260 $id = ! empty( $object->ID ) ? $object->ID : $object->get_id();
261 $post = get_post( $id );
262 $data = array();
263
264 $assigned = $this->get_assigned( $id );
265
266 $course_id = 0;
267 if ( ! empty( $assigned ) && method_exists( $object, 'set_course' ) ) {
268 $course_id = $assigned['course']['id'];
269 $object->set_course( $course_id );
270 }
271
272 $userLessonModel = UserLessonModel::find_user_item(
273 get_current_user_id(),
274 $id,
275 LP_LESSON_CPT,
276 $course_id,
277 LP_COURSE_CPT,
278 true
279 );
280 $end_time = '';
281
282 if ( $userLessonModel instanceof UserLessonModel ) {
283 $end_time = $userLessonModel->get_end_time();
284 }
285
286 foreach ( $fields as $field ) {
287 switch ( $field ) {
288 case 'id':
289 $data['id'] = $id;
290 break;
291 case 'name':
292 $data['name'] = $post->post_title;
293 break;
294 case 'slug':
295 $data['slug'] = $post->post_name;
296 break;
297 case 'permalink':
298 $data['permalink'] = $object->get_permalink();
299 break;
300 case 'date_created':
301 $data['date_created'] = lp_jwt_prepare_date_response( $post->post_date_gmt, $post->post_date );
302 break;
303 case 'date_created_gmt':
304 $data['date_created_gmt'] = lp_jwt_prepare_date_response( $post->post_date_gmt );
305 break;
306 case 'date_modified':
307 $data['date_modified'] = lp_jwt_prepare_date_response( $post->post_modified_gmt, $post->post_modified );
308 break;
309 case 'date_modified_gmt':
310 $data['date_modified_gmt'] = lp_jwt_prepare_date_response( $post->post_modified_gmt );
311 break;
312 case 'status':
313 $data['status'] = $post->post_status;
314 break;
315 case 'content':
316 $data['content'] = 'view' === $context ? apply_filters( 'the_content', $post->post_content ) : $post->post_content;
317 break;
318 case 'excerpt':
319 $data['excerpt'] = $post->post_excerpt;
320 break;
321 case 'can_finish_course':
322 $data['can_finish_course'] = $this->check_can_finish_course( $id );
323 break;
324 case 'duration':
325 $data['duration'] = learn_press_get_post_translated_duration( $id, esc_html__( 'Lifetime', 'learnpress' ) );
326 break;
327 case 'assigned':
328 $data['assigned'] = $assigned;
329 break;
330 case 'results':
331 $data['results'] = $this->get_lesson_results( $object );
332 break;
333 case 'video_intro':
334 $data['video_intro'] = $this->get_video_intro( $id );
335 break;
336 }
337 }
338
339 $data['end_time'] = $end_time;
340 $data['meta_data'] = $this->get_course_meta( $id );
341
342 return $data;
343 }
344
345 public function get_video_intro( $id ) {
346 $video_intro = get_post_meta( $id, '_lp_lesson_video_intro', true );
347
348 if ( ! $video_intro ) {
349 return '';
350 }
351
352 if ( wp_oembed_get( $video_intro ) ) {
353 return wp_oembed_get( $video_intro );
354 }
355
356 return do_shortcode( $video_intro );
357 }
358
359 public function check_can_finish_course( $id ) {
360 $user = learn_press_get_current_user();
361
362 if ( ! $user || ! $id ) {
363 return false;
364 }
365
366 $course_id = $this->get_course_by_item_id( $id );
367
368 if ( empty( $course_id ) ) {
369 return false;
370 }
371
372 $course = learn_press_get_course( $course_id );
373
374 if ( $user && $course ) {
375 $check = $user->can_show_finish_course_btn( $course );
376
377 if ( $check['status'] === 'success' ) {
378 return true;
379 }
380
381 return false;
382 }
383
384 return false;
385 }
386
387 public function get_lesson_results( $lesson ) {
388 global $wpdb;
389
390 $output = array();
391
392 $user_id = learn_press_get_current_user_id();
393
394 if ( ! $user_id || ! $lesson ) {
395 return $output;
396 }
397
398 $id = ! empty( $lesson->ID ) ? $lesson->ID : $lesson->get_id();
399
400 $course_id = $this->get_course_by_item_id( $id );
401
402 if ( empty( $course_id ) ) {
403 return $output;
404 }
405
406 $query = $wpdb->prepare( "SELECT status FROM {$wpdb->prefix}learnpress_user_items WHERE user_id=%d AND item_id=%d AND ref_id=%d", $user_id, $id, $course_id );
407
408 $status = $wpdb->get_var( $query );
409
410 $output['status'] = ! empty( $status ) ? $status : '';
411
412 return $output;
413 }
414
415 public function get_course_meta( $id ) {
416 if ( ! class_exists( 'LP_Meta_Box_Lesson' ) ) {
417 include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/lesson/settings.php';
418 }
419
420 $metabox = new LP_Meta_Box_Lesson();
421
422 $output = array();
423 foreach ( $metabox->metabox( $id ) as $meta_key => $object ) {
424 if ( is_a( $object, 'LP_Meta_Box_Field' ) ) {
425 $object->id = $meta_key;
426 $output[ $meta_key ] = $object->meta_value( $id );
427 }
428 }
429
430 return $output;
431 }
432
433 public function get_assigned( $id ) {
434 $courses = learn_press_get_item_courses( $id );
435
436 $output = array();
437
438 if ( $courses ) {
439 foreach ( $courses as $course ) {
440 $output['course'] = array(
441 'id' => $course->ID,
442 'title' => $course->post_title,
443 'slug' => $course->post_name,
444 'content' => $course->post_content,
445 'author' => $course->post_author,
446 );
447 }
448 }
449
450 return $output;
451 }
452
453 public function get_item_schema() {
454 $schema = array(
455 '$schema' => 'http://json-schema.org/draft-04/schema#',
456 'title' => $this->post_type,
457 'type' => 'object',
458 'properties' => array(
459 'id' => array(
460 'description' => __( 'A unique identifier for the resource.', 'learnpress' ),
461 'type' => 'integer',
462 'context' => array( 'view', 'edit' ),
463 'readonly' => true,
464 ),
465 'name' => array(
466 'description' => __( 'Course name.', 'learnpress' ),
467 'type' => 'string',
468 'context' => array( 'view', 'edit' ),
469 ),
470 'slug' => array(
471 'description' => __( 'Course slug.', 'learnpress' ),
472 'type' => 'string',
473 'context' => array( 'view', 'edit' ),
474 ),
475 'permalink' => array(
476 'description' => __( 'Course URL.', 'learnpress' ),
477 'type' => 'string',
478 'format' => 'uri',
479 'context' => array( 'view', 'edit' ),
480 'readonly' => true,
481 ),
482 'date_created' => array(
483 'description' => __( "The date the Course was created, in the site's timezone.", 'learnpress' ),
484 'type' => 'date-time',
485 'context' => array( 'view', 'edit' ),
486 'readonly' => true,
487 ),
488 'date_created_gmt' => array(
489 'description' => __( 'The date the Course was created, as GMT.', 'learnpress' ),
490 'type' => 'date-time',
491 'context' => array( 'view', 'edit' ),
492 'readonly' => true,
493 ),
494 'date_modified' => array(
495 'description' => __( "The date the Course was last modified, in the site's timezone.", 'learnpress' ),
496 'type' => 'date-time',
497 'context' => array( 'view', 'edit' ),
498 'readonly' => true,
499 ),
500 'date_modified_gmt' => array(
501 'description' => __( 'The date the Course was last modified, as GMT.', 'learnpress' ),
502 'type' => 'date-time',
503 'context' => array( 'view', 'edit' ),
504 'readonly' => true,
505 ),
506 'status' => array(
507 'description' => __( 'Course status (post status).', 'learnpress' ),
508 'type' => 'string',
509 'default' => 'publish',
510 'enum' => array_merge( array_keys( get_post_statuses() ), array( 'future' ) ),
511 'context' => array( 'view', 'edit' ),
512 ),
513 'content' => array(
514 'description' => __( 'Course content.', 'learnpress' ),
515 'type' => 'string',
516 'context' => array( 'view', 'edit' ),
517 ),
518 'excerpt' => array(
519 'description' => __( 'Retrieves the course excerpt..', 'learnpress' ),
520 'type' => 'string',
521 'context' => array( 'view', 'edit' ),
522 ),
523 'can_finish_course' => array(
524 'description' => __( 'Can finish the course', 'learnpress' ),
525 'type' => 'boolean',
526 'context' => array( 'view' ),
527 'readonly' => true,
528 ),
529 'duration' => array(
530 'description' => __( 'Duration', 'learnpress' ),
531 'type' => 'string',
532 'context' => array( 'view' ),
533 ),
534 'assigned' => array(
535 'description' => __( 'Assigned.', 'learnpress' ),
536 'type' => 'array',
537 'context' => array( 'view', 'edit' ),
538 'items' => array(
539 'id' => array(
540 'description' => __( 'Item ID.', 'learnpress' ),
541 'type' => 'integer',
542 'context' => array( 'view', 'edit' ),
543 ),
544 'title' => array(
545 'description' => __( 'Title.', 'learnpress' ),
546 'type' => 'string',
547 'context' => array( 'view', 'edit' ),
548 ),
549 'slug' => array(
550 'description' => __( 'Item slug.', 'learnpress' ),
551 'type' => 'string',
552 'context' => array( 'view', 'edit' ),
553 ),
554 'content' => array(
555 'description' => __( 'Item Content.', 'learnpress' ),
556 'type' => 'string',
557 'context' => array( 'view', 'edit' ),
558 ),
559 'author' => array(
560 'description' => __( 'Item Author.', 'learnpress' ),
561 'type' => 'integer',
562 'context' => array( 'view', 'edit' ),
563 ),
564 ),
565 ),
566 'results' => array(
567 'description' => __( 'Retrieves the Lesson result..', 'learnpress' ),
568 'type' => 'array',
569 'context' => array( 'view', 'edit' ),
570 'items' => array(
571 'status' => array(
572 'description' => __( 'Status.', 'learnpress' ),
573 'type' => 'string',
574 'context' => array( 'view', 'edit' ),
575 ),
576 ),
577 ),
578 'video_intro' => array(
579 'description' => __( 'Video intro.', 'learnpress' ),
580 'type' => 'string',
581 'context' => array( 'view', 'edit' ),
582 ),
583 ),
584 );
585
586 return $this->add_additional_fields_schema( $schema );
587 }
588
589 /**
590 * API get item lesson
591 * @since 4.1.6.9.1
592 *
593 * @param $request
594 *
595 * @return WP_Error|WP_HTTP_Response|WP_REST_Response
596 * @throws Exception
597 */
598 public function get_item( $request ) {
599 $object = $this->get_object( (int) $request['id'] );
600
601 if ( ! $object || 0 === $object->get_id() ) {
602 return new WP_Error( "lp_rest_{$this->post_type}_invalid_id", esc_html__( 'Invalid ID.', 'learnpress' ), array( 'status' => 404 ) );
603 }
604
605 $item_id = (int) $request['id'];
606
607 $course_id = $this->get_course_by_item_id( $item_id );
608 $course = learn_press_get_course( $course_id );
609 if ( $course && is_user_logged_in() ) {
610 $user = learn_press_get_current_user();
611 $course_data = $user->get_course_data( $course_id );
612
613 if ( $course_data && $course_data->is_enrolled() ) {
614 $item = $course_data->get_item( $item_id );
615
616 if ( ! $item ) {
617 $item = LP_User_Item::get_item_object( $item_id );
618
619 $item->set_ref_id( $course_id );
620 $item->set_parent_id( $course_data->get_user_item_id() );
621 $item->update();
622 }
623 }
624 }
625
626 $data = $this->prepare_object_for_response( $object, $request );
627 $response = rest_ensure_response( $data );
628
629 if ( $this->public ) {
630 $response->link_header( 'alternate', $this->get_permalink( $object ), array( 'type' => 'text/html' ) );
631 }
632
633 return $response;
634 }
635 }
636