Tribe__Tickets_Plus__REST__V1__Endpoints__QR


Source

File: src/Tribe/REST/V1/Endpoints/QR.php

class Tribe__Tickets_Plus__REST__V1__Endpoints__QR
extends Tribe__Tickets__REST__V1__Endpoints__Base
implements Tribe__REST__Endpoints__READ_Endpoint_Interface, Tribe__Documentation__Swagger__Provider_Interface {

	/**
	 * @var Tribe__REST__Main
	 */
	protected $main;

	/**
	 * @var WP_REST_Request
	 */
	protected $serving;

	/**
	 * @var Tribe__Tickets__REST__Interfaces__Post_Repository
	 */
	protected $post_repository;

	/**
	 * @var Tribe__Tickets__REST__V1__Validator__Interface
	 */
	protected $validator;

	/**
	 * Get attendee by id
	 *
	 * @since 4.7.5
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return mixed|void|WP_Error|WP_REST_Response
	 */
	public function get( WP_REST_Request $request ) {
		$this->serving = $request;

		$ticket = get_post( $request['id'] );
		$ticket_type = tribe( 'tickets.data_api' )->detect_by_id( $request['id'] );

		$cap = get_post_type_object( $ticket_type['post_type'] )->cap->read_post;
		if ( ! ( 'publish' === $ticket->post_status || current_user_can( $cap, $request['id'] ) ) ) {
			$message = $this->messages->get_message( 'ticket-not-accessible' );

			return new WP_Error( 'ticket-not-accessible', $message, array( 'status' => 403 ) );
		}

		$data = $this->post_repository->get_qr_data( $request['id'], 'single' );

		/**
		 * Filters the data that will be returned for a single qr ticket request.
		 *
		 * @since 4.5.13
		 *
		 * @param array           $data    The retrieved data.
		 * @param WP_REST_Request $request The original request.
		 */
		$data = apply_filters( 'tribe_tickets_plus_rest_qr_data', $data, $request );

		return is_wp_error( $data ) ? $data : new WP_REST_Response( $data );
	}

	/**
	 * Returns an array in the format used by Swagger 2.0.
	 *
	 * While the structure must conform to that used by v2.0 of Swagger the structure can be that of a full document
	 * or that of a document part.
	 * The intelligence lies in the "gatherer" of informations rather than in the single "providers" implementing this
	 * interface.
	 *
	 * @since 4.7.5
	 *
	 * @link http://swagger.io/
	 *
	 * @return array An array description of a Swagger supported component.
	 */
	public function get_documentation() {
		$POST_defaults = array(
			'in'      => 'formData',
			'default' => '',
			'type'    => 'string',
		);
		$post_args     = array_merge( $this->READ_args(), $this->CHECK_IN_args() );

		return array(
			'post' => array(
				'consumes'   => array( 'application/x-www-form-urlencoded' ),
				'parameters' => $this->swaggerize_args( $post_args, $POST_defaults ),
				'responses'  => array(
					'201' => array(
						'description' => __( 'Returns successful check in', 'event-tickets-plus' ),
						'schema'      => array(
							'$ref' => '#/definitions/Ticket',
						),
					),
					'400' => array(
						'description' => __( 'A required parameter is missing or an input parameter is in the wrong format', 'event-tickets-plus' ),
					),
					'403' => array(
						'description' => __( 'The ticket is already checked in', 'event-tickets-plus' ),
					),
				),
			),
		);
	}

	/**
	 * Provides the content of the `args` array to register the endpoint support for GET requests.
	 *
	 * @since 4.7.5
	 *
	 * @return array
	 */
	public function READ_args() {
		return array(
			'id' => array(
				'in'                => 'path',
				'type'              => 'integer',
				'description'       => __( 'The ticket id.', 'event-tickets-plus' ),
				'required'          => true,
				'validate_callback' => array( $this->validator, 'is_ticket_id' ),
			),
		);
	}

	/**
	 * Returns the content of the `args` array that should be used to register the endpoint
	 * with the `register_rest_route` function.
	 *
	 * @since 4.7.5
	 *
	 * @return array
	 */
	public function CHECK_IN_args() {
		return array(
			// QR fields
			'api_key'       => array(
				'required'          => true,
				'validate_callback' => array( $this->validator, 'is_string' ),
				'type'              => 'string',
				'description'       => __( 'The API key to authorize check in.', 'event-tickets-plus' ),
			),
			'ticket_id'     => array(
				'required'          => true,
				'validate_callback' => array( $this->validator, 'is_numeric' ),
				'type'              => 'string',
				'description'       => __( 'The ID of the ticket to check in.', 'event-tickets-plus' ),
			),
			'security_code'     => array(
				'required'          => true,
				'validate_callback' => array( $this->validator, 'is_string' ),
				'type'              => 'string',
				'description'       => __( 'The security code of the ticket to verify for check in.', 'event-tickets-plus' ),
			),
		);
	}

	/**
	 * Check in attendee
	 *
	 * @since 4.7.5
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_REST_Response
	 */
	public function check_in( WP_REST_Request $request ) {

		$this->serving = $request;

		$qr_arr = $this->prepare_qr_arr( $request );

		if ( is_wp_error( $qr_arr ) ) {
			$response = new WP_REST_Response( $qr_arr );
			$response->set_status( 400 );

			return $response;
		}

		$api_check = $this->has_api( $qr_arr );

		// Check all the data we need is there
		if ( empty( $api_check ) || empty( $qr_arr['ticket_id'] ) ) {
			$response = new WP_REST_Response( $qr_arr );
			$response->set_status( 400 );

			return $response;
		}

		$ticket_id = (int) $qr_arr['ticket_id'];
		$security_code = (string) $qr_arr['security_code'];
		$service_provider = tribe( 'tickets.data_api' )->get_ticket_provider( $ticket_id );
		if ( empty( $service_provider->security_code ) || (  $security_code !== get_post_meta( $ticket_id, $service_provider->security_code, true )  )   ) {
			$response = new WP_REST_Response( array( 'msg' => __( 'Security code is not valid!', 'event-tickets-plus' ) ) );
			$response->set_status( 403 );

			return $response;
		}

		// add check attendee data
		$attendee = $service_provider->get_attendees_by_id( $ticket_id );
		$attendee = reset( $attendee );
		if ( ! is_array( $attendee ) ) {
			$response = new WP_REST_Response( array( 'msg' => __('An attendee is not found with this ID.', 'event-tickets-plus' ) ) );
			$response->set_status( 403 );

			return $response;
		}

		// add check for completed attendee status
		$complete_statuses = (array) tribe( 'tickets.status' )->get_completed_status_by_provider_name( $service_provider );
		if ( ! in_array( $attendee['order_status'], $complete_statuses ) ) {
			$response = new WP_REST_Response( array( 'msg' => __( 'This attendee\'s ticket is not authorized to be Checked in', 'event-tickets-plus' ) ) );
			$response->set_status( 403 );

			return $response;
		}

		// check if attendee is checked in
		$checked_status = get_post_meta( $ticket_id, '_tribe_qr_status', true );
		if ( $checked_status ) {
			$response = new WP_REST_Response( array( 'msg' => __( 'Already checked in!', 'event-tickets-plus' ) ) );
			$response->set_status( 403 );

			return $response;
		}

		$checked = $this->_check_in( $ticket_id, $service_provider );
		if ( ! $checked ) {
			$msg_arr = array(
				'msg'             => __( 'Ticket not checked in!', 'event-tickets-plus' ),
				'tribe_qr_status' => get_post_meta( $ticket_id, '_tribe_qr_status', 1 ),
			);
			$result  = array_merge( $msg_arr, $qr_arr );

			$response = new WP_REST_Response( $result );
			$response->set_status( 403 );

			return $response;
		}

		$response = new WP_REST_Response( array( 'msg' => __( 'Checked In!', 'event-tickets-plus' ) ) );
		$response->set_status( 201 );

		return $response;
	}

	/**
	 * Check if API is present and matches key is settings
	 *
	 * @since 4.7.5
	 *
	 * @param $qr_arr
	 *
	 * @return bool
	 */
	public function has_api( $qr_arr ) {

		if ( empty( $qr_arr['api_key'] ) ) {
			return false;
		}

		$tec_options = Tribe__Settings_Manager::get_options();
		if ( ! is_array( $tec_options ) ) {
			return false;
		}

		if ( $tec_options['tickets-plus-qr-options-api-key'] !== esc_attr( $qr_arr['api_key'] ) ) {
			return false;
		}

		return true;

	}

	/**
	 * Setup array of variables for check in
	 *
	 * @since 4.7.5
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return array|mixed|void
	 */
	protected function prepare_qr_arr( WP_REST_Request $request ) {

		$qr_arr = array(
			'api_key'       => $request['api_key'],
			'ticket_id'     => $request['ticket_id'],
			'security_code' => $request['security_code'],
		);

		/**
		 * Allow filtering of $postarr data with additional $request arguments.
		 *
		 * @param array           $qr_arr  Post array used for check in
		 * @param WP_REST_Request $request REST request object
		 *
		 * @since 4.7.5
		 */
		$qr_arr = apply_filters( 'tribe_tickets_plus_rest_qr_prepare_qr_arr', $qr_arr, $request );

		return $qr_arr;
	}

	/**
	 * Check in attendee and on first success return
	 *
	 * @since 4.7.5
	 *
	 * @param $ticket_id
	 *
	 * @return boolean
	 */
	private function _check_in( $attendee_id, $service_provider ) {

		if ( empty( $service_provider ) ) {
			return false;
		}

		// set parameter to true for the QR app - it is false for the original url so that the message displays
		$success = $service_provider->checkin( $attendee_id, true );
		if ( $success ) {
			return $success;
		}

		return false;
	}
}


Top ↑

Methods

  • check_in — Check in attendee
  • CHECK_IN_args — Returns the content of the `args` array that should be used to register the endpoint with the `register_rest_route` function.
  • get — Get attendee by id
  • get_documentation — Returns an array in the format used by Swagger 2.0.
  • has_api — Check if API is present and matches key is settings
  • is_tec_event_happening_now — Check if an event is on date and time, in order to check-in QR codes.
  • READ_args — Provides the content of the `args` array to register the endpoint support for GET requests.
  • should_checkin_qr_events_happening_now — Check if the QR codes should be only checked when the event is on date and time.