STRATO-apps/wordpress_03/app/wp-content/plugins/tutor-pro/addons/h5p/src/Lesson.php

SHA-256: b4924f689a27994bfbfffd39eab45467dc464e7be17b32bb2dbd3b4135e0050c
<?php
/**
 * Handle Tutor H5P Lesson logic
 *
 * @package TutorPro\Addons
 * @subpackage H5P
 * @author Themeum <support@themeum.com>
 * @link https://themeum.com
 * @since 3.0.0
 */

namespace TutorPro\H5P;

use Tutor\Cache\TutorCache;
use TUTOR\Input;
use TUTOR\Tutor_Base;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Tutor H5P Lesson class
 */
class Lesson extends Tutor_Base {

	const TUTOR_H5P_LESSON_STATEMENT_LIST  = 'tutor-h5p-lesson-statements';
	const TUTOR_H5P_LESSON_STATEMENT_COUNT = 'tutor-h5p-lesson-statement-count';
	/**
	 * Tutor H5P Lesson class constructor
	 */
	public function __construct() {

		/**
		 * Hooks for handling tutor H5P lesson
		*/
		add_action( 'wp_ajax_tutor_h5p_list_lesson_contents', array( $this, 'obtain_lesson_content_list' ) );
		add_action( 'wp_ajax_save_h5p_lesson_xAPI_statement', array( $this, 'save_h5p_lesson_xAPI_statement' ) );
		add_filter( 'tutor_validate_lesson_complete', array( $this, 'lesson_completion_restriction' ), 10, 3 );
		add_action( 'wp_ajax_set_h5p_lesson_finished', array( $this, 'set_h5p_lesson_finished' ) );
		add_action( 'tutor_before_delete_course_content', array( $this, 'delete_h5p_lesson_statements_by_id' ), 10, 2 );
		add_action( 'tutor_lesson_before_the_content', array( $this, 'set_h5p_lesson' ), 10, 2 );
	}

	/**
	 * Set H5P lesson elements for tracking h5p lesson data.
	 *
	 * @since 3.0.0
	 *
	 * @param \WP_Post $post the post object.
	 * @param integer  $course_id the course id.
	 * @return void
	 */
	public function set_h5p_lesson( \WP_Post $post, int $course_id ) {
		$shortcodes = Utils::get_h5p_shortcodes( $post->post_content );
		if ( count( $shortcodes ) > 0 ) {
			?>
			<div class="tutor-fs-6 tutor-color-secondary tutor-lesson-wrapper tutor-spotlight-h5p-lesson-content" data-lesson-id="<?php echo esc_attr( $post->ID ); ?>" data-course-id="<?php echo esc_attr( $course_id ); ?>" data-topic-id="<?php echo esc_attr( $post->post_parent ); ?>">
				<input type="hidden" id="complete_lesson_enabled" value="<?php echo esc_attr( tutor_utils()->get_option( 'disable_complete_lesson_button' ) ); ?>" />
			</div>					
			<?php
		}
	}

	/**
	 * Set meta value when all H5P contents are complete
	 *
	 * @since 3.0.0
	 *
	 * @return JSON
	 */
	public function set_h5p_lesson_finished() {

		tutor_utils()->checking_nonce();

		$user_id   = get_current_user_id();
		$lesson_id = Input::post( 'lesson_id', 0, INPUT::TYPE_INT );

		update_user_meta( $user_id, '_tutor_h5p_lesson_completed_' . $lesson_id, true );

		return wp_send_json_success();
	}

	/**
	 * Prevent h5p lesson completion until all h5p lesson are complete
	 *
	 * @since 3.0.0
	 *
	 * @param bool $is_complete check if the lesson is complete.
	 * @param int  $user_id the user id.
	 * @param int  $lesson_id the lesson id.
	 * @return bool
	 */
	public function lesson_completion_restriction( $is_complete, $user_id, $lesson_id ) {
		$lesson     = get_post( $lesson_id );
		$content    = $lesson->post_content;
		$shortcodes = Utils::get_h5p_shortcodes( $content );

		if ( ! tutor_utils()->get_option( 'disable_complete_lesson_button' ) ) {
			return $is_complete;
		}

		if ( count( $shortcodes ) ) {
			if ( ! get_user_meta( $user_id, '_tutor_h5p_lesson_completed_' . $lesson_id, true ) ) {
				$is_complete = false;
			}
		}

		return $is_complete;
	}

	/**
	 * Provide H5P content list for lesson.
	 *
	 * @since 3.0.0
	 *
	 * @return void
	 */
	public function obtain_lesson_content_list() {

		tutor_utils()->checking_nonce();

		$search_filter = Input::post( 'search_filter', null, INPUT::TYPE_STRING );
		$h5p_contents  = Utils::get_h5p_contents( null, $search_filter );

		$filtered_h5p_contents = array();
		$filtered_contents     = array( 'Personality Quiz' );

		if ( tutor_utils()->get_option( 'disable_complete_lesson_button' ) ) {
			array_push( $filtered_contents, 'Interactive Book' );
		}

		// The following content type support are not available for lesson for now.
		foreach ( $h5p_contents as $content ) {
			if ( ! in_array( $content->content_type, $filtered_contents, true ) ) {
				array_push( $filtered_h5p_contents, $content );
			}
		}

		wp_send_json_success( array( 'output' => $filtered_h5p_contents ) );
	}

	/**
	 * Save tutor H5P lesson xAPI statement on database
	 *
	 * @since 3.0.0
	 *
	 * @return mixed
	 */
	public function save_h5p_lesson_xAPI_statement() {
		global $wpdb;
		tutor_utils()->checking_nonce();

		$topic_id   = Input::post( 'topic_id', 0, INPUT::TYPE_INT );
		$lesson_id  = Input::post( 'lesson_id', 0, INPUT::TYPE_INT );
		$content_id = Input::post( 'content_id', 0, INPUT::TYPE_INT );
		$course_id  = Input::post( 'course_id', 0, INPUT::TYPE_INT );
		$instructor = tutor_utils()->get_instructors_by_course( $course_id );
		$user_id    = get_current_user_id();
		$statement  = Input::post( 'statement' );

		if ( 0 === $topic_id && 0 === $lesson_id && 0 === $course_id && 0 === $content_id ) {
			wp_send_json_error();
		}

		$lesson_xapi_statement = array(
			'content_id'    => $content_id,
			'user_id'       => $user_id,
			'created_at'    => current_time( 'mysql', true ),
			'instructor_id' => isset( $instructor[0] ) ? $instructor[0]->ID : 0,
		);

		$statement = json_decode( $statement );

		// Check if statement has verb.
		if ( isset( $statement->verb ) ) {
			$verb = $statement->verb;

			if ( isset( $verb->id ) ) {
				$verb_id                          = $verb->id;
				$lesson_xapi_statement['verb_id'] = $verb_id;
			}

			// The verb display text is placed on the display property.
			if ( isset( $verb->display ) ) {

				$display                       = $verb->display;
				$lesson_xapi_statement['verb'] = Utils::get_xpi_locale_property( $display );

			}
		}

		// Check if statement has activity.
		if ( isset( $statement->object ) ) {

			$object = $statement->object;

			// Activity definition property contains the activity details.
			if ( isset( $object->definition ) ) {
				$definition = $object->definition;

				if ( isset( $definition->name ) ) {
					$lesson_xapi_statement['activity_name'] = Utils::get_xpi_locale_property( $definition->name );
				} elseif ( isset( $definition->description ) ) {
						$lesson_xapi_statement['activity_name'] = Utils::get_xpi_locale_property( $definition->description );
				} elseif ( isset( $statement->context ) ) {
					$context                                = $statement->context;
					$contextActivities                      = isset( $context->contextActivities ) ? $context->contextActivities : null;
					$category                               = isset( $contextActivities->category ) ? $contextActivities->category : null;
					$library_id                             = is_array( $category ) && count( $category ) ? $category[0]->id : null;
					$library_name                           = isset( $library_id ) ? str_replace( 'http://h5p.org/libraries/', '', $library_id ) : null;
					$lesson_xapi_statement['activity_name'] = isset( $library_name ) ? $library_name : '';
				}
				$lesson_xapi_statement['activity_description'] = isset( $definition->description ) ? Utils::get_xpi_locale_property( $definition->description ) : '';

				if ( is_array( $definition->correctResponsesPattern ) && count( $definition->correctResponsesPattern ) ) {
					$lesson_xapi_statement['activity_correct_response_pattern'] = maybe_serialize( $definition->correctResponsesPattern );
				}

				// Choices are the available choices provided on the H5P content.
				$choices = $definition->choices ?? $definition->source;
				if ( is_array( $choices ) && count( $choices ) ) {
					$lesson_xapi_statement['activity_choices'] = maybe_serialize( $choices );
				}

				// Target are the possible answer for the H5P content.
				$target = $definition->target;
				if ( is_array( $target ) && count( $target ) ) {
					$lesson_xapi_statement['activity_target'] = maybe_serialize( $target );
				}

				$lesson_xapi_statement['activity_interaction_type'] = isset( $definition->interactionType ) ? $definition->interactionType : '';
			}
		}

		// Check if result is provided with the statement.
		if ( isset( $statement->result ) ) {
			$result = $statement->result;
			if ( isset( $result->score ) ) {
				$score                                        = $result->score;
				$lesson_xapi_statement['result_max_score']    = $score->max;
				$lesson_xapi_statement['result_min_score']    = $score->min;
				$lesson_xapi_statement['result_raw_score']    = $score->raw;
				$lesson_xapi_statement['result_scaled_score'] = $score->scaled;
			}

			$lesson_xapi_statement['result_completion'] = $result->completion;
			$lesson_xapi_statement['result_success']    = $result->success;
			$lesson_xapi_statement['result_response']   = $result->response;
			$lesson_xapi_statement['result_duration']   = $result->duration;
		}

		Utils::save_tutor_h5p_statement( $lesson_xapi_statement );

		$lesson_xapi_statement['course_id'] = $course_id;
		$lesson_xapi_statement['lesson_id'] = $lesson_id;
		$lesson_xapi_statement['topic_id']  = $topic_id;

		$is_inserted = $wpdb->insert( "{$wpdb->prefix}tutor_h5p_lesson_statement", $lesson_xapi_statement );

		if ( $is_inserted ) {
			wp_send_json_success();
		}
	}

	/**
	 * Delete H5P lesson statements by course id or lesson id.
	 *
	 * @since 3.0.0
	 *
	 * @param int $course_id the course id.
	 * @param int $lesson_id the lesson id.
	 * @return void
	 */
	public function delete_h5p_lesson_statements_by_id( $course_id, $lesson_id ) {
		global $wpdb;

		$course_id = (int) filter_var( $course_id, FILTER_SANITIZE_NUMBER_INT );
		$lesson_id = (int) filter_var( $lesson_id, FILTER_SANITIZE_NUMBER_INT );

		$where_clause = '';

		if ( 0 !== $course_id ) {
			$where_clause = "WHERE course_id IN ({$course_id})";
		}
		if ( 0 !== $lesson_id ) {
			$where_clause = "WHERE lesson_id IN ({$lesson_id})";
		}

		$delete_statements = $wpdb->query(
			"DELETE FROM {$wpdb->prefix}tutor_h5p_lesson_statement {$where_clause}"
		);
	}


	/**
	 * Count all the H5P lesson statements.
	 *
	 * @since 3.0.0
	 *
	 * @param string $search search filter to query with.
	 * @param string $date date filter to query with.
	 * @param string $filter the main filter for querying.
	 *
	 * @return int
	 */
	public static function count_h5p_lesson_statements( $search = '', $date = '', $filter = '' ) {
		global $wpdb;

		$search_query = sanitize_text_field( $search );
		$date_query   = sanitize_text_field( $date );
		$filter_query = sanitize_text_field( $filter );

		if ( '' !== $search_query ) {
			$search_query = '%' . $wpdb->esc_like( $search_query ) . '%';
			$search       = $wpdb->prepare( ' AND (verb LIKE %s OR activity_name LIKE %s OR user_id LIKE %s)', $search_query, $search_query, $search_query );
		}

		if ( '' !== $date ) {
			$date_query = tutor_get_formated_date( 'Y-m-d', $date );
			$date       = $wpdb->prepare( ' AND DATE(created_at) = %s', $date_query );
		}

		if ( '' !== $filter_query ) {
			$filter = $wpdb->prepare( ' AND course_id = %d', $filter_query );
		}

		$statement_count = TutorCache::get( self::TUTOR_H5P_LESSON_STATEMENT_COUNT );

		if ( false === $statement_count ) {
			TutorCache::set(
				self::TUTOR_H5P_LESSON_STATEMENT_COUNT,
				// phpcs:disable
				$statement_count = $wpdb->get_var(
					$wpdb->prepare(
						"SELECT COUNT(statement_id) FROM {$wpdb->prefix}tutor_h5p_lesson_statement
						WHERE 1=1 AND instructor_id = %d {$filter} {$search} {$date}",
						get_current_user_id()
					)
				)
				// phpcs:enable
			);
		}

		return (int) $statement_count;
	}


	/**
	 * Get all the tutor H5P lesson statements.
	 *
	 * @since 3.0.0
	 *
	 * @param string $limit the row limit.
	 * @param string $offset the row offset.
	 * @param string $order the sorting order.
	 * @param string $search the search value.
	 * @param string $date the date value to search for.
	 * @param string $filter the main filter to query for.
	 *
	 * @return array
	 */
	public static function get_h5p_lesson_statements( $limit = '', $offset = '', $order = 'DESC', $search = '', $date = '', $filter = '' ) {
		global $wpdb;

		$limit_query  = sanitize_text_field( $limit );
		$offset_query = sanitize_text_field( $offset );
		$order_query  = sanitize_sql_orderby( $order );
		$search_query = sanitize_text_field( $search );
		$date_query   = sanitize_text_field( $date );
		$filter_query = sanitize_text_field( $filter );

		if ( '' !== $limit_query ) {
			$limit = ' LIMIT %d';
		}

		if ( '' !== $offset_query ) {
			$offset = ' OFFSET %d';
		}

		if ( $order_query ) {
			$order = " ORDER BY created_at {$order_query}";
		}

		if ( '' !== $search_query ) {
			$search_query = '%' . $wpdb->esc_like( $search_query ) . '%';
			$search       = $wpdb->prepare( ' AND (verb LIKE %s OR activity_name LIKE %s OR user_id LIKE %s)', $search_query, $search_query, $search_query );
		}

		if ( '' !== $date ) {
			$date_query = tutor_get_formated_date( 'Y-m-d', $date );
			$date       = $wpdb->prepare( ' AND DATE(created_at) = %s', $date_query );
		}

		if ( '' !== $filter_query ) {
			$filter = $wpdb->prepare( ' AND course_id = %d', $filter_query );
		}

		$lesson_statements = TutorCache::get( self::TUTOR_H5P_LESSON_STATEMENT_LIST );

		if ( false === $lesson_statements ) {
			TutorCache::set(
				self::TUTOR_H5P_LESSON_STATEMENT_LIST,
				// phpcs:disable
				$lesson_statements = $wpdb->get_results(
					$wpdb->prepare(
						"SELECT * FROM {$wpdb->prefix}tutor_h5p_lesson_statement
            			WHERE 1=1 AND instructor_id = %d {$filter} {$search} {$date} {$order}
            			{$limit}
           				{$offset}",
						get_current_user_id(),
						$limit_query,
						$offset_query,
					)
				)
				// phpcs:enable
			);
		}

		return $lesson_statements;
	}
}