PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 4.0.0
Tutor LMS – eLearning and online course solution v4.0.0
4.0.0 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 / Ajax.php
tutor / classes Last commit date
Addons.php 1 day ago Admin.php 1 day ago Ajax.php 1 day ago Announcements.php 1 day ago Assets.php 1 day ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 1 day ago Container.php 11 months ago Course.php 1 day ago Course_Embed.php 3 years ago Course_Filter.php 1 day ago Course_List.php 1 day ago Course_Settings_Tabs.php 1 day ago Course_Widget.php 1 year ago Custom_Validation.php 1 day ago Dashboard.php 1 day ago Earnings.php 9 months ago FormHandler.php 1 day ago Frontend.php 1 day ago Gutenberg.php 1 year ago Icon.php 1 day ago Input.php 1 day ago Instructor.php 1 day ago Instructors_List.php 1 day ago Lesson.php 1 day ago Options_V2.php 1 day ago Permalink.php 1 day ago Post_types.php 2 days ago Private_Course_Access.php 1 day ago Q_And_A.php 1 day ago Question_Answers_List.php 11 months ago Quiz.php 1 day ago QuizBuilder.php 1 day ago Quiz_Attempts_List.php 1 day ago RestAPI.php 2 years ago Reviews.php 1 day ago Rewrite_Rules.php 2 years ago SampleCourse.php 1 day ago Shortcode.php 1 day ago Singleton.php 1 year ago Student.php 1 day ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 1 day ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 4 weeks ago Tutor.php 1 day ago TutorEDD.php 1 day ago Tutor_Base.php 2 years ago Tutor_Setup.php 1 day ago Upgrader.php 1 day ago User.php 1 day ago UserPreference.php 1 day ago Utils.php 1 day ago Video_Stream.php 3 years ago WhatsNew.php 10 months ago Withdraw.php 1 day ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 1 day ago
Ajax.php
643 lines
1 <?php
2 /**
3 * Handle Ajax Request
4 *
5 * @package Tutor
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 namespace TUTOR;
12
13 defined( 'ABSPATH' ) || exit;
14
15 use Tutor\GDPR\Controllers\LegalConsent;
16 use Tutor\Helpers\HttpHelper;
17 use Tutor\Models\LessonModel;
18 use Tutor\Traits\JsonResponse;
19
20 /**
21 * Ajax Class
22 *
23 * @since 1.0.0
24 */
25 class Ajax {
26 use JsonResponse;
27
28 const LOGIN_ERRORS_TRANSIENT_KEY = 'tutor_login_errors';
29
30 /**
31 * Constructor
32 *
33 * @since 1.0.0
34 * @since 2.6.2 added allow_hooks param.
35 *
36 * @param bool $allow_hooks default value true.
37 *
38 * @return void
39 */
40 public function __construct( $allow_hooks = true ) {
41 if ( $allow_hooks ) {
42 add_action( 'wp_ajax_sync_video_playback', array( $this, 'sync_video_playback' ) );
43 add_action( 'wp_ajax_tutor_place_rating', array( $this, 'tutor_place_rating' ) );
44 add_action( 'wp_ajax_delete_tutor_review', array( $this, 'delete_tutor_review' ) );
45
46 add_action( 'wp_ajax_tutor_course_add_to_wishlist', array( $this, 'tutor_course_add_to_wishlist' ) );
47 add_action( 'wp_ajax_nopriv_tutor_course_add_to_wishlist', array( $this, 'tutor_course_add_to_wishlist' ) );
48
49 /**
50 * Ajax login
51 *
52 * @since v.1.6.3
53 */
54 add_action( 'tutor_action_tutor_user_login', array( $this, 'process_tutor_login' ) );
55
56 /**
57 * Announcement
58 *
59 * @since v.1.7.9
60 */
61 add_action( 'wp_ajax_tutor_announcement_create', array( $this, 'create_or_update_announcement' ) );
62 add_action( 'wp_ajax_tutor_announcement_delete', array( $this, 'delete_announcement' ) );
63
64 add_action( 'wp_ajax_tutor_youtube_video_duration', array( $this, 'ajax_youtube_video_duration' ) );
65 }
66 }
67
68
69
70 /**
71 * Update video information and data when necessary
72 *
73 * @since 1.0.0
74 *
75 * @return void
76 */
77 public function sync_video_playback() {
78 tutor_utils()->checking_nonce();
79
80 $user_id = get_current_user_id();
81 $post_id = Input::post( 'post_id', 0, Input::TYPE_INT );
82 $duration = Input::post( 'duration' );
83 $current_time = Input::post( 'currentTime' );
84
85 if ( ! tutor_utils()->has_enrolled_content_access( 'lesson', $post_id ) ) {
86 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
87 exit;
88 }
89
90 /**
91 * Update posts attached video
92 */
93 $video = tutor_utils()->get_video( $post_id );
94
95 if ( $duration ) {
96 $video['duration_sec'] = $duration; // Duration in sec.
97 $video['playtime'] = tutor_utils()->playtime_string( $duration );
98 $video['runtime'] = tutor_utils()->playtime_array( $duration );
99 }
100 tutor_utils()->update_video( $post_id, $video );
101
102 /**
103 * Sync Lesson Reading Info by Users
104 */
105
106 $best_watch_time = tutor_utils()->get_lesson_reading_info( $post_id, $user_id, 'video_best_watched_time' );
107 if ( $best_watch_time < $current_time ) {
108 LessonModel::update_lesson_reading_info( $post_id, $user_id, 'video_best_watched_time', $current_time );
109 }
110
111 if ( Input::post( 'is_ended', false, Input::TYPE_BOOL ) ) {
112 LessonModel::mark_lesson_complete( $post_id );
113 LessonModel::update_lesson_reading_info( $post_id, $user_id, 'video_best_watched_time', 0 );
114 }
115 exit();
116 }
117
118 /**
119 * Place rating
120 *
121 * @since 1.0.0
122 * @return void
123 */
124 public function tutor_place_rating() {
125 tutor_utils()->checking_nonce();
126
127 $user_id = get_current_user_id();
128 $course_id = Input::post( 'course_id' );
129 $rating = Input::post( 'tutor_rating_gen_input', 0, Input::TYPE_INT );
130 $review = Input::post( 'review', '', Input::TYPE_TEXTAREA );
131
132 $rating <= 0 ? $rating = 1 : 0;
133 $rating > 5 ? $rating = 5 : 0;
134
135 $this->add_or_update_review( $user_id, $course_id, $rating, $review );
136 }
137
138 /**
139 * Add/Update rating
140 *
141 * @param int $user_id the user id.
142 * @param int $course_id the course id.
143 * @param int $rating rating star number.
144 * @param string $review review description.
145 * @param int $review_id review id needed for api update.
146 *
147 * @return void|string
148 */
149 public function add_or_update_review( $user_id, $course_id, $rating, $review, $review_id = 0 ) {
150 global $wpdb;
151
152 $moderation = tutor_utils()->get_option( 'enable_course_review_moderation', false, true, true );
153 $user = get_userdata( $user_id );
154 $date = date( 'Y-m-d H:i:s', tutor_time() ); //phpcs:ignore
155
156 if ( ! tutor_is_rest() && ! tutor_utils()->has_enrolled_content_access( 'course', $course_id ) ) {
157 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
158 exit;
159 }
160
161 do_action( 'tutor_before_rating_placed' );
162
163 $is_edit = 0 === $review_id ? false : true;
164
165 if ( ! tutor_is_rest() ) {
166 $previous_rating_id = $wpdb->get_var(
167 $wpdb->prepare(
168 "SELECT comment_ID
169 from {$wpdb->comments}
170 WHERE comment_post_ID = %d AND
171 user_id = %d AND
172 comment_type = 'tutor_course_rating'
173 LIMIT 1;",
174 $course_id,
175 $user_id
176 )
177 );
178
179 if ( ! empty( $previous_rating_id ) ) {
180 $review_id = $previous_rating_id;
181 $is_edit = true;
182 }
183 }
184
185 if ( $is_edit ) {
186 $wpdb->update(
187 $wpdb->comments,
188 array(
189 'comment_content' => $review,
190 'comment_approved' => $moderation ? 'hold' : 'approved',
191 'comment_date' => $date,
192 'comment_date_gmt' => get_gmt_from_date( $date ),
193 ),
194 array( 'comment_ID' => $review_id )
195 );
196
197 $rating_info = $wpdb->get_row(
198 $wpdb->prepare(
199 "SELECT * FROM {$wpdb->commentmeta}
200 WHERE comment_id = %d
201 AND meta_key = 'tutor_rating'; ",
202 $review_id
203 )
204 );
205
206 if ( $rating_info ) {
207 $wpdb->update(
208 $wpdb->commentmeta,
209 array( 'meta_value' => $rating ),
210 array(
211 'comment_id' => $review_id,
212 'meta_key' => 'tutor_rating',
213 )
214 );
215 } else {
216 $wpdb->insert(
217 $wpdb->commentmeta,
218 array(
219 'comment_id' => $review_id,
220 'meta_key' => 'tutor_rating',
221 'meta_value' => $rating,
222 )
223 );
224 }
225 } else {
226 $data = array(
227 'comment_post_ID' => esc_sql( $course_id ),
228 'comment_approved' => $moderation ? 'hold' : 'approved',
229 'comment_type' => 'tutor_course_rating',
230 'comment_date' => $date,
231 'comment_date_gmt' => get_gmt_from_date( $date ),
232 'user_id' => $user_id,
233 'comment_author' => $user->user_login,
234 'comment_agent' => 'TutorLMSPlugin',
235 );
236 if ( $review ) {
237 $data['comment_content'] = $review;
238 }
239
240 $wpdb->insert( $wpdb->comments, $data );
241 $comment_id = (int) $wpdb->insert_id;
242 $review_id = $comment_id;
243
244 if ( $comment_id ) {
245 $wpdb->insert(
246 $wpdb->commentmeta,
247 array(
248 'comment_id' => $comment_id,
249 'meta_key' => 'tutor_rating',
250 'meta_value' => $rating,
251 )
252 );
253
254 do_action( 'tutor_after_rating_placed', $comment_id );
255 }
256 }
257
258 if ( ! tutor_is_rest() ) {
259 wp_send_json_success(
260 array(
261 'message' => __( 'Rating placed successfully!', 'tutor' ),
262 'review_id' => $review_id,
263 )
264 );
265 } else {
266 return $is_edit ? 'updated' : 'created';
267 }
268 }
269
270 /**
271 * Delete a review
272 *
273 * @since 1.0.0
274 * @since 2.6.2 added params user_id.
275 * @param int $user_id the user id.
276 * @return void|bool
277 */
278 public function delete_tutor_review( $user_id = 0 ) {
279 if ( ! tutor_is_rest() ) {
280 tutor_utils()->checking_nonce();
281 }
282
283 $review_id = Input::post( 'review_id' );
284
285 if ( ! tutor_utils()->can_user_manage( 'review', $review_id, tutils()->get_user_id( $user_id ) ) ) {
286 wp_send_json_error( array( 'message' => __( 'Permissioned Denied!', 'tutor' ) ) );
287 exit;
288 }
289
290 global $wpdb;
291 $wpdb->delete( $wpdb->commentmeta, array( 'comment_id' => $review_id ) );
292 $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $review_id ) );
293
294 if ( tutor_is_rest() ) {
295 return true;
296 }
297
298 wp_send_json_success();
299 }
300
301 /**
302 * Add course in wishlist
303 *
304 * @since 1.0.0
305 * @return void|string
306 */
307 public function tutor_course_add_to_wishlist() {
308 tutor_utils()->checking_nonce();
309
310 $is_enabled_wishlist = tutor_utils()->get_option( 'enable_wishlist', true );
311 if ( ! $is_enabled_wishlist ) {
312 wp_send_json_error( array( 'message' => __( 'Wishlist option is disabled', 'tutor' ) ) );
313 }
314
315 // Redirect login since only logged in user can add courses to wishlist.
316 if ( ! is_user_logged_in() ) {
317 wp_send_json_error(
318 array(
319 'redirect_to' => wp_login_url( wp_get_referer() ),
320 )
321 );
322 }
323
324 $user_id = get_current_user_id();
325 $course_id = Input::post( 'course_id', 0, Input::TYPE_INT );
326
327 $result = $this->add_or_delete_wishlist( $user_id, $course_id );
328
329 if ( tutor_is_rest() ) {
330 return $result;
331 } elseif ( 'added' === $result ) {
332 wp_send_json_success(
333 array(
334 'status' => 'added',
335 'message' => __( 'Course added to wish list', 'tutor' ),
336 )
337 );
338 } else {
339 wp_send_json_success(
340 array(
341 'status' => 'removed',
342 'message' => __( 'Course removed from wish list', 'tutor' ),
343 )
344 );
345 }
346 }
347
348 /**
349 * Add or Delete wishlist by user_id and course_id
350 *
351 * @since 2.6.2
352 *
353 * @param int $user_id the user id.
354 * @param int $course_id the course_id to add to the wishlist.
355 *
356 * @return string
357 */
358 public function add_or_delete_wishlist( $user_id, $course_id ) {
359 global $wpdb;
360
361 $if_added_to_list = tutor_utils()->is_wishlisted( $course_id, $user_id );
362
363 $result = '';
364
365 if ( $if_added_to_list ) {
366 $wpdb->delete(
367 $wpdb->usermeta,
368 array(
369 'user_id' => $user_id,
370 'meta_key' => '_tutor_course_wishlist',
371 'meta_value' => $course_id,
372 )
373 );
374
375 $result = 'removed';
376 } else {
377 add_user_meta( $user_id, '_tutor_course_wishlist', $course_id );
378
379 $result = 'added';
380 }
381
382 return $result;
383 }
384
385 /**
386 * Process tutor login
387 *
388 * @since 1.6.3
389 * @since 2.1.3 Ajax removed, validation errors stores in session.
390 *
391 * @return void
392 */
393 public function process_tutor_login() {
394 $validation_error = new \WP_Error();
395
396 /**
397 * Separate nonce verification added to show nonce verification
398 * failed message in a proper way.
399 *
400 * @since 2.1.4
401 */
402 if ( ! tutor_utils()->is_nonce_verified( 'post' ) ) {
403 $validation_error->add( 401, __( 'Nonce verification failed', 'tutor' ) );
404 \set_transient( self::LOGIN_ERRORS_TRANSIENT_KEY, $validation_error->get_error_messages(), MINUTE_IN_SECONDS );
405 return;
406 }
407
408 /**
409 * No sanitization/wp_unslash needed for log & pwd since WordPress
410 * does itself
411 *
412 * @since 2.1.3
413 *
414 * @see https://developer.wordpress.org/reference/functions/wp_signon/
415 */
416 //phpcs:disable WordPress.Security.NonceVerification.Missing
417 $username = tutor_utils()->array_get( 'log', $_POST ); //phpcs:ignore
418 $password = tutor_utils()->array_get( 'pwd', $_POST ); //phpcs:ignore
419 $redirect_to = isset( $_POST['redirect_to'] ) ? esc_url_raw( wp_unslash( $_POST['redirect_to'] ) ) : '';
420 $remember = isset( $_POST['rememberme'] );
421 //phpcs:enable WordPress.Security.NonceVerification.Missing
422
423 try {
424 $creds = array(
425 'user_login' => trim( $username ),
426 'user_password' => $password,
427 'remember' => $remember,
428 );
429
430 $validation_error = apply_filters( 'tutor_process_login_errors', $validation_error, $creds['user_login'], $creds['user_password'] );
431 if ( $validation_error->get_error_code() ) {
432 $validation_error->add(
433 $validation_error->get_error_code(),
434 $validation_error->get_error_message()
435 );
436 }
437
438 if ( empty( $creds['user_login'] ) ) {
439 $validation_error->add(
440 400,
441 __( 'Username is required.', 'tutor' )
442 );
443 }
444
445 $validate_consent = LegalConsent::validate_consent( LegalConsent::DISPLAY_ON_LOGIN, $_POST );
446 if ( is_wp_error( $validate_consent ) ) {
447 $validation_error->add(
448 $validate_consent->get_error_code(),
449 $validate_consent->get_error_message(),
450 );
451 }
452
453 if ( $validation_error->has_errors() ) {
454 \set_transient( self::LOGIN_ERRORS_TRANSIENT_KEY, $validation_error->get_error_messages() );
455 return;
456 }
457
458 // On multi-site, ensure user exists on current site, if not add them before allowing login.
459 if ( is_multisite() ) {
460 $user_data = get_user_by( is_email( $creds['user_login'] ) ? 'email' : 'login', $creds['user_login'] );
461 if ( $user_data && ! is_user_member_of_blog( $user_data->ID, get_current_blog_id() ) ) {
462 add_user_to_blog( get_current_blog_id(), $user_data->ID, 'customer' );
463 }
464 }
465
466 // Perform the login.
467 $user = wp_signon( apply_filters( 'tutor_login_credentials', $creds ), is_ssl() );
468 if ( is_wp_error( $user ) ) {
469 // If no error exist then add WP login error, to prevent error duplication.
470 if ( ! $validation_error->has_errors() ) {
471 $validation_error->add( 400, $user->get_error_message() );
472 }
473 } else {
474 // @since 4.0.0 $validate _consent param added.
475 do_action( 'tutor_after_login_success', $user->ID, $validate_consent );
476
477 // Since 1.9.8 do enroll if guest attempt to enroll.
478 $course_enroll_attempt = Input::post( 'tutor_course_enroll_attempt' );
479 if ( ! empty( $course_enroll_attempt ) && is_a( $user, 'WP_User' ) ) {
480 do_action( 'tutor_do_enroll_after_login_if_attempt', $course_enroll_attempt, $user->ID );
481 }
482 wp_safe_redirect( $redirect_to );
483 exit();
484 }
485 } catch ( \Exception $e ) {
486 do_action( 'tutor_login_failed' );
487 $validation_error->add( 400, $e->getMessage() );
488 } finally {
489 // Store errors in transient data.
490 \set_transient( self::LOGIN_ERRORS_TRANSIENT_KEY, $validation_error->get_error_messages(), MINUTE_IN_SECONDS );
491 }
492 }
493
494 /**
495 * Create/Update announcement
496 *
497 * @since 1.7.9
498 *
499 * @return void
500 */
501 public function create_or_update_announcement() {
502 tutor_utils()->checking_nonce();
503
504 $error = array();
505 $course_id = Input::post( 'tutor_announcement_course' );
506 $announcement_title = Input::post( 'tutor_announcement_title' );
507 $announcement_summary = Input::post( 'tutor_announcement_summary', '', Input::TYPE_TEXTAREA );
508
509 // Check if user can manage this announcement.
510 if ( ! tutor_utils()->can_user_manage( 'course', $course_id ) ) {
511 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
512 }
513
514 // Set data and sanitize it.
515 $form_data = array(
516 'post_type' => 'tutor_announcements',
517 'post_title' => $announcement_title,
518 'post_content' => $announcement_summary,
519 'post_parent' => $course_id,
520 'post_status' => 'publish',
521 );
522
523 if ( Input::has( 'announcement_id' ) ) {
524 $form_data['ID'] = Input::post( 'announcement_id' );
525 }
526
527 if ( ! empty( $form_data['ID'] ) ) {
528 if ( ! tutor_utils()->can_user_manage( 'announcement', $form_data['ID'] ) ) {
529 wp_send_json_error( array( 'message' => tutor_utils()->error_message() ) );
530 }
531 }
532
533 // Validation message set.
534 if ( empty( $form_data['post_parent'] ) ) {
535 $error['post_parent'] = __( 'Course name required', 'tutor' );
536
537 }
538
539 if ( empty( $form_data['post_title'] ) ) {
540 $error['post_title'] = __( 'Announcement title required', 'tutor' );
541 }
542
543 if ( empty( $form_data['post_content'] ) ) {
544 $error['post_content'] = __( 'Announcement summary required', 'tutor' );
545
546 }
547
548 if ( empty( $form_data['post_content'] ) ) {
549 $error['post_content'] = __( 'Announcement summary required', 'tutor' );
550
551 }
552
553 // If validation fails.
554 if ( count( $error ) > 0 ) {
555 wp_send_json_error(
556 array(
557 'message' => __( 'All fields required!', 'tutor' ),
558 'fields' => $error,
559 )
560 );
561 }
562
563 // Insert or update post.
564 $post_id = wp_insert_post( $form_data );
565 if ( $post_id > 0 ) {
566 $announcement = get_post( $post_id );
567 $action_type = Input::post( 'action_type' );
568
569 do_action( 'tutor_announcements/after/save', $post_id, $announcement, $action_type );
570
571 $resp_message = 'create' === $action_type ? __( 'Announcement created successfully', 'tutor' ) : __( 'Announcement updated successfully', 'tutor' );
572 wp_send_json_success( array( 'message' => $resp_message ) );
573 }
574
575 wp_send_json_error( array( 'message' => __( 'Something Went Wrong!', 'tutor' ) ) );
576 }
577
578 /**
579 * Delete announcement
580 *
581 * @since 1.7.9
582 *
583 * @return void
584 */
585 public function delete_announcement() {
586 tutor_utils()->checking_nonce();
587
588 $announcement_id = Input::post( 'announcement_id' );
589
590 if ( ! tutor_utils()->can_user_manage( 'announcement', $announcement_id ) ) {
591 wp_send_json_error( array( 'message' => __( 'Access Denied', 'tutor' ) ) );
592 }
593
594 $delete = wp_delete_post( $announcement_id );
595 if ( $delete ) {
596 wp_send_json_success( array( 'message' => __( 'Announcement deleted successfully', 'tutor' ) ) );
597 }
598
599 wp_send_json_error( array( 'message' => __( 'Announcement delete failed', 'tutor' ) ) );
600 }
601
602 /**
603 * Get youtube video duration.
604 *
605 * @since 3.0.0
606 *
607 * @return void
608 */
609 public function ajax_youtube_video_duration() {
610 tutor_utils()->check_nonce();
611
612 $video_id = Input::post( 'video_id' );
613 if ( empty( $video_id ) ) {
614 $this->json_response( __( 'Video ID is required', 'tutor' ), null, HttpHelper::STATUS_BAD_REQUEST );
615 }
616
617 tutor_utils()->check_current_user_capability( 'edit_tutor_courses' );
618
619 $api_key = tutor_utils()->get_option( 'lesson_video_duration_youtube_api_key', '' );
620 $url = "https://www.googleapis.com/youtube/v3/videos?id=$video_id&part=contentDetails&key=$api_key";
621
622 $request = HttpHelper::get( $url );
623 if ( HttpHelper::STATUS_OK === $request->get_status_code() ) {
624 $response = $request->get_json();
625 if ( isset( $response->items[0]->contentDetails->duration ) ) {
626 $duration = $response->items[0]->contentDetails->duration;
627 $this->json_response(
628 __( 'Fetched duration successfully', 'tutor' ),
629 array(
630 'duration' => $duration,
631 )
632 );
633 }
634 }
635
636 $this->json_response(
637 __( 'Failed to fetch duration', 'tutor' ),
638 null,
639 HttpHelper::STATUS_BAD_REQUEST
640 );
641 }
642 }
643