decode_json_response( $this->make_authenticated_request( sprintf( '/projects/%s', $project_id ) ) ); } /** * Retrieve information about a particular document. * * @param string $project_id The project's UUID. * @param string $document_id The document's UUID. * @return stdClass|WP_Error The response from Airstory\API::make_authenticated_request(). */ public function get_document( $project_id, $document_id ) { return $this->decode_json_response( $this->make_authenticated_request( sprintf( '/projects/%s/documents/%s', $project_id, $document_id ) ) ); } /** * Retrieve the rendered content for a given document. * * Note that this method will return the entire response, which includes a declaration * and supporting elements. These can be filtered via Airstory\Core\get_body_contents(). * * @param string $project_id The project's UUID. * @param string $document_id The document's UUID. * @return string|WP_Error The response from Airstory\API::make_authenticated_request(). */ public function get_document_content( $project_id, $document_id ) { $request = $this->make_authenticated_request( sprintf( '/projects/%s/documents/%s/content', $project_id, $document_id ) ); return wp_remote_retrieve_body( $request ); } /** * Retrieve basic information about the current user. * * @return stdClass|WP_Error The response from Airstory\API::make_authenticated_request(). */ public function get_user() { return $this->decode_json_response( $this->make_authenticated_request( '/user' ) ); } /** * Create a new target for the given user. * * @param string $email The user's Airstory email address. * @param array $target { * The target consists of three properties, all of which are required. * * @var int $identifier The WordPress user ID. The API would also accept a username, but this * should be something immutable. * @var string $name The WordPress site name. * @var string $url The webhook URL for this site. * } * @return string|WP_Error Either the UUID of the newly-created target within Airstory, or a * WP_Error should anything go awry. */ public function post_target( $email, $target ) { $response = $this->make_authenticated_request( sprintf( '/users/%s/targets', $email ), array( 'method' => 'POST', 'headers' => array( 'content-type' => 'application/json', ), 'body' => wp_json_encode( $target ), ) ); if ( is_wp_error( $response ) ) { return $response; } if ( empty( $response['headers']['link'] ) ) { return new WP_Error( 'airstory-link', __( 'Invalid response from Airstory when connecting account', 'airstory' ), $response ); } return sanitize_text_field( $response['headers']['link'] ); } /** * Update an existing target within Airstory. * * @param string $email The user's Airstory email address. * @param string $connection_id The target connection's UUID. * @param array $target Updated target properties. For the full list, @see API::post_target(). * @return bool|WP_Error Either a boolean TRUE or a WP_Error should anything go awry. */ public function put_target( $email, $connection_id, $target ) { $response = $this->make_authenticated_request( sprintf( '/users/%s/targets/%s', $email, $connection_id ), array( 'method' => 'PUT', 'headers' => array( 'content-type' => 'application/json', ), 'body' => wp_json_encode( $target ), ) ); if ( is_wp_error( $response ) ) { return $response; } if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { return new WP_Error( 'airstory-link', __( 'Invalid response from Airstory when updating account', 'airstory' ), $response ); } return true; } /** * Remove an existing target from within Airstory. * * @param string $email The user's Airstory email address. * @param string $target The target ID. * @return string|WP_Error Either the UUID of the now-destroyed target within Airstory, or a * a WP_Error should anything go awry. */ public function delete_target( $email, $target ) { $response = $this->make_authenticated_request( sprintf( '/users/%s/targets/%s', $email, $target ), array( 'method' => 'DELETE', ) ); if ( is_wp_error( $response ) ) { return $response; } return $target; } /** * Explicitly set the Airstory user token. * * This can be used to run a request as a given user, since get_credentials() will return the * $this->token property if it's already set. * * @param string|WP_Error $token The Airstory user token to use, or a WP_Error object that may * have been returned by Credentials\get_token(). * @return string The token that has been set. If $token was a valid string, this will just be * the value of $token. */ public function set_token( $token ) { if ( is_wp_error( $token ) ) { $token = ''; } $this->token = (string) $token; return $this->token; } /** * Retrieve the credentials for the currently logged-in user. * * @return string The bearer token to be passed with API requests. */ protected function get_credentials() { /* * If someone's attempted to assign a token via set_token(), this value will be an empty string * instead of NULL. This should be enough to indicate we may not necessarily want to default to * the current user. */ if ( null !== $this->token ) { return $this->token; } return $this->set_token( Credentials\get_token( wp_get_current_user()->ID ) ); } /** * Make an authenticated request to the Airstory API. * * @param string $path The API endpoint, relative to the API_BASE constant. The path should begin * with a leading slash. * @param array $args { * Optional. Additional arguments to pass to wp_remote_request(), which will be merged with * defaults. For a full list of available settings, @see wp_remote_request(). * * @var string $method The HTTP method (verb) to use. Default is "GET". * } * @return array|WP_Error If everything comes back okay, the response array. Otherwise, a * WP_Error object will be given with an explanation of what went wrong. */ protected function make_authenticated_request( $path, $args = array() ) { $token = $this->get_credentials(); // Don't even attempt the request if we don't have a token. if ( empty( $token ) ) { return new WP_Error( 'airstory-missing-credentials', __( 'An Airstory token is required to make this request', 'airstory' ) ); } // Begin assembling the URL and arguments. $url = sprintf( '%s%s', self::API_BASE, $path ); $args = wp_parse_args( $args, array( 'method' => 'GET', 'headers' => array(), ) ); // Explicitly append the Authorization header, which is required by Airstory. $args['headers']['Authorization'] = sprintf( 'Bearer=%s', $token ); // Assemble the request, along with an Authorization header. return wp_remote_request( $url, $args ); } /** * For requests that return JSON (e.g. anything except getting the generated HTML), JSON-decode * the API response and return it. * * @param array $response The HTTP response array. * @return stdClass|WP_Error If JSON-decoded successfully, a stdClass representation of the * response body, otherwise a WP_Error object. */ protected function decode_json_response( $response ) { $result = json_decode( wp_remote_retrieve_body( $response ), false ); // Something went wrong decoding the JSON. if ( empty( $result ) ) { return new WP_Error( 'airstory-invalid-json', __( 'The request did not return valid JSON', 'airstory' ), $response ); } return $result; } }