Viewing File: /home/rtsgrob/ww3/wp-content/plugins/tutor-pro/addons/tutor-zoom/classes/Zoom.php
<?php
/**
* TutorZoom Class
*
* @package TUTOR
*
* @since v.1.7.1
*/
namespace TUTOR_ZOOM;
use TUTOR\Tutor_Base;
use TUTOR\User;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Zoom extends Tutor_Base {
private $api_key;
private $settings_key;
private $zoom_meeting_post_type;
private $zoom_meeting_base_slug;
private $zoom_meeting_post_meta;
function __construct( $register_hooks = true ) {
parent::__construct();
$this->api_key = 'tutor_zoom_api';
$this->settings_key = 'tutor_zoom_settings';
$this->zoom_meeting_post_type = 'tutor_zoom_meeting';
$this->zoom_meeting_base_slug = 'tutor-zoom-meeting';
$this->zoom_meeting_post_meta = '_tutor_zm_data';
if ( ! $register_hooks ) {
// This object is used for reusable method calls
return;
}
add_action( 'init', array( $this, 'register_zoom_post_types' ) );
/**
* Register all admin scripts
*
* use same admin scripts on the front end for zoom
*
* @since 1.9.4
*/
add_action( 'wp_loaded', array( $this, 'register_admin_scripts' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'admin_scripts_frontend' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'tutor_script_text_domain' ), 100 );
add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) );
add_action( 'tutor_admin_register', array( $this, 'register_menu' ) );
add_filter( 'tutor_course_contents_post_types', array( $this, 'tutor_course_contents_post_types' ) );
// Saving zoom settings
add_action( 'wp_ajax_tutor_save_zoom_api', array( $this, 'tutor_save_zoom_api' ) );
add_action( 'wp_ajax_tutor_save_zoom_settings', array( $this, 'tutor_save_zoom_settings' ) );
// Add meeting button options
add_action( 'add_meta_boxes', function(){
tutor_meta_box_wrapper( 'zoome-meeting-for-course', __( 'Zoom Meeting', 'tutor' ), array($this, 'add_meetings_metabox'), tutor()->course_post_type, 'advanced', 'default', 'tutor-admin-post-meta' );
});
add_action( 'tutor/frontend_course_edit/after/course_builder', array( $this, 'add_meta_box_frontend' ) );
add_action( 'tutor_course_builder_after_btn_group', array( $this, 'add_meeting_option_in_topic' ), 12, 2 );
// Meeting modal form and save action
add_action( 'wp_ajax_tutor_zoom_save_meeting', array( $this, 'tutor_zoom_save_meeting' ) );
add_action( 'wp_ajax_tutor_zoom_delete_meeting', array( $this, 'tutor_zoom_delete_meeting' ) );
add_action( 'tutor_course/single/before/topics', array( $this, 'tutor_zoom_course_meeting' ) );
add_filter( 'template_include', array( $this, 'load_meeting_template' ), 99 );
/**
* Apply filters on tutor nav items add zoom menu
*
* Load zoom template from zoom addons
*
* @since 1.9.4
*/
add_filter( 'tutor_dashboard/instructor_nav_items', array( $this, 'add_zoom_menu' ) );
add_filter( 'load_dashboard_template_part_from_other_location', array( $this, 'load_zoom_template' ) );
add_action( 'tutor/course/builder/content/tutor_zoom_meeting', array( $this, 'course_builder_row' ), 10, 4 );
/**
* Is zoom lesson completed
*
* @since v2.0.0
*/
add_action( 'tutor_is_zoom_lesson_done', array( __CLASS__, 'is_zoom_lesson_done' ), 10, 3 );
add_action( 'tutor/zoom/right_icon_area', array( $this, 'right_icon_area' ), 10, 2 );
/**
* Show admin notice to update Zoom API authentication
* from JWT to Server-to-Server-OAuth
*
* @since 2.2.0
*/
add_action( 'admin_notices', array( $this, 'show_admin_notice' ) );
add_action( 'wp_footer', array( $this, 'show_notice_frontend' ) );
add_filter( 'post_type_link', array( $this, 'change_zoom_single_url' ), 1, 2 );
}
/**
* Change zoom meeting single URL
*
* @since 2.6.0
*
* @param string $post_link post link.
* @param integer $id id.
*
* @return string
*/
public function change_zoom_single_url( $post_link, $id = 0 ) {
$post = get_post( $id );
if ( is_object( $post ) && 'tutor_zoom_meeting' === $post->post_type ) {
$course_id = tutor_utils()->get_course_id_by( 'zoom_lesson', $post->ID );
$course = get_post( $course_id );
if ( is_object( $course ) ) {
return home_url( "/{$this->course_base_permalink}/{$course->post_name}/zoom-lessons/" . $post->post_name . '/' );
} else {
return home_url( "/{$this->course_base_permalink}/sample-course/zoom-lessons/" . $post->post_name . '/' );
}
}
return $post_link;
}
public function course_builder_row( $meeting, $topic, $course_id, $index = null ) {
$row_id = 'tutor-zoom-meeting-' . $meeting->ID;
$id_string_delete = 'tutor-zoom-meet-del-modal-id' . $meeting->ID;
?>
<div data-course_content_id="<?php echo $meeting->ID; ?>" id="<?php echo $row_id; ?>" class="course-content-item tutor-zoom-meeting-item tutor-zoom-meeting-<?php echo $meeting->ID; ?>">
<div class="tutor-course-content-top tutor-d-flex tutor-align-center">
<span class="tutor-icon-hamburger-menu tutor-cursor-move tutor-px-12"></span>
<a href="javascript:;" class="<?php echo $topic->ID>0 ? 'tutor-zoom-meeting-modal-open-btn' : ''; ?>" data-tutor-modal-target="<?php echo $topic->ID>0 ? 'tutor-zoom-modal-cb-'.$meeting->ID : ''; ?>">
<?php echo __( 'Zoom', 'tutor' ) . ' ' . $index . ': ' . stripslashes( $meeting->post_title ); ?>
</a>
<div class="tutor-course-content-top-right-action">
<?php if($topic->ID>0): ?>
<a href="javascript:;" class="tutor-zoom-meeting-modal-open-btn tutor-iconic-btn" data-tutor-modal-target="tutor-zoom-modal-cb-<?php echo $meeting->ID; ?>">
<span class="tutor-icon-edit" area-hidden="true"></span>
</a>
<?php endif; ?>
<a href="javascript:;" class="tutor-iconic-btn" data-tutor-modal-target="<?php echo $id_string_delete; ?>">
<span class="tutor-icon-trash-can-line" area-hidden="true"></span>
</a>
</div>
</div>
<?php
// update Modal
$this->tutor_zoom_meeting_modal_content( $meeting->ID, $topic->ID, $course_id, 'course-builder', 'tutor-zoom-modal-cb-' . $meeting->ID );
// Delete confirmation modal
tutor_load_template( 'modal.confirm', array(
'id' => $id_string_delete,
'image' => 'icon-trash.svg',
'title' => __('Do You Want to Delete This Meeting?', 'tutor-pro'),
'content' => __('Are you sure you want to delete this meeting permanently? Please confirm your choice.', 'tutor-pro'),
'yes' => array(
'text' => __('Yes, Delete This', 'tutor-pro'),
'class' => 'tutor-list-ajax-action',
'attr' => array(
'data-request_data=\'{"meeting_id":"'. $meeting->ID .'", "action":"tutor_zoom_delete_meeting"}\'',
'data-delete_element_id="' . $row_id . '"'
)
),
));
?>
</div>
<?php
}
public function register_zoom_post_types() {
$labels = array(
'name' => _x( 'Meetings', 'post type general name', 'tutor-pro' ),
'singular_name' => _x( 'Meeting', 'post type singular name', 'tutor-pro' ),
'menu_name' => _x( 'Meetings', 'admin menu', 'tutor-pro' ),
'name_admin_bar' => _x( 'Meeting', 'add new on admin bar', 'tutor-pro' ),
'add_new' => _x( 'Add New', $this->zoom_meeting_post_type, 'tutor-pro' ),
'add_new_item' => __( 'Add New Meeting', 'tutor-pro' ),
'new_item' => __( 'New Meeting', 'tutor-pro' ),
'edit_item' => __( 'Edit Meeting', 'tutor-pro' ),
'view_item' => __( 'View Meeting', 'tutor-pro' ),
'all_items' => __( 'Meetings', 'tutor-pro' ),
'search_items' => __( 'Search Meetings', 'tutor-pro' ),
'parent_item_colon' => __( 'Parent Meetings:', 'tutor-pro' ),
'not_found' => __( 'No Meeting found.', 'tutor-pro' ),
'not_found_in_trash' => __( 'No Meetings found in Trash.', 'tutor-pro' ),
);
$args = array(
'labels' => $labels,
'description' => __( 'Description.', 'tutor-pro' ),
'public' => false,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => false,
'query_var' => true,
'rewrite' => array( 'slug' => $this->zoom_meeting_base_slug ),
'menu_icon' => 'dashicons-list-view',
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => false,
'menu_position' => null,
'supports' => array( 'title', 'editor' ),
'exclude_from_search' => true,
);
register_post_type( $this->zoom_meeting_post_type, $args );
}
/**
* Register all admin scripts so that later
*
* we can enqueue on admin_scripts hook or wp_enqueue_scripts hook
*
* @since 1.9.4
*/
public function register_admin_scripts() {
wp_register_script( 'tutor_zoom_timepicker_js', TUTOR_ZOOM()->url . 'assets/js/lib/jquery-ui-timepicker.js', array( 'jquery', 'jquery-ui-datepicker', 'jquery-ui-slider' ), TUTOR_PRO_VERSION, true );
wp_register_script( 'tutor_zoom_admin_js', TUTOR_ZOOM()->url . 'assets/js/admin.js', array( 'jquery' ), TUTOR_PRO_VERSION, true );
wp_register_script( 'tutor_zoom_common_js', TUTOR_ZOOM()->url . 'assets/js/common.js', array( 'jquery', 'jquery-ui-datepicker' ), TUTOR_PRO_VERSION, true );
wp_register_style( 'tutor_zoom_timepicker_css', TUTOR_ZOOM()->url . 'assets/css/jquery-ui-timepicker.css', false, TUTOR_PRO_VERSION );
wp_register_style( 'tutor_zoom_common_css', TUTOR_ZOOM()->url . 'assets/css/common.css', false, TUTOR_PRO_VERSION );
wp_register_style( 'tutor_zoom_admin_css', TUTOR_ZOOM()->url . 'assets/css/admin.css', false, TUTOR_PRO_VERSION );
}
/**
* Enqueue admin scripts
*/
public function admin_scripts() {
wp_enqueue_script( 'tutor_zoom_timepicker_js' );
wp_enqueue_script( 'tutor_zoom_admin_js' );
wp_enqueue_script( 'tutor_zoom_common_js' );
wp_enqueue_style( 'tutor_zoom_timepicker_css' );
wp_enqueue_style( 'tutor_zoom_common_css' );
wp_enqueue_style( 'tutor_zoom_admin_css' );
}
/**
* Load admin scripts on the frontend that is need for zoom
*
* @since 1.9.4
*/
public function admin_scripts_frontend() {
wp_enqueue_script( 'tutor_zoom_timepicker_js' );
wp_enqueue_script( 'tutor_zoom_admin_js' );
wp_enqueue_script( 'tutor_zoom_common_js' );
wp_enqueue_style( 'tutor_zoom_timepicker_css' );
wp_enqueue_style( 'tutor_zoom_common_css' );
}
/**
* Enqueue frontend scripts
*/
public function frontend_scripts() {
global $wp_query;
$is_frontend_course_builder = tutor_utils()->is_tutor_frontend_dashboard( 'create-course' );
$is_single_zoom_page = ( is_single() && ! empty( $wp_query->query['post_type'] ) && $wp_query->query['post_type'] === 'tutor_zoom_meeting' );
if ( $wp_query->is_page && $is_frontend_course_builder ) {
wp_enqueue_script( 'tutor_zoom_timepicker_js', TUTOR_ZOOM()->url . 'assets/js/lib/jquery-ui-timepicker.js', array( 'jquery', 'jquery-ui-datepicker', 'jquery-ui-slider' ), TUTOR_PRO_VERSION, true );
wp_enqueue_style( 'tutor_zoom_timepicker_css', TUTOR_ZOOM()->url . 'assets/css/jquery-ui-timepicker.css', false, TUTOR_PRO_VERSION );
wp_enqueue_script( 'tutor_zoom_common_js', TUTOR_ZOOM()->url . 'assets/js/common.js', array( 'jquery', 'jquery-ui-datepicker' ), TUTOR_PRO_VERSION, true );
wp_enqueue_style( 'tutor_zoom_common_css', TUTOR_ZOOM()->url . 'assets/css/common.css', false, TUTOR_PRO_VERSION );
}
if ( is_single_course() || $is_single_zoom_page ) {
wp_enqueue_script( 'tutor_zoom_moment_js', TUTOR_ZOOM()->url . 'assets/js/lib/moment.min.js', array(), TUTOR_PRO_VERSION, true );
wp_enqueue_script( 'tutor_zoom_moment_tz_js', TUTOR_ZOOM()->url . 'assets/js/lib/moment-timezone-with-data.min.js', array(), TUTOR_PRO_VERSION, true );
wp_enqueue_script( 'tutor_zoom_countdown_js', TUTOR_ZOOM()->url . 'assets/js/lib/jquery.countdown.min.js', array( 'jquery' ), TUTOR_PRO_VERSION, true );
}
if ( is_single_course() || $is_single_zoom_page || $is_frontend_course_builder || ( isset( $wp_query->query_vars['tutor_dashboard_page'] ) && $wp_query->query_vars['tutor_dashboard_page'] == 'zoom' ) ) {
wp_enqueue_script( 'tutor_zoom_frontend_js', TUTOR_ZOOM()->url . 'assets/js/frontend.js', array( 'jquery' ), TUTOR_PRO_VERSION, true );
wp_enqueue_style( 'tutor_zoom_frontend_css', TUTOR_ZOOM()->url . 'assets/css/frontend.css', false, TUTOR_PRO_VERSION );
}
}
public function register_menu() {
add_submenu_page( 'tutor', __( 'Zoom', 'tutor-pro' ), __( 'Zoom', 'tutor-pro' ), 'manage_tutor_instructor', 'tutor_zoom', array( $this, 'tutor_zoom' ) );
}
public function tutor_course_contents_post_types( $post_types ) {
$post_types[] = $this->zoom_meeting_post_type;
return $post_types;
}
public function add_meetings_metabox( $echo = true ) {
$current_course_id = ! is_admin() && isset( $_GET['course_ID'] ) ? $_GET['course_ID'] : get_the_ID();
$post = get_post( $current_course_id );
$user_id = get_current_user_id();
$settings = json_decode( get_user_meta( $user_id, $this->api_key, true ), true );
$api_key = ( ! empty( $settings['api_key'] ) ) ? $settings['api_key'] : '';
$api_secret = ( ! empty( $settings['api_secret'] ) ) ? $settings['api_secret'] : '';
if ( is_a( $post, 'WP_POST' ) && $post->post_type == tutor()->course_post_type && ! empty( $api_key ) && ! empty( $api_secret ) ) {
$course_id = $post->ID;
$topic_id = 0;
if ( $echo ) {
echo '<div class="tutor-course-builder-section">
<div id="tutor-zoom-metabox-wrap">';
require TUTOR_ZOOM()->path . 'views/metabox/meetings.php';
echo ' </div>
</div>';
} else {
ob_start();
?>
<div class="tutor-course-builder-section">
<div id="tutor-zoom-metabox-wrap">
<?php require TUTOR_ZOOM()->path . 'views/metabox/meetings.php' ;?>
</div>
</div>
<?php
return ob_get_clean();
}
}
}
public function add_meeting_option_in_topic( $topic_id, $course_id ) {
$user_id = get_current_user_id();
$settings = json_decode( get_user_meta( $user_id, $this->api_key, true ), true );
$api_key = ( ! empty( $settings['api_key'] ) ) ? $settings['api_key'] : '';
$api_secret = ( ! empty( $settings['api_secret'] ) ) ? $settings['api_secret'] : '';
$new_modal_ = 'tutor-zoom-new-lesson-' . $topic_id;
if ( ! empty( $api_key ) && ! empty( $api_secret ) ) {
?>
<button class="tutor-btn tutor-btn-outline-primary tutor-btn-sm" data-tutor-modal-target="<?php echo $new_modal_; ?>">
<i class="tutor-icon-brand-zoom tutor-mr-8" area-hidden="true"></i>
<?php _e( 'Zoom Live Lesson', 'tutor-pro' ); ?>
</button>
<?php
$this->tutor_zoom_meeting_modal_content( 0, $topic_id, $course_id, 'course-builder', $new_modal_ );
}
}
public function tutor_zoom_meeting_modal_content( $meeting_id, $topic_id, $course_id, $click_form, $modal_id = null ) {
$meeting_host = $this->get_users_options();
$timezone_options = require dirname( __DIR__ ) . '/includes/timezone.php';
$modal_id = $modal_id ? $modal_id : 'tutor-zoom-meeting-modal-' . $meeting_id;
$post = null;
$meeting_data = null;
if ( 0 != $meeting_id ) {
$post = get_post( $meeting_id );
$meeting_start = get_post_meta( $meeting_id, '_tutor_zm_start_datetime', true );
$meeting_data = get_post_meta( $meeting_id, $this->zoom_meeting_post_meta, true );
$meeting_data = json_decode( $meeting_data, true );
}
!is_array($meeting_data) ? $meeting_data=null : 0;
$start_date = '';
$start_time = '';
$host_id = (! empty( $meeting_data ) && ! empty($meeting_data['host_id'])) ? $meeting_data['host_id'] : '';
$title = (! empty( $meeting_data ) && ! empty($meeting_data['topic'])) ? wp_strip_all_tags( $meeting_data['topic'] ) : '';
$summary = (! empty( $post ) && ! empty($post->post_content)) ? $post->post_content : '';
$timezone = (! empty( $meeting_data ) && ! empty($meeting_data['timezone'])) ? $meeting_data['timezone'] : '';
$duration = (! empty( $meeting_data ) && ! empty($meeting_data['duration'])) ? $meeting_data['duration'] : 60;
$duration_unit = ! empty( $post ) ? get_post_meta( $meeting_id, '_tutor_zm_duration_unit', true ) : 'min';
$password = (! empty( $meeting_data ) && ! empty($meeting_data['password'])) ? $meeting_data['password'] : '';
$auto_recording = (! empty( $meeting_data ) && ! empty($meeting_data['settings'])) ? $meeting_data['settings']['auto_recording'] : $this->get_settings( 'auto_recording' );
// Fallback meeting title
if(empty($title) && !empty($post)){
$title = $post->post_title;
}
if ( ! empty( $meeting_data ) ) {
$input_date = \DateTime::createFromFormat( 'Y-m-d H:i:s', $meeting_start );
$start_date = $input_date->format( 'd/m/Y' );
$start_time = $input_date->format( 'h:i A' );
$duration = ( $duration_unit == 'hr' ) ? $duration / 60 : $duration;
}
require TUTOR_ZOOM()->path . 'views/template/meeting-editor.php';
}
/**
* Save meeting
*/
public function tutor_zoom_save_meeting() {
tutor_utils()->checking_nonce();
$course_id = (int) sanitize_text_field( $_POST['course_id'] );
if ( ! tutor_utils()->can_user_edit_course( get_current_user_id(), $course_id) ) {
wp_send_json_error( tutor_utils()->error_message() );
}
// Check if API key updated.
if ( ! $this->has_account_id() ) {
wp_send_json_error(
array(
'post_id' => false,
'message' => __( 'Invalid Api Credentials', 'tutor-pro' ),
)
);
}
// Prepare linking data.
$meeting_id = (int) sanitize_text_field( $_POST['meeting_id'] );
$existing_meeting_id = $meeting_id;
$topic_id = (int) sanitize_text_field( $_POST['topic_id'] );
$click_form = sanitize_text_field( $_POST['click_form'] );
// Prepare auth data
$user_id = get_current_user_id();
$settings = json_decode( get_user_meta( $user_id, $this->api_key, true ), true );
$api_key = ( ! empty( $settings['api_key'] ) ) ? $settings['api_key'] : '';
$api_secret = ( ! empty( $settings['api_secret'] ) ) ? $settings['api_secret'] : '';
// Respond error if api key or secret not set
if ( empty( $api_key ) || empty( $api_secret ) ) {
wp_send_json_error(
array(
'post_id' => false,
'message' => __( 'Invalid Api Credentials', 'tutor-pro' ),
)
);
}
// Validate post value
$post_keys = array(
'meeting_host',
'meeting_title',
'meeting_timezone',
'meeting_date',
'meeting_time',
);
foreach ( $post_keys as $key ) {
if ( empty( $_POST[ $key ] ) ) {
wp_send_json_error( array( 'message' => __( 'All fields required!', 'tutor-pro' ) ) );
return;
}
}
// If set, then create the meeting
$host_id = sanitize_text_field( $_POST['meeting_host'] );
$title = sanitize_text_field( $_POST['meeting_title'] );
$summary = ! empty( $_POST['meeting_summary'] ) ? sanitize_text_field( $_POST['meeting_summary'] ) : '';
$timezone = sanitize_text_field( $_POST['meeting_timezone'] );
$start_date = sanitize_text_field( $_POST['meeting_date'] );
$start_time = sanitize_text_field( $_POST['meeting_time'] );
$input_duration = ! empty( $_POST['meeting_duration'] ) ? intval( $_POST['meeting_duration'] ) : 60;
$duration_unit = ! empty( $_POST['meeting_duration_unit'] ) ? $_POST['meeting_duration_unit'] : 'min';
$password = ! empty( $_POST['meeting_password'] ) ? sanitize_text_field( $_POST['meeting_password'] ) : '';
$join_before_host = ( $this->get_settings( 'join_before_host' ) ) ? true : false;
$host_video = ( $this->get_settings( 'host_video' ) ) ? true : false;
$participants_video = ( $this->get_settings( 'participants_video' ) ) ? true : false;
$mute_participants = ( $this->get_settings( 'mute_participants' ) ) ? true : false;
$enforce_login = ( $this->get_settings( 'enforce_login' ) ) ? true : false;
$auto_recording = ! empty( $_POST['auto_recording'] ) ? sanitize_text_field( $_POST['auto_recording'] ) : '';
if ( false === date_create_from_format( 'd/m/Y', $start_date ) ) {
$start_date = tutor_get_formated_date( 'd/m/Y', $start_date );
}
$input_date = \DateTime::createFromFormat( 'd/m/Y h:i A', $start_date . ' ' . $start_time );
if(!$input_date){
wp_send_json_error( array('message' => __('Invalid Time Format', 'tutor-pro')));
return;
}
$meeting_start = $input_date->format( 'Y-m-d\TH:i:s' );
$duration = ( $duration_unit == 'hr' ) ? $input_duration * 60 : $input_duration;
$data = array(
'topic' => $title,
'type' => 2,
'start_time' => $meeting_start,
'timezone' => $timezone,
'duration' => $duration,
'password' => $password,
'settings' => array(
'join_before_host' => $join_before_host,
'host_video' => $host_video,
'participant_video' => $participants_video,
'mute_upon_entry' => $mute_participants,
'auto_recording' => $auto_recording,
'enforce_login' => $enforce_login,
),
);
// save post
$menu_order = tutor_utils()->get_next_course_content_order_id( $topic_id, $meeting_id );
$post_content = array(
'ID' => $meeting_id ? $meeting_id : 0,
'post_title' => $title,
'post_name' => sanitize_title( $title ),
'post_content' => $summary,
'post_type' => $this->zoom_meeting_post_type,
'post_parent' => $topic_id ? $topic_id : $course_id,
'post_status' => 'publish',
'menu_order' => $menu_order,
);
// save zoom meeting
$post_id = wp_insert_post( $post_content );
!$meeting_id ? $meeting_id=$post_id : 0;
$meeting_data = get_post_meta( $post_id, $this->zoom_meeting_post_meta, true );
$meeting_data = json_decode( $meeting_data, true );
// Interact with zoom
$zoom_endpoint = tutor_utils()->get_package_object( true, '\Zoom\Endpoint\Meetings', $api_key, $api_secret );
if ( ! empty( $meeting_data ) && isset( $meeting_data['id'] ) ) {
// Update existing meeting id if id provided
$zoom_endpoint->update( $meeting_data['id'], $data );
$saved_meeting = $zoom_endpoint->meeting( $meeting_data['id'] );
do_action( 'tutor_zoom_after_update_meeting', $post_id );
} else {
// Or create new meeting
$saved_meeting = $zoom_endpoint->create( $host_id, $data );
update_post_meta( $post_id, '_tutor_zm_for_course', $course_id );
update_post_meta( $post_id, '_tutor_zm_for_topic', $topic_id );
do_action( 'tutor_zoom_after_save_meeting', $post_id );
}
// Update meeting meta data
update_post_meta( $post_id, '_tutor_zm_start_date', $input_date->format( 'Y-m-d' ) );
update_post_meta( $post_id, '_tutor_zm_start_datetime', $input_date->format( 'Y-m-d H:i:s' ) );
update_post_meta( $post_id, '_tutor_zm_duration', $input_duration );
update_post_meta( $post_id, '_tutor_zm_duration_unit', $duration_unit );
update_post_meta( $post_id, $this->zoom_meeting_post_meta, json_encode( $saved_meeting ) );
// Prepare response HTML to be shown after meeting create/update
$course_contents = '';
$selector = '';
$replace_selector = '';
if ( $click_form == 'course-builder' ) {
// If from course builder under topic
ob_start();
$single_meetings = $this->get_meetings( null, null, null, array(), true, $meeting_id );
foreach($single_meetings as $single_meeting){
$this->course_builder_row( $single_meeting, (object) array( 'ID' => $topic_id ), $course_id );
}
$course_contents = ob_get_clean();
$selector = 'course-builder';
$replace_selector = $existing_meeting_id ? '#tutor-zoom-meeting-' . $existing_meeting_id : '';
} elseif ( $click_form == 'metabox' ) {
// If from standalone meeting outside topic
ob_start();
require TUTOR_ZOOM()->path . 'views/metabox/meetings.php';
$course_contents = ob_get_clean();
$selector = '#tutor-zoom-metabox-wrap';
}
// Provide the form again, otherwise new zoom lesson modal shows the previous input contents
$modal_html = '';
if(!$existing_meeting_id && $topic_id) {
$new_modal_ = 'tutor-zoom-new-lesson-' . $topic_id;
ob_start();
$this->tutor_zoom_meeting_modal_content( 0, $topic_id, $course_id, 'course-builder', $new_modal_ );
$modal_html = ob_get_clean();
}
// Finally send the response
wp_send_json_success(
array(
'message' => __( 'Meeting Successfully Saved', 'tutor-pro' ),
'course_contents' => $course_contents,
'selector' => $selector,
'replace_selector' => $replace_selector,
'editor_modal_html' => $modal_html
)
);
}
/**
* Delete meeting
*/
public function tutor_zoom_delete_meeting() {
tutor_utils()->checking_nonce();
$post_id = (int) sanitize_text_field( $_POST['meeting_id'] );
$course_id = wp_get_post_parent_id( $post_id );
if ( tutor()->topics_post_type === get_post_type( $course_id ) ) {
$course_id = wp_get_post_parent_id( $course_id );
}
if ( ! tutor_utils()->can_user_edit_course( get_current_user_id(), $course_id ) ) {
wp_send_json_error( tutor_utils()->error_message() );
}
// Check if API key updated.
if ( ! $this->has_account_id() ) {
wp_send_json_error(
array(
'post_id' => false,
'message' => __( 'Invalid Api Credentials', 'tutor-pro' ),
)
);
}
$user_id = get_current_user_id();
$settings = json_decode( get_user_meta( $user_id, $this->api_key, true ), true );
$api_key = ( ! empty( $settings['api_key'] ) ) ? $settings['api_key'] : '';
$api_secret = ( ! empty( $settings['api_secret'] ) ) ? $settings['api_secret'] : '';
if ( ! empty( $api_key ) && ! empty( $api_secret ) ) {
$meeting_data = get_post_meta( $post_id, $this->zoom_meeting_post_meta, true );
$meeting_data = json_decode( $meeting_data, true );
$zoom_endpoint = tutor_utils()->get_package_object( true, '\Zoom\Endpoint\Meetings', $api_key, $api_secret );
if(isset($meeting_data['id'])){
$meeting_info = $zoom_endpoint->meeting($meeting_data['id']);
if(is_array($meeting_info) && isset($meeting_info['id'])){
$zoom_endpoint->remove( $meeting_data['id'] );
}
}
wp_delete_post( $post_id, true );
do_action( 'tutor_zoom_after_delete_meeting', $post_id );
wp_send_json_success(
array(
'post_id' => $post_id,
'message' => __( 'Meeting Successfully Deleted', 'tutor-pro' ),
)
);
} else {
wp_send_json_error(
array(
'post_id' => false,
'message' => __( 'Invalid Api Credentials', 'tutor-pro' ),
)
);
}
}
/**
* Get zoom meetings based on time context like expired, active, and currently running
*/
public function get_meetings( $limit = 10, $page = 1, $context = '', $args = array(), $get_from_topic = true, $meeting_id = null ) {
global $wpdb;
$filter_clause = '';
$limit_offset = '';
$limit_offset .= ' ORDER BY ' . ( ! empty( $args['order_by'] ) ? $args['order_by'] : '_meta_start.meta_value' );
$limit_offset .= ' ' . ( ! empty( $args['order'] ) ? $args['order'] : 'DESC' );
$limit_offset .= ! ( $limit === null ) ? ' LIMIT ' . $limit . ' OFFSET ' . ( ( $page - 1 ) * $limit ) : '';
// Get meetings by id
if ( $meeting_id ) {
$meeting_id = ! is_array( $meeting_id ) ? array( $meeting_id ) : 0;
$meeting_ids = implode( ',', $meeting_id );
$filter_clause .= ' AND _meeting.ID IN(' . $meeting_ids . ')';
}
// Course ID filter
if ( ! empty( $args['course_id'] ) ) {
$topic_ids = array();
if ( $get_from_topic ) {
$topic_ids = $wpdb->get_col(
$wpdb->prepare(
"SELECT ID FROM {$wpdb->posts} WHERE post_type=%s AND post_parent=%d",
'topics',
$args['course_id']
)
);
}
$parent_ids = array_merge( $topic_ids, array( $args['course_id'] ) );
$parent_ids = implode( ',', $parent_ids );
$filter_clause .= ' AND _meeting.post_parent IN (' . $parent_ids . ')';
}
// Author filter
if ( ! empty( $args['author'] ) ) {
$filter_clause .= ' AND _meeting.post_author=' . $args['author'];
}
// Search filter
if ( ! empty( $args['search'] ) ) {
$filter_clause .= ' AND _meeting.post_title LIKE "%' . sanitize_text_field( $args['search'] ) . '%"';
}
// Date filter
if ( ! empty( $args['date'] ) ) {
$filter_clause .= ' AND DATE(_meta_start.meta_value)=\'' . $args['date'] . '\'';
}
$context_clause = '';
if ( ! ( $context === null ) ) {
$math_operator = $context == 'active' ? '>' : '<';
$context_clause = ' AND ((
_meta_unit.meta_value=\'min\'
AND (_meta_start.meta_value + INTERVAL _meta_duration.meta_value MINUTE)' . $math_operator . 'NOW()
) OR (
_meta_unit.meta_value=\'hr\'
AND (_meta_start.meta_value + INTERVAL _meta_duration.meta_value HOUR)' . $math_operator . 'NOW()
))';
}
// Get the meetings from Database
$meetings = $wpdb->get_results(
"SELECT DISTINCT _meeting.*,
_meta_start.meta_value AS meeting_starts_at,
(_meta_start.meta_value + INTERVAL _meta_duration.meta_value MINUTE)<NOW() AS is_expired,
(NOW()>_meta_start.meta_value AND NOW()<_meta_start.meta_value + INTERVAL _meta_duration.meta_value MINUTE) AS is_running,
_meta_start.meta_value>NOW() AS is_upcoming
FROM {$wpdb->posts} _meeting
INNER JOIN {$wpdb->postmeta} _meta_start ON _meeting.ID=_meta_start.post_id
INNER JOIN {$wpdb->postmeta} _meta_duration ON _meeting.ID=_meta_duration.post_id
INNER JOIN {$wpdb->postmeta} _meta_unit ON _meeting.ID=_meta_unit.post_id
WHERE _meeting.post_type='tutor_zoom_meeting'
AND _meta_start.meta_key='_tutor_zm_start_datetime'
AND _meta_unit.meta_key='_tutor_zm_duration_unit'
AND _meta_duration.meta_key='_tutor_zm_duration'
{$filter_clause}
{$context_clause}
{$limit_offset}"
);
return $meetings;
}
private function get_option_data( $key, $data ) {
if ( empty( $data ) || ! is_array( $data ) ) {
return false;
}
if ( ! $key ) {
return $data;
}
if ( array_key_exists( $key, $data ) ) {
return apply_filters( $key, $data[ $key ] );
}
}
private function get_transient_key() {
$user_id = get_current_user_id();
$transient_key = 'tutor_zoom_users_' . $user_id;
return $transient_key;
}
public function get_api( $key = null ) {
$user_id = get_current_user_id();
$api_data = json_decode( get_user_meta( $user_id, $this->api_key, true ), true );
return $this->get_option_data( $key, $api_data );
}
private function get_settings( $key = null ) {
$user_id = get_current_user_id();
$settings_data = json_decode( get_user_meta( $user_id, $this->settings_key, true ), true );
return $this->get_option_data( $key, $settings_data );
}
public function tutor_zoom() {
require TUTOR_ZOOM()->path . 'views/pages/main.php';
}
public function tutor_save_zoom_api() {
tutor_utils()->checking_nonce();
if ( ! User::has_any_role( array( User::ADMIN, User::INSTRUCTOR ) ) ) {
wp_send_json_error( tutor_utils()->error_message() );
}
$api_data = (array) isset( $_POST[ $this->api_key ] ) ? $_POST[ $this->api_key ] : array();
$api_data = apply_filters( 'tutor_zoom_api_input', $api_data );
if ( empty( $api_data['api_key'] ) || empty( $api_data['api_secret'] ) || empty( $api_data['account_id'] ) ) {
wp_send_json_error(
array(
'message' => 'Please fill up all the fields',
'tutor-pro',
)
);
}
do_action( 'tutor_save_zoom_api_before' );
$user_id = get_current_user_id();
update_user_meta( $user_id, $this->api_key, json_encode( $api_data ) );
do_action( 'tutor_save_zoom_api_after' );
// Validate before saving.
if ( ! $this->tutor_check_api_connection( $api_data ) ) {
delete_user_meta( $user_id, $this->api_key );
wp_send_json_error( array( 'message' => __( 'Please recheck your API Key and Secret Key', 'tutor-pro' ) ) );
return;
}
wp_send_json_success( array( 'message' => __( 'You can now add live classes to any course!', 'tutor-pro' ) ) );
}
public function tutor_save_zoom_settings() {
tutor_utils()->checking_nonce();
if ( ! User::has_any_role( array( User::ADMIN, User::INSTRUCTOR ) ) ) {
wp_send_json_error( tutor_utils()->error_message() );
}
do_action( 'tutor_save_zoom_settings_before' );
$settings = (array) isset( $_POST[ $this->settings_key ] ) ? $_POST[ $this->settings_key ] : array();
$settings = apply_filters( 'tutor_zoom_settings_input', $settings );
$user_id = get_current_user_id();
update_user_meta( $user_id, $this->settings_key, json_encode( $settings ) );
do_action( 'tutor_save_zoom_settings_after' );
wp_send_json_success( array( 'message' => __( 'Settings Updated', 'tutor-pro' ) ) );
}
private function tutor_check_api_connection( $settings ) {
$transient_key = $this->get_transient_key();
delete_transient( $transient_key ); // delete temporary cache
$users = $this->tutor_zoom_get_users( $settings );
return ! empty( $users );
}
/**
* Get Zoom Users from Zoom API
*
* @return array
*/
public function tutor_zoom_get_users( $settings = null ) {
$user_id = get_current_user_id();
$transient_key = $this->get_transient_key();
$users = get_transient( $transient_key );
$settings = $settings ? $settings : json_decode( get_user_meta( $user_id, $this->api_key, true ), true );
if ( empty( $users ) ) {
$api_key = ( ! empty( $settings['api_key'] ) ) ? $settings['api_key'] : '';
$api_secret = ( ! empty( $settings['api_secret'] ) ) ? $settings['api_secret'] : '';
if ( ! empty( $api_key ) && ! empty( $api_secret ) ) {
$users = array();
$users_data = tutor_utils()->get_package_object( true, '\Zoom\Endpoint\Users', $api_key, $api_secret );
$users_list = $users_data->userlist();
if ( ! empty( $users_list ) && ! empty( $users_list['users'] ) ) {
$users = $users_list['users'];
set_transient( $transient_key, $users, 36000 );
}
} else {
$users = array();
}
}
return $users;
}
/**
* Get Zoom Users
*
* @return array
*/
public function get_users_options() {
$users = $this->tutor_zoom_get_users();
if ( ! empty( $users ) ) {
foreach ( $users as $user ) {
$first_name = $user['first_name'];
$last_name = $user['last_name'] ?? '';
$email = $user['email'];
$id = $user['id'];
$user_list[ $id ] = $first_name . ' ' . $last_name . ' (' . $email . ')';
}
} else {
return array();
}
return $user_list;
}
/**
* Load zoom meeting template
*
* @return array
*/
public function tutor_zoom_course_meeting() {
ob_start();
tutor_load_template( 'single.course.zoom-meetings', null, true );
$output = apply_filters( 'tutor_course/single/zoom_meetings', ob_get_clean() );
echo $output;
}
/**
* Load zoom meeting template
*
* @return array
*/
public function load_meeting_template( $template ) {
global $wp_query, $post;
if ( $wp_query->is_single && ! empty( $wp_query->query_vars['post_type'] ) && $wp_query->query_vars['post_type'] === $this->zoom_meeting_post_type ) {
if ( is_user_logged_in() ) {
$content_type = ( get_post_type( $post->post_parent ) === tutor()->course_post_type ) ? 'topic' : 'lesson';
$has_content_access = tutor_utils()->has_enrolled_content_access( $content_type, $post->ID );
if ( $has_content_access ) {
$template = tutor_get_template( 'single-zoom-meeting', true );
} else {
$template = tutor_get_template( 'single.lesson.required-enroll' ); // You need to enroll first
}
} else {
$template = tutor_get_template( 'login' );
}
return $template;
}
return $template;
}
/**
* Add zoom menu on the tutor dashboard (frontend)
*
* @return array
*
* @since 1.9.4
*/
public function add_zoom_menu( $nav_items ) {
do_action( 'before_zoom_menu_add_on_frontend' );
$new_items = array(
'zoom' => array( 'title' => __( 'Zoom', 'tutor-pro' ), 'auth_cap' => tutor()->instructor_role, 'icon' => 'tutor-icon-brand-zoom' )
);
$nav_items = array_merge( $nav_items, $new_items );
return apply_filters( 'after_zoom_menu_add_on_frontend', $nav_items );
}
/**
* If request is for zoom then load template from addons
*
* @param String
*
* @return String
*
* @since 1.9.4
*/
public function load_zoom_template( $location ) {
global $wp_query;
$query_vars = $wp_query->query_vars;
if ( isset( $query_vars['tutor_dashboard_page'] ) && $query_vars['tutor_dashboard_page'] == 'zoom' ) {
$location = TUTOR_ZOOM()->path . '/templates/main.php';
}
return $location;
}
public function tutor_script_text_domain() {
wp_set_script_translations( 'tutor_zoom_admin_js', 'tutor-pro', tutor_pro()->path . 'languages/' );
wp_set_script_translations( 'tutor_zoom_frontend_js', 'tutor-pro', tutor_pro()->path . 'languages/' );
}
/**
* Check is zoom lesson mark as done or not
*
* @param string $value default value.
* @param string $lesson_id zoom lesson id.
* @param string $user_id id of student.
*
* @return bool | true on success | false on failure
*/
public static function is_zoom_lesson_done( $value, $lesson_id, $user_id ) : bool {
$lesson_id = sanitize_text_field( tutor_utils()->get_post_id( $lesson_id ) );
$user_id = sanitize_text_field( tutor_utils()->get_user_id( $user_id ) );
if ( $lesson_id && $user_id ) {
$meta_key = '_tutor_completed_lesson_id_' . $lesson_id;
$count = get_user_meta( $user_id, $meta_key, true );
return $count ? true : false;
}
return false;
}
/**
* Show icon on the right side of title on course spot light section
*
* @param int $post_id | zoom post id.
*
* @return void
*/
public function right_icon_area( int $post_id, $lock_icon=false ) : void {
$post_id = sanitize_text_field( $post_id );
$user_id = get_current_user_id();
$is_completed = self::is_zoom_lesson_done( '', $post_id, $user_id );
if ( $is_completed ) {
echo "<input type='checkbox' class='tutor-form-check-input tutor-form-check-circle' disabled='disabled' readonly='readonly' checked='checked'/>";
} else {
if($lock_icon) {
echo '<i class="tutor-icon-lock-line tutor-fs-7 tutor-color-muted tutor-mr-4" area-hidden="true"></i>';
} else {
echo "<input type='checkbox' class='tutor-form-check-input tutor-form-check-circle' disabled='disabled' readonly='readonly'/>";
}
}
}
/**
* Add meta box on the front end course build
*
* @since v2.0.0
*/
public function add_meta_box_frontend() {
course_builder_section_wrap( $this->add_meetings_metabox( $echo = false ), __( 'Zoom Meeting', 'tutor-pro' ) );
}
/**
* Show admin notice if Zoom API not updated
*
* @since 2.2.0
*
* @return void
*/
public function show_admin_notice() {
$account_id = $this->get_api( 'account_id' );
if ( ! $account_id ) {
$wrapper_class = 'notice notice-error tutor-py-8';
$this->alert_msg( $wrapper_class );
}
}
/**
* Zoom API update alert message
*
* @since 2.2.0
*
* @param string $wrapper_class notice wrapper css class.
* @param string $link_btn_class link btn class.
* @param bool $waring_border set true to show warning border.
*
* @return void
*/
public function alert_msg( string $wrapper_class, string $link_btn_class = '', $waring_border = false ) {
?>
<div class="<?php echo esc_attr( $wrapper_class ); ?>" style="<?php echo esc_attr( $waring_border ? "border:1px solid var(--tutor-color-warning);" : '' ); ?>">
<div class="tutor-fs-5 tutor-fw-medium tutor-mb-0 tutor-color-black tutor-mb-12">
<?php esc_html_e( 'API Update Required', 'tutor-pro' ); ?>
</div>
<div class="tutor-fs-7">
<div>
<?php echo sprintf( __( "The <a href='https://developers.zoom.us/docs/internal-apps/jwt-faq/' target='_blank'>Zoom JWT app type will be deprecated!</a> You must migrate to the new server-to-server OAuth app and update your API setup by September 1, 2023.", 'tutor-pro' ) ); ?>
</div>
<a class="<?php echo esc_attr( $link_btn_class ); ?>" href="https://docs.themeum.com/tutor-lms/addons/zoom-integration" target="_blank">
<?php esc_html_e( 'Check how to migrate from JWT to Server-to-Server OAuth app type', 'tutor-pro' ); ?>
</a>
</div>
</div>
<?php
}
/**
* Check whether user updated Zoom API or not
*
* @since 2.2.0
*
* @return boolean
*/
public function has_account_id() {
$account_id = $this->get_api( 'account_id' );
return $account_id ? true : false;
}
/**
* Show notice on the frontend if Zoom API not updated
*
* @since 2.2.0
*
* @return void
*/
public function show_notice_frontend() {
// Return if current user is not administrator or instructor.
if ( ! current_user_can( 'administrator' ) && ! current_user_can( tutor()->instructor_role ) ) {
return;
}
// Return if Zoom API already updated.
if ( $this->has_account_id() ) {
return;
}
// Return if user already landed on the set api page.
$dashboard_page = get_query_var( 'tutor_dashboard_page', '' );
$dashboard_sub_page = get_query_var( 'tutor_dashboard_sub_page', '' );
if ( 'zoom' === $dashboard_page && 'set-api' === $dashboard_sub_page ) {
return;
}
tutor_snackbar(
__( 'The Zoom JWT app type will be deprecated!', 'tutor-pro' ),
array(
array(
'title' => __( 'Migrate', 'tutor-pro' ),
'class' => 'tutor-btn tutor-btn-primary tutor-btn-sm',
'href' => tutor_utils()->tutor_dashboard_url( 'zoom/set-api' ),
),
array(
'title' => __( 'Documentation', 'tutor-pro' ),
'class' => 'tutor-btn tutor-btn-outline-primary tutor-btn-sm',
'href' => 'https://docs.themeum.com/tutor-lms/tutorials/how-to-migrate-from-zoom-jwt-to-server-to-server-oauth/',
'target' => '_blank',
),
),
'tutor-icon-warning'
);
}
}
Back to Directory
File Manager