gocodebox/lifterlms-rest

View on GitHub
includes/server/class-llms-rest-webhooks-controller.php

Summary

Maintainability
A
3 hrs
Test Coverage
A
97%
<?php
/**
 * REST Controller for Webhooks.
 *
 * @package  LifterLMS_REST/Classes
 *
 * @since 1.0.0-beta.3
 * @version 1.0.0-beta.27
 */

defined( 'ABSPATH' ) || exit;

/**
 * LLMS_REST_Webhooks_Controller class.
 *
 * @since 1.0.0-beta.3
 */
class LLMS_REST_Webhooks_Controller extends LLMS_REST_Controller {

    /**
     * Route base.
     *
     * @var string
     */
    protected $rest_base = 'webhooks';

    /**
     * Schema properties available for ordering the collection.
     *
     * @var string[]
     */
    protected $orderby_properties = array(
        'id',
        'name',
        'created',
        'updated',
    );

    /**
     * Check if the authenticated user can perform the request action.
     *
     * @since 1.0.0-beta.3
     *
     * @return boolean
     */
    protected function check_permissions() {
        return current_user_can( 'manage_lifterlms_webhooks' ) ? true : llms_rest_authorization_required_error();
    }

    /**
     * Check if a given request has access to create an item.
     *
     * @param  WP_REST_Request $request Full details about the request.
     * @return WP_Error|boolean
     */
    public function create_item_permissions_check( $request ) {
        return $this->check_permissions();
    }

    /**
     * Insert the prepared data into the database.
     *
     * @since 1.0.0-beta.3
     *
     * @param array           $prepared Prepared item data.
     * @param WP_REST_Request $request  Request object.
     * @return obj Object Instance of object from $this->get_object().
     */
    protected function create_object( $prepared, $request ) {

        return LLMS_REST_API()->webhooks()->create( $prepared );

    }

    /**
     * Check if a given request has access to delete an item.
     *
     * @since 1.0.0-beta.3
     *
     * @param  WP_REST_Request $request Full details about the request.
     * @return bool|WP_Error
     */
    public function delete_item_permissions_check( $request ) {
        return $this->check_permissions();
    }

    /**
     * Delete the object.
     *
     * Note: we do not return 404s when the resource to delete cannot be found. We assume it's already been deleted and respond with 204.
     * Errors returned by this method should be any error other than a 404!
     *
     * @since 1.0.0-beta.3
     *
     * @param obj             $object  Instance of the object from $this->get_object().
     * @param WP_REST_Request $request Request object.
     * @return true|WP_Error true when the object is removed, WP_Error on failure.
     */
    protected function delete_object( $object, $request ) {

        return $object->delete();

    }

    /**
     * Retrieves the query params for the objects collection.
     *
     * @since 1.0.0-beta.3
     *
     * @return array Collection parameters.
     */
    public function get_collection_params() {

        $params = parent::get_collection_params();

        $params['status'] = array(
            'description' => __( 'Include only webhooks matching a specific status.', 'lifterlms' ),
            'type'        => 'string',
            'enum'        => array_keys( LLMS_REST_API()->webhooks()->get_statuses() ),
        );

        return $params;

    }

    /**
     * Get the Webhook's schema, conforming to JSON Schema.
     *
     * @since 1.0.0-beta.27
     *
     * @return array
     */
    protected function get_item_schema_base() {

        return array(
            '$schema'    => 'http://json-schema.org/draft-04/schema#',
            'title'      => 'webhook',
            'type'       => 'object',
            'properties' => array(
                'id'           => array(
                    'description' => __( 'Webhook ID.', 'lifterlms' ),
                    'type'        => 'integer',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'name'         => array(
                    'description' => __( 'Friendly, human-readable name or description.', 'lifterlms' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                    'arg_options' => array(
                        'sanitize_callback' => 'sanitize_text_field',
                    ),
                ),
                'status'       => array(
                    'description' => __( 'The status of the webhook.', 'lifterlms' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                    'enum'        => array_keys( LLMS_REST_API()->webhooks()->get_statuses() ),
                    'default'     => 'disabled',
                ),
                'topic'        => array(
                    'description' => __( 'The webhook topic', 'lifterlms' ),
                    'type'        => 'string',
                    'required'    => true,
                    'context'     => array( 'view', 'edit' ),
                    'arg_options' => array(
                        'validate_callback' => array( LLMS_REST_API()->webhooks(), 'is_topic_valid' ),
                    ),
                ),
                'delivery_url' => array(
                    'description' => __( 'The webhook payload delivery URL.', 'lifterlms' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                    'required'    => true,
                ),
                'secret'       => array(
                    'description' => __( 'An optional secret key used to generate the delivery signature.', 'lifterlms' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                ),
                'created'      => array(
                    'description' => __( 'Creation date. Format: Y-m-d H:i:s', 'lifterlms' ),
                    'type'        => 'string',
                    'format'      => 'date-time',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'updated'      => array(
                    'description' => __( 'Date last modified. Format: Y-m-d H:i:s', 'lifterlms' ),
                    'type'        => 'string',
                    'format'      => 'date-time',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'resource'     => array(
                    'description' => __( 'The parsed resource from the `topic`.', 'lifterlms' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'event'        => array(
                    'description' => __( 'The parsed event from the `topic`.', 'lifterlms' ),
                    'type'        => 'string',
                    'context'     => array( 'view', 'edit' ),
                    'readonly'    => true,
                ),
                'hooks'        => array(
                    'description' => __( 'List of WordPress action hook associated with the webhook.', 'lifterlms' ),
                    'type'        => 'array',
                    'items'       => array(
                        'type' => 'string',
                    ),
                    'context'     => array( 'view', 'edit' ),
                ),
            ),
        );

    }

    /**
     * Check if a given request has access to read an item.
     *
     * @since 1.0.0-beta.3
     *
     * @param  WP_REST_Request $request Full details about the request.
     * @return WP_Error|boolean
     */
    public function get_item_permissions_check( $request ) {
        return $this->check_permissions();
    }

    /**
     * Check if a given request has access to read items.
     *
     * @since 1.0.0-beta.3
     *
     * @param  WP_REST_Request $request Full details about the request.
     * @return WP_Error|boolean
     */
    public function get_items_permissions_check( $request ) {
        return $this->check_permissions();
    }

    /**
     * Retrieve pagination information from an objects query.
     *
     * @since 1.0.0-beta.3
     * @since 1.0.0-beta-24 Fixed access of protected LLMS_Abstract_Query properties.
     *
     * @param LLMS_REST_Webhooks_Query $query    Objects query result returned by {@see LLMS_REST_Webhooks_Controller::get_objects_query()}.
     * @param array                    $prepared Array of collection arguments.
     * @param WP_REST_Request          $request  Request object.
     * @return array {
     *     Array of pagination information.
     *
     *     @type int $current_page  Current page number.
     *     @type int $total_results Total number of results.
     *     @type int $total_pages   Total number of results pages.
     * }
     */
    protected function get_pagination_data_from_query( $query, $prepared, $request ) {

        return array(
            'current_page'  => $query->get( 'page' ),
            'total_results' => $query->get_found_results(),
            'total_pages'   => $query->get_max_pages(),
        );

    }

    /**
     * Retrieve An Webhook object by ID.
     *
     * @since 1.0.0-beta.3
     *
     * @param int  $id      Webhook ID.
     * @param bool $hydrate If true, pulls all key data from the database on instantiation.
     * @return WP_Error|LLMS_REST_API_Key
     */
    protected function get_object( $id, $hydrate = true ) {

        if ( ! is_numeric( $id ) ) {
            $id = $this->get_object_id( $id );
        }

        $key = LLMS_REST_API()->webhooks()->get( $id, $hydrate );
        return $key ? $key : llms_rest_not_found_error();

    }

    /**
     * Retrieve a query object based on arguments from a `get_items()` (collection) request.
     *
     * @since 1.0.0-beta.3
     *
     * @param array           $prepared Array of collection arguments.
     * @param WP_REST_Request $request  Request object.
     * @return LLMS_REST_Webhooks_Query
     */
    protected function get_objects_query( $prepared, $request ) {

        return new LLMS_REST_Webhooks_Query( $prepared );

    }

    /**
     * Retrieve an array of objects from the result of $this->get_objects_query().
     *
     * @since 1.0.0-beta.3
     *
     * @param obj $query Objects query result.
     * @return obj[]
     */
    protected function get_objects_from_query( $query ) {

        return $query->get_results();

    }

    /**
     * Map request keys to database keys for insertion.
     *
     * Array keys are the request fields (as defined in the schema) and
     * array values are the database fields.
     *
     * @since 1.0.0-beta.3
     *
     * @return array
     */
    protected function map_schema_to_database() {

        $map = parent::map_schema_to_database();

        // Not inserted/read via database calls.
        unset( $map['resource'], $map['event'], $map['hooks'] );

        return $map;

    }

    /**
     * Prepare an object for response.
     *
     * @since 1.0.0-beta.3
     *
     * @param LLMS_Abstract_User_Data $object  User object.
     * @param WP_REST_Request         $request Request object.
     * @return array
     */
    protected function prepare_object_for_response( $object, $request ) {

        $prepared = parent::prepare_object_for_response( $object, $request );

        $prepared['id']       = absint( $prepared['id'] );
        $prepared['resource'] = $object->get_resource();
        $prepared['event']    = $object->get_event();
        $prepared['hooks']    = $object->get_hooks();
        $prepared['created']  = mysql_to_rfc3339( $prepared['created'] );
        $prepared['updated']  = mysql_to_rfc3339( $prepared['updated'] );

        return $prepared;

    }

    /**
     * Update a Webhook.
     *
     * @since 1.0.0-beta.3
     * @since 1.0.0-beta.27 Handle custom rest fields registered via `register_rest_field()`.
     *
     * @param WP_REST_Request $request Request object.
     * @return WP_Error|WP_REST_Response
     */
    public function update_item( $request ) {

        $prepared = $this->prepare_item_for_database( $request );
        // Exclude additional fields registered via `register_rest_field()`.
        $prepared = array_diff_key( $prepared, $this->get_additional_fields() );
        $webhook  = LLMS_REST_API()->webhooks()->update( $prepared );
        if ( is_wp_error( $request ) ) {
            $request->add_data( array( 'status' => 400 ) );
            return $request;
        }

        // Fields registered via `register_rest_field()`.
        $fields_update = $this->update_additional_fields_for_object( $webhook, $request );
        if ( is_wp_error( $fields_update ) ) {
            return $fields_update;
        }

        $request->set_param( 'context', 'edit' );

        $response = $this->prepare_item_for_response( $webhook, $request );

        return $response;

    }

    /**
     * Check if a given request has access to update an item.
     *
     * @since 1.0.0-beta.3
     *
     * @param  WP_REST_Request $request Full details about the request.
     * @return WP_Error|boolean
     */
    public function update_item_permissions_check( $request ) {
        return $this->check_permissions();
    }

}