feat: add S3-compatible storage provider (MinIO, Ceph, R2, etc.)
Adds a new 'S3-Compatible Storage' provider that works with any
S3-API-compatible object storage service, including MinIO, Ceph,
Cloudflare R2, Backblaze B2, and others.
Changes:
- New provider class: classes/providers/storage/s3-compatible-provider.php
- Provider key: s3compatible
- Reads user-configured endpoint URL from settings
- Uses path-style URL access (required by most S3-compatible services)
- Supports credentials via AS3CF_S3COMPAT_ACCESS_KEY_ID /
AS3CF_S3COMPAT_SECRET_ACCESS_KEY wp-config.php constants
- Disables AWS-specific features (Block Public Access, Object Ownership)
- New provider SVG icons (s3compatible.svg, -link.svg, -round.svg)
- Registered provider in main plugin class with endpoint setting support
- Updated StorageProviderSubPage to show endpoint URL input for S3-compatible
- Built pro settings bundle with rollup (Svelte 4.2.19)
- Added package.json and updated rollup.config.mjs for pro-only builds
This commit is contained in:
87
classes/api/api-manager.php
Normal file
87
classes/api/api-manager.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API;
|
||||
|
||||
class API_Manager {
|
||||
|
||||
/**
|
||||
* @var API_Manager
|
||||
*/
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $api_endpoints;
|
||||
|
||||
/**
|
||||
* Protected constructor to prevent creating a new instance of the
|
||||
* class via the `new` operator from outside this class.
|
||||
*/
|
||||
protected function __construct() {
|
||||
$this->api_endpoints = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make this class a singleton.
|
||||
*
|
||||
* Use this instead of __construct().
|
||||
*
|
||||
* @return API_Manager
|
||||
*/
|
||||
public static function get_instance(): API_Manager {
|
||||
if ( ! isset( static::$instance ) && ! ( self::$instance instanceof API_Manager ) ) {
|
||||
static::$instance = new API_Manager();
|
||||
}
|
||||
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a named API Endpoint handler instance.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return API|null
|
||||
*/
|
||||
public function get_api_endpoint( string $name ): ?API {
|
||||
if ( ! empty( $name ) && array_key_exists( $name, $this->api_endpoints ) ) {
|
||||
return $this->api_endpoints[ $name ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of APi Endpoint paths keyed by their name.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function api_endpoints(): array {
|
||||
return array_map( function ( API $api_endpoint ) {
|
||||
return $api_endpoint->endpoint();
|
||||
}, $this->api_endpoints );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register API Endpoint handler instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @param API $api
|
||||
*/
|
||||
public function register_api_endpoint( string $name, API $api ) {
|
||||
$this->api_endpoints[ $name ] = $api;
|
||||
}
|
||||
|
||||
/**
|
||||
* As this class is a singleton it should not be clone-able.
|
||||
*/
|
||||
protected function __clone() {
|
||||
}
|
||||
|
||||
/**
|
||||
* As this class is a singleton it should not be able to be unserialized.
|
||||
*/
|
||||
public function __wakeup() {
|
||||
}
|
||||
}
|
||||
160
classes/api/api.php
Normal file
160
classes/api/api.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API;
|
||||
|
||||
use Amazon_S3_And_CloudFront;
|
||||
use WP_Error;
|
||||
use WP_HTTP_Response;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
abstract class API {
|
||||
const NAMESPACE_BASE = 'wp-offload-media';
|
||||
|
||||
/**
|
||||
* API Version that class is part of.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $version = 0;
|
||||
|
||||
/**
|
||||
* The endpoint name.
|
||||
*
|
||||
* This name will be used in the route, and where possible should be plural.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $name = '';
|
||||
|
||||
/** @var Amazon_S3_And_CloudFront */
|
||||
protected $as3cf;
|
||||
|
||||
/**
|
||||
* Initiate the API
|
||||
*
|
||||
* @param Amazon_S3_And_CloudFront $as3cf
|
||||
*/
|
||||
public function __construct( $as3cf ) {
|
||||
$this->as3cf = $as3cf;
|
||||
|
||||
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API version.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function version() {
|
||||
return static::$version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name for endpoint.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function name() {
|
||||
return static::$name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get API namespace for endpoint.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function api_namespace() {
|
||||
return self::NAMESPACE_BASE . '/v' . static::version();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get route to be appended to namespace in endpoint.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function route() {
|
||||
return '/' . static::name() . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get complete API endpoint path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function endpoint() {
|
||||
return static::api_namespace() . static::route();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get common response values for named API endpoint.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function endpoint_common_response( $name ) {
|
||||
$endpoint = $this->as3cf->get_api_manager()->get_api_endpoint( $name );
|
||||
|
||||
if ( ! empty( $endpoint ) ) {
|
||||
return $endpoint->common_response();
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Common response values for this API endpoint.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function common_response() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* All API requests must be from administrator or user granted "manage_options" capability.
|
||||
*
|
||||
* This function is used as the "permission_callback" for all routes.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check_permissions( WP_REST_Request $request ) {
|
||||
return current_user_can( 'manage_options' );
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple wrapper for rest_ensure_response to allow filters to fire before the response is sent.
|
||||
*
|
||||
* Ensures a REST response is a response object (for consistency).
|
||||
*
|
||||
* @param string $method Case-insensitive HTTP method, e.g. "get" or "post".
|
||||
* @param string $endpoint Endpoint name, e.g. "settings".
|
||||
* @param WP_Error|WP_HTTP_Response|mixed $response Response to check.
|
||||
* @param string $prefix Optional plugin prefix to be used for filter.
|
||||
*
|
||||
* @return WP_REST_Response|mixed If response generated an error, WP_Error, if response
|
||||
* is already an instance, WP_HTTP_Response, otherwise
|
||||
* returns a new WP_REST_Response instance.
|
||||
*/
|
||||
protected function rest_ensure_response( $method, $endpoint, $response, $prefix = '' ) {
|
||||
$method = empty( $method ) ? 'method' : strtolower( trim( $method ) );
|
||||
$endpoint = empty( $endpoint ) ? 'endpoint' : strtolower( trim( $endpoint ) );
|
||||
$prefix = empty( $prefix ) ? $this->as3cf->get_plugin_prefix() : strtolower( trim( $prefix ) );
|
||||
|
||||
// A specific filter is fed through a general filter to allow for granular and general filtering of responses.
|
||||
return rest_ensure_response(
|
||||
apply_filters(
|
||||
$prefix . '_api_response',
|
||||
apply_filters( $prefix . '_api_response_' . $method . '_' . $endpoint, $response )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register REST API routes.
|
||||
*/
|
||||
abstract public function register_routes();
|
||||
}
|
||||
475
classes/api/v1/buckets.php
Normal file
475
classes/api/v1/buckets.php
Normal file
@@ -0,0 +1,475 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API\V1;
|
||||
|
||||
use AS3CF_Error;
|
||||
use DeliciousBrains\WP_Offload_Media\API\API;
|
||||
use Exception;
|
||||
use WP_Error;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
class Buckets extends API {
|
||||
/** @var int */
|
||||
protected static $version = 1;
|
||||
|
||||
/** @var string */
|
||||
protected static $name = 'buckets';
|
||||
|
||||
/** @var array */
|
||||
private $error_args = array(
|
||||
'type' => 'error',
|
||||
'only_show_in_settings' => true,
|
||||
'only_show_on_tab' => 'media',
|
||||
'custom_id' => 'bucket-error',
|
||||
);
|
||||
|
||||
/**
|
||||
* Register REST API routes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'get_buckets' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array( $this, 'post_buckets' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'PUT',
|
||||
'callback' => array( $this, 'put_buckets' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST GET request and returns the current buckets, optionally for given region.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function get_buckets( WP_REST_Request $request ) {
|
||||
$data = $request->get_query_params();
|
||||
$region = empty( $data['region'] ) ? false : $data['region'];
|
||||
|
||||
$buckets = $this->as3cf->get_buckets( $region );
|
||||
|
||||
if ( is_wp_error( $buckets ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
$this->as3cf->get_storage_provider()->prepare_bucket_error( $buckets ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'get', static::name(), array() );
|
||||
}
|
||||
|
||||
$this->as3cf->notices->dismiss_notice( $this->error_args['custom_id'] );
|
||||
|
||||
return $this->rest_ensure_response( 'get', static::name(), array(
|
||||
'buckets' => $buckets,
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST POST request to create a bucket and returns saved status.
|
||||
*
|
||||
* NOTE: This does not update settings.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function post_buckets( WP_REST_Request $request ) {
|
||||
$data = $request->get_json_params();
|
||||
$bucket = empty( $data['bucket'] ) ? false : $data['bucket'];
|
||||
|
||||
// Front end validation should have caught this, it's all gone Pete Tong!
|
||||
if ( ! $bucket ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'No bucket name provided.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$bucket = $this->as3cf->check_bucket( $bucket );
|
||||
|
||||
// Front end validation should have caught this, it's all gone Pete Tong!
|
||||
if ( ! $bucket ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'Bucket name not valid.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$region = empty( $data['region'] ) ? false : $data['region'];
|
||||
|
||||
// Front end validation should have caught this, it's all gone Pete Tong!
|
||||
if ( ! $region ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'No region provided.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
// Make sure defines agree with given params.
|
||||
$defines = $this->as3cf->get_defined_settings();
|
||||
|
||||
if ( ! empty( $defines['bucket'] ) && $defines['bucket'] !== $bucket ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'Bucket name does not match defined value.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $defines['region'] ) && $defines['region'] !== $region ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'Region does not match defined value.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$result = $this->as3cf->create_bucket( $bucket, $region );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
$this->as3cf->get_storage_provider()->prepare_bucket_error( $result ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$this->as3cf->notices->dismiss_notice( $this->error_args['custom_id'] );
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array( 'saved' => $result ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST PUT request to update a bucket's properties and returns saved status.
|
||||
*
|
||||
* NOTE: This does not directly update settings.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function put_buckets( WP_REST_Request $request ) {
|
||||
$data = $request->get_json_params();
|
||||
$bucket = empty( $data['bucket'] ) ? false : $data['bucket'];
|
||||
|
||||
do_action( 'as3cf_pre_update_bucket' );
|
||||
|
||||
add_filter( 'as3cf_api_response_put_buckets', function ( $response ) {
|
||||
do_action( 'as3cf_post_update_bucket', $response['saved'] );
|
||||
|
||||
return $response;
|
||||
} );
|
||||
|
||||
// Front end validation should have caught this, it's all gone Pete Tong!
|
||||
if ( ! $bucket ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'No bucket name provided.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'put', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$bucket = $this->as3cf->check_bucket( $bucket );
|
||||
|
||||
// Front end validation should have caught this, it's all gone Pete Tong!
|
||||
if ( ! $bucket ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'Bucket name not valid.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'put', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* At present the only reason to call this endpoint is to change the
|
||||
* Block All Public Access or Object Ownership status of an S3 bucket.
|
||||
* As such, `blockPublicAccess` and `enforceObjectOwnership are required properties.
|
||||
*
|
||||
* In the future this endpoint may change to allow updating of
|
||||
* other bucket properties, and may therefore be altered to have
|
||||
* a differing set of required and optional properties depending
|
||||
* on storage provider, including region.
|
||||
*/
|
||||
|
||||
if ( ! isset( $data['blockPublicAccess'] ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'No Block All Public Access status provided.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'put', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
if ( ! isset( $data['objectOwnershipEnforced'] ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
__( 'No Enforce Object Ownership status provided.', 'amazon-s3-and-cloudfront' ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'put', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$block = ! empty( $data['blockPublicAccess'] );
|
||||
|
||||
$result = $this->block_public_access( $bucket, $block );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
$this->as3cf->get_storage_provider()->prepare_bucket_error( $result, true ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'put', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$enforce = ! empty( $data['objectOwnershipEnforced'] );
|
||||
|
||||
$result = $this->enforce_object_ownership( $bucket, $enforce );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
$this->as3cf->get_storage_provider()->prepare_bucket_error( $result, true ),
|
||||
$this->error_args
|
||||
);
|
||||
|
||||
return $this->rest_ensure_response( 'put', static::name(), array( 'saved' => false ) );
|
||||
}
|
||||
|
||||
$this->as3cf->notices->dismiss_notice( $this->error_args['custom_id'] );
|
||||
$this->as3cf->bucket_changed();
|
||||
|
||||
return $this->rest_ensure_response( 'put', static::name(), array( 'saved' => true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Block All Public Access status of given bucket.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param boolean $block
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*
|
||||
* There's no actual setting for this, the state of public access to the bucket is checked as required.
|
||||
*/
|
||||
public function block_public_access( string $bucket, bool $block ) {
|
||||
if ( false === $this->as3cf->get_storage_provider()->block_public_access_supported() ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
sprintf(
|
||||
_x(
|
||||
"Can't change Block All Public Access setting for %s buckets.",
|
||||
"Trying to change public access setting for given provider's bucket.",
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
$this->as3cf->get_storage_provider()->get_provider_service_name()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->as3cf->get_storage_provider()->needs_access_keys() ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'Storage Provider not configured with access credentials.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
if ( empty( $bucket ) ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'No bucket name provided.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
// Make sure given bucket name matches currently set bucket.
|
||||
$settings_bucket = $this->as3cf->get_setting( 'bucket' );
|
||||
|
||||
if ( $settings_bucket !== $bucket ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'Bucket name does not match currently set bucket.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
$region = $this->as3cf->get_setting( 'region' );
|
||||
$block = ! empty( $block );
|
||||
|
||||
try {
|
||||
$public_access_blocked = $this->as3cf->get_provider_client( $region )->public_access_blocked( $bucket );
|
||||
} catch ( Exception $e ) {
|
||||
$public_access_blocked = null;
|
||||
AS3CF_Error::log( $e->getMessage() );
|
||||
}
|
||||
|
||||
if ( empty( $block ) !== empty( $public_access_blocked ) ) {
|
||||
try {
|
||||
$this->as3cf->get_provider_client( $region )->block_public_access( $bucket, $block );
|
||||
} catch ( Exception $e ) {
|
||||
AS3CF_Error::log( $e->getMessage() );
|
||||
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'Could not change Block All Public Access status for bucket.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
// The bucket level request may succeed, but account level overrides may negate the change or the change simply silently failed.
|
||||
// So check that all is as expected as we can't change the account level settings.
|
||||
try {
|
||||
$public_access_blocked = $this->as3cf->get_provider_client( $region )->public_access_blocked( $bucket );
|
||||
} catch ( Exception $e ) {
|
||||
$public_access_blocked = null;
|
||||
AS3CF_Error::log( $e->getMessage() );
|
||||
}
|
||||
|
||||
if ( empty( $block ) !== empty( $public_access_blocked ) ) {
|
||||
if ( $block ) {
|
||||
$notice_message = __( '<strong>Failed to Enable Block All Public Access</strong> — We could not enable Block All Public Access. You will need to log in to the AWS Console and do it manually.', 'amazon-s3-and-cloudfront' );
|
||||
} else {
|
||||
$notice_message = __( '<strong>Failed to Disable Block All Public Access</strong> — We could not disable Block All Public Access. You will need to log in to the AWS Console and do it manually.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
$notice_message .= ' ' . $this->as3cf->settings_more_info_link( 'bucket' );
|
||||
|
||||
return new WP_Error( 'exception', $notice_message );
|
||||
}
|
||||
|
||||
// Successfully changed Block All Public Access status.
|
||||
return true;
|
||||
}
|
||||
|
||||
// All good, but nothing to do.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Object Ownership status of given bucket.
|
||||
*
|
||||
* @param string $bucket
|
||||
* @param boolean $enforce
|
||||
*
|
||||
* @return WP_Error|bool
|
||||
*
|
||||
* There's no actual setting for this, the state of object ownership controls in the bucket is checked as required.
|
||||
*/
|
||||
public function enforce_object_ownership( string $bucket, bool $enforce ) {
|
||||
if ( false === $this->as3cf->get_storage_provider()->object_ownership_supported() ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
sprintf(
|
||||
_x(
|
||||
"Can't change Object Ownership setting for %s buckets.",
|
||||
"Trying to change object ownership setting for given provider's bucket.",
|
||||
'amazon-s3-and-cloudfront'
|
||||
),
|
||||
$this->as3cf->get_storage_provider()->get_provider_service_name()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->as3cf->get_storage_provider()->needs_access_keys() ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'Storage Provider not configured with access credentials.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
if ( empty( $bucket ) ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'No bucket name provided.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
// Make sure given bucket name matches currently set bucket.
|
||||
$settings_bucket = $this->as3cf->get_setting( 'bucket' );
|
||||
|
||||
if ( $settings_bucket !== $bucket ) {
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'Bucket name does not match currently set bucket.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
$region = $this->as3cf->get_setting( 'region' );
|
||||
$enforce = ! empty( $enforce );
|
||||
|
||||
try {
|
||||
$object_ownership_enforced = $this->as3cf->get_provider_client( $region )->object_ownership_enforced( $bucket );
|
||||
} catch ( Exception $e ) {
|
||||
$object_ownership_enforced = null;
|
||||
AS3CF_Error::log( $e->getMessage() );
|
||||
}
|
||||
|
||||
if ( empty( $enforce ) !== empty( $object_ownership_enforced ) ) {
|
||||
try {
|
||||
$this->as3cf->get_provider_client( $region )->enforce_object_ownership( $bucket, $enforce );
|
||||
} catch ( Exception $e ) {
|
||||
AS3CF_Error::log( $e->getMessage() );
|
||||
|
||||
return new WP_Error(
|
||||
'exception',
|
||||
__( 'Could not change Object Ownership status for bucket.', 'amazon-s3-and-cloudfront' )
|
||||
);
|
||||
}
|
||||
|
||||
// The bucket level request may succeed, but as it does not return a status from the API, we don't know for sure.
|
||||
try {
|
||||
$object_ownership_enforced = $this->as3cf->get_provider_client( $region )->object_ownership_enforced( $bucket );
|
||||
} catch ( Exception $e ) {
|
||||
$object_ownership_enforced = null;
|
||||
AS3CF_Error::log( $e->getMessage() );
|
||||
}
|
||||
|
||||
if ( empty( $enforce ) !== empty( $object_ownership_enforced ) ) {
|
||||
if ( $enforce ) {
|
||||
$notice_message = __( '<strong>Failed to Enforce Object Ownership</strong> — We could not enforce Object Ownership. You will need to log in to the AWS Console and do it manually.', 'amazon-s3-and-cloudfront' );
|
||||
} else {
|
||||
$notice_message = __( '<strong>Failed to turn off Object Ownership Enforcement</strong> — We could not turn off Object Ownership enforcement. You will need to log in to the AWS Console and do it manually.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
$notice_message .= ' ' . $this->as3cf->settings_more_info_link( 'bucket' );
|
||||
|
||||
return new WP_Error( 'exception', $notice_message );
|
||||
}
|
||||
|
||||
// Successfully changed Object Ownership status.
|
||||
return true;
|
||||
}
|
||||
|
||||
// All good, but nothing to do.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
42
classes/api/v1/diagnostics.php
Normal file
42
classes/api/v1/diagnostics.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API\V1;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\API\API;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
class Diagnostics extends API {
|
||||
/** @var int */
|
||||
protected static $version = 1;
|
||||
|
||||
protected static $name = 'diagnostics';
|
||||
|
||||
/**
|
||||
* Register REST API routes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'get_diagnostics' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST GET request and returns the current diagnostics.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function get_diagnostics( WP_REST_Request $request ) {
|
||||
return $this->rest_ensure_response( 'get', static::name(), array(
|
||||
'diagnostics' => $this->as3cf->output_diagnostic_info(),
|
||||
) );
|
||||
}
|
||||
}
|
||||
84
classes/api/v1/notifications.php
Normal file
84
classes/api/v1/notifications.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API\V1;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\API\API;
|
||||
use WP_Error;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
class Notifications extends API {
|
||||
/** @var int */
|
||||
protected static $version = 1;
|
||||
|
||||
/** @var string */
|
||||
protected static $name = 'notifications';
|
||||
|
||||
/**
|
||||
* Register REST API routes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'get_notifications' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'DELETE',
|
||||
'callback' => array( $this, 'delete_notifications' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST GET request and returns the current notifications.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function get_notifications( WP_REST_Request $request ) {
|
||||
$data = $request->get_query_params();
|
||||
$tab = empty( $data['tab'] ) ? '' : $data['tab'];
|
||||
$all_tabs = ! empty( $data['all_tabs'] );
|
||||
|
||||
return $this->rest_ensure_response( 'get', static::name(), array(
|
||||
'notifications' => $this->as3cf->get_notifications( $tab, $all_tabs ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST DELETE request and returns the current notifications.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function delete_notifications( WP_REST_Request $request ) {
|
||||
$data = $request->get_json_params();
|
||||
|
||||
if ( empty( $data['id'] ) ) {
|
||||
return $this->rest_ensure_response( 'delete', static::name(),
|
||||
new WP_Error( 'missing-notification-id', __( 'Notification ID not supplied.', 'amazon-s3-and-cloudfront' ) )
|
||||
);
|
||||
}
|
||||
|
||||
$this->as3cf->dismiss_notification( $data['id'] );
|
||||
|
||||
$tab = empty( $data['tab'] ) ? '' : $data['tab'];
|
||||
$all_tabs = ! empty( $data['all_tabs'] );
|
||||
|
||||
return $this->rest_ensure_response( 'delete', static::name(), array(
|
||||
'notifications' => $this->as3cf->get_notifications( $tab, $all_tabs ),
|
||||
) );
|
||||
}
|
||||
}
|
||||
409
classes/api/v1/settings.php
Normal file
409
classes/api/v1/settings.php
Normal file
@@ -0,0 +1,409 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API\V1;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\API\API;
|
||||
use Exception;
|
||||
use WP_Error;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
class Settings extends API {
|
||||
/** @var int */
|
||||
protected static $version = 1;
|
||||
|
||||
/** @var string */
|
||||
protected static $name = 'settings';
|
||||
|
||||
/**
|
||||
* Register REST API routes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'get_settings' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'PUT',
|
||||
'callback' => array( $this, 'put_settings' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST GET request and returns the current settings and defined settings keys.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function get_settings( WP_REST_Request $request ) {
|
||||
return $this->rest_ensure_response( 'get', static::name(), $this->common_response() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Common response values for this API endpoint.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function common_response(): array {
|
||||
return array(
|
||||
'settings' => $this->as3cf->obfuscate_sensitive_settings( $this->as3cf->get_all_settings() ),
|
||||
'defined_settings' => array_keys( $this->as3cf->get_defined_settings() ),
|
||||
'storage_providers' => $this->as3cf->get_available_storage_provider_details(),
|
||||
'delivery_providers' => $this->as3cf->get_available_delivery_provider_details(),
|
||||
'is_plugin_setup' => $this->as3cf->is_plugin_setup(),
|
||||
'is_plugin_setup_with_credentials' => $this->as3cf->is_plugin_setup( true ),
|
||||
'needs_access_keys' => $this->as3cf->get_storage_provider()->needs_access_keys(),
|
||||
'bucket_writable' => $this->as3cf->bucket_writable(),
|
||||
'urls' => $this->as3cf->get_js_urls(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST PUT request to save supplied settings
|
||||
* and returns saved status, current settings, defined settings keys,
|
||||
* and various config data that may be altered by a change in settings.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function put_settings( WP_REST_Request $request ) {
|
||||
$saved = true;
|
||||
$data = $request->get_json_params();
|
||||
|
||||
try {
|
||||
$changed = $this->save_settings( $data );
|
||||
} catch ( Exception $e ) {
|
||||
$changed = false;
|
||||
}
|
||||
|
||||
if ( $changed === false ) {
|
||||
$saved = false;
|
||||
$changed = array();
|
||||
}
|
||||
|
||||
return $this->rest_ensure_response(
|
||||
'put',
|
||||
static::name(),
|
||||
array_merge(
|
||||
$this->common_response(),
|
||||
array(
|
||||
'saved' => $saved,
|
||||
'changed_settings' => $changed,
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle saving settings submitted by user.
|
||||
*
|
||||
* @param array $new_settings
|
||||
*
|
||||
* @return array|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function save_settings( array $new_settings ) {
|
||||
$changed_keys = array();
|
||||
$warning_args = array(
|
||||
'type' => 'warning',
|
||||
'only_show_in_settings' => true,
|
||||
'only_show_on_tab' => 'media',
|
||||
);
|
||||
|
||||
do_action( 'as3cf_pre_save_settings' );
|
||||
|
||||
$allowed = $this->as3cf->get_allowed_settings_keys();
|
||||
$old_settings = $this->as3cf->get_all_settings( false );
|
||||
|
||||
// Merge in defined settings as they take precedence and must overwrite anything supplied.
|
||||
// Only needed to allow for validation, during save defined settings are removed from array anyway.
|
||||
$new_settings = array_merge( $new_settings, $this->as3cf->get_defined_settings() );
|
||||
|
||||
// Keep track of whether the delivery provider has changed and signed url settings need to be checked.
|
||||
$check_signed_urls_settings = $this->check_signed_urls_settings( $new_settings, $old_settings );
|
||||
|
||||
foreach ( $allowed as $key ) {
|
||||
// Special case for when Secret Access Key is not changed.
|
||||
if (
|
||||
'secret-access-key' === $key &&
|
||||
! empty( $new_settings['secret-access-key'] ) &&
|
||||
_x( '-- not shown --', 'placeholder for hidden secret access key, 39 char max', 'amazon-s3-and-cloudfront' ) === $new_settings['secret-access-key']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Whether defined or not, get rid of old database setting for key.
|
||||
$this->as3cf->remove_setting( $key );
|
||||
|
||||
if ( ! isset( $new_settings[ $key ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $this->as3cf->sanitize_setting( $key, $new_settings[ $key ] );
|
||||
|
||||
if ( 'key-file' === $key && is_string( $value ) && ! empty( $value ) ) {
|
||||
// Guard against empty JSON.
|
||||
if ( '""' === $value ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = json_decode( $value, true );
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return $this->return_with_error( __( 'Key File not valid JSON.', 'amazon-s3-and-cloudfront' ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'bucket' === $key && $this->setting_changed( $old_settings, $key, $value ) ) {
|
||||
$value = $this->as3cf->check_bucket( $value );
|
||||
|
||||
// Front end validation should have caught this, it's all gone Pete Tong!
|
||||
if ( ! $value ) {
|
||||
return $this->return_with_error( __( 'Bucket name not valid.', 'amazon-s3-and-cloudfront' ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'signed-urls-key-file-path' === $key && is_string( $value ) && ! empty( $value ) ) {
|
||||
// Can be a Windows path with backslashes, so need to undo what PUT does to them.
|
||||
$value = stripslashes( $value );
|
||||
}
|
||||
|
||||
if ( $check_signed_urls_settings ) {
|
||||
if ( 'signed-urls-key-id' === $key && empty( $value ) ) {
|
||||
return $this->return_with_error( $this->as3cf->get_delivery_provider()->signed_urls_key_id_name() . _x( ' not provided.', 'missing form field', 'amazon-s3-and-cloudfront' ) );
|
||||
}
|
||||
|
||||
if ( 'signed-urls-key-file-path' === $key ) {
|
||||
if ( empty( $value ) ) {
|
||||
return $this->return_with_error( $this->as3cf->get_delivery_provider()->signed_urls_key_file_path_name() . _x( ' not provided.', 'missing form field', 'amazon-s3-and-cloudfront' ) );
|
||||
}
|
||||
|
||||
if ( ! $this->as3cf->get_delivery_provider()->validate_signed_urls_key_file_path( $value ) ) {
|
||||
// A notice is created by the validation function, we just want the rollback.
|
||||
return $this->return_with_error();
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'signed-urls-object-prefix' === $key && empty( $value ) ) {
|
||||
return $this->return_with_error( $this->as3cf->get_delivery_provider()->signed_urls_object_prefix_name() . _x( ' not provided.', 'missing form field', 'amazon-s3-and-cloudfront' ) );
|
||||
}
|
||||
}
|
||||
|
||||
$this->as3cf->set_setting( $key, $value );
|
||||
|
||||
if ( $this->setting_changed( $old_settings, $key, $value ) ) {
|
||||
$changed_keys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
// Before checking that settings are all properly aligned,
|
||||
// ensure storage and delivery providers are in sync in core class.
|
||||
$this->as3cf->set_storage_provider();
|
||||
$this->as3cf->set_delivery_provider();
|
||||
|
||||
// If Storage Provider has changed, reset Delivery Provider to Storage if no longer compatible.
|
||||
// Also reset region name if no longer compatible.
|
||||
if ( ! empty( $changed_keys ) && in_array( 'provider', $changed_keys ) ) {
|
||||
$storage_provider = $this->as3cf->get_storage_provider();
|
||||
$storage_supported = $this->as3cf->get_delivery_provider()->supports_storage( $storage_provider->get_provider_key_name() );
|
||||
|
||||
if ( ! $storage_supported ) {
|
||||
$this->as3cf->set_setting( 'delivery-provider', $this->as3cf->get_default_delivery_provider() );
|
||||
}
|
||||
|
||||
$region = $this->as3cf->get_setting( 'region' );
|
||||
|
||||
if (
|
||||
( empty( $region ) && $storage_provider->region_required() ) ||
|
||||
( ! empty( $region ) && ! in_array( $region, array_keys( $storage_provider->get_regions() ) ) )
|
||||
) {
|
||||
// Note: We don't trigger changed keys when resetting the region as we do not want to stop
|
||||
// the storage provider change because the bucket is not usable.
|
||||
// The provider/region/bucket combination will be checked in due course.
|
||||
$this->as3cf->set_setting( 'region', $storage_provider->get_default_region() );
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure newly selected provider/region/bucket combination is usable and bucket's extra data is up-to-date.
|
||||
if ( ! empty( $changed_keys ) && ( in_array( 'bucket', $changed_keys ) || in_array( 'region', $changed_keys ) ) ) {
|
||||
$bucket_error = $this->check_set_bucket_for_error();
|
||||
|
||||
if ( ! empty( $bucket_error ) ) {
|
||||
return $this->return_with_error( $bucket_error );
|
||||
}
|
||||
|
||||
// Has a side effect of saving settings, but that should be ok if bucket changed and validated,
|
||||
// as changing bucket is usually a separate process from changing other settings.
|
||||
$this->as3cf->bucket_changed();
|
||||
}
|
||||
|
||||
// If delivery provider has been changed, but not intentionally, we need to warn the user.
|
||||
if (
|
||||
! empty( $changed_keys ) &&
|
||||
! in_array( 'delivery-provider', $changed_keys ) &&
|
||||
$this->setting_changed( $old_settings, 'delivery-provider', $this->as3cf->get_setting( 'delivery-provider' ) )
|
||||
) {
|
||||
$changed_keys = array_unique( array_merge( $changed_keys, array( 'delivery-provider' ) ) );
|
||||
$storage_provider = $this->as3cf->get_storage_provider();
|
||||
$warnings[] = sprintf( __( 'Delivery Provider has been reset to the default for %s', 'amazon-s3-and-cloudfront' ), $storage_provider->get_provider_service_name() );
|
||||
}
|
||||
|
||||
// None of the settings produced an error of their own.
|
||||
// However, side effects may re-instate the notice after this.
|
||||
$this->as3cf->notices->dismiss_notice( 'save-settings-error' );
|
||||
|
||||
// Check provider/region/bucket to see whether any error notice or warning necessary.
|
||||
// Note: As this is a side effect of another change such as switching provider, settings save is not prevented.
|
||||
if ( ! in_array( 'bucket', $changed_keys ) && ! in_array( 'region', $changed_keys ) && ! empty( $this->as3cf->get_setting( 'bucket' ) ) ) {
|
||||
$bucket_error = $this->check_set_bucket_for_error();
|
||||
|
||||
if ( empty( $bucket_error ) && $this->setting_changed( $old_settings, 'region', $this->as3cf->get_setting( 'region' ) ) ) {
|
||||
// If region has been changed, but not intentionally, we may need to warn user.
|
||||
$changed_keys = array_unique( array_merge( $changed_keys, array( 'region' ) ) );
|
||||
$region_name = $this->as3cf->get_storage_provider()->get_region_name( $this->as3cf->get_setting( 'region' ) );
|
||||
$warnings[] = sprintf( __( 'Region has been changed to %s', 'amazon-s3-and-cloudfront' ), $region_name );
|
||||
}
|
||||
}
|
||||
|
||||
// Great success ...
|
||||
$this->as3cf->save_settings();
|
||||
|
||||
// ... but there may be warnings.
|
||||
if ( ! empty( $warnings ) ) {
|
||||
foreach ( $warnings as $warning ) {
|
||||
$this->as3cf->notices->add_notice( $warning, $warning_args );
|
||||
}
|
||||
}
|
||||
|
||||
do_action( 'as3cf_post_save_settings', true );
|
||||
|
||||
return $changed_keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the given setting changed?
|
||||
*
|
||||
* @param array $old_settings
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setting_changed( array $old_settings, string $key, $value ): bool {
|
||||
if (
|
||||
( empty( $old_settings[ $key ] ) !== empty( $value ) ) ||
|
||||
( isset( $old_settings[ $key ] ) && $old_settings[ $key ] !== $value )
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that provider/region/bucket combination is usable.
|
||||
*
|
||||
* @return string|WP_Error|null Error/string if problems, null otherwise.
|
||||
*/
|
||||
private function check_set_bucket_for_error() {
|
||||
$bucket = $this->as3cf->get_setting( 'bucket' );
|
||||
|
||||
if ( empty( $bucket ) ) {
|
||||
return __( 'No bucket provided.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
// If region not required as a parameter, and not already defined, get it from bucket.
|
||||
if ( $this->as3cf->get_storage_provider()->region_required() || $this->as3cf->get_defined_setting( 'region', false ) ) {
|
||||
$region = $this->as3cf->get_setting( 'region', false );
|
||||
} else {
|
||||
$region = $this->as3cf->get_bucket_region( $bucket, false );
|
||||
}
|
||||
|
||||
// When region is force checked and has an error, a notice is already created.
|
||||
if ( is_wp_error( $region ) ) {
|
||||
return $region;
|
||||
}
|
||||
|
||||
if ( ! $region ) {
|
||||
return __( 'No region provided.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
// Region may have been updated.
|
||||
$this->as3cf->set_setting( 'region', $region );
|
||||
|
||||
$can_write = $this->as3cf->check_write_permission( $bucket, $region );
|
||||
|
||||
if ( is_wp_error( $can_write ) ) {
|
||||
return $this->as3cf->get_storage_provider()->prepare_bucket_error( $can_write );
|
||||
}
|
||||
|
||||
if ( ! $can_write ) {
|
||||
return __( 'Access Denied to Bucket.', 'amazon-s3-and-cloudfront' );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we need to test signed URL settings and potentially prevent the save operation. We only need to test
|
||||
* this if:
|
||||
* - The delivery provider has not changed.
|
||||
* - And signed URLs are enabled in the new settings.
|
||||
* - And the delivery provider allows the use of signed URLs with a key file.
|
||||
*
|
||||
* @param array $new_settings
|
||||
* @param array $old_settings
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function check_signed_urls_settings( array $new_settings, array $old_settings ): bool {
|
||||
$delivery_provider_changed = ! empty( $new_settings['delivery-provider'] ) && $this->setting_changed( $old_settings, 'delivery-provider', $new_settings['delivery-provider'] );
|
||||
$signed_urls_enabled = ! empty( $new_settings['enable-delivery-domain'] ) && ! empty( $new_settings['enable-signed-urls'] );
|
||||
|
||||
return ! $delivery_provider_changed && $signed_urls_enabled ? $this->as3cf->get_delivery_provider()->use_signed_urls_key_file_allowed() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs an error notice if string given, resets settings and then returns false.
|
||||
*
|
||||
* @param string|WP_Error|null $error Message for new notice, or WP_Error or null if new notice not needed.
|
||||
*
|
||||
* @return false
|
||||
* @throws Exception
|
||||
*/
|
||||
private function return_with_error( $error = null ): bool {
|
||||
if ( ! is_wp_error( $error ) && ! empty( $error ) ) {
|
||||
$this->as3cf->notices->add_notice(
|
||||
$error,
|
||||
array(
|
||||
'type' => 'error',
|
||||
'only_show_in_settings' => true,
|
||||
'only_show_on_tab' => 'media',
|
||||
'custom_id' => 'save-settings-error',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Revert all changes.
|
||||
$this->as3cf->get_settings( true );
|
||||
$this->as3cf->set_storage_provider();
|
||||
$this->as3cf->set_delivery_provider();
|
||||
|
||||
do_action( 'as3cf_post_save_settings', false );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
66
classes/api/v1/state.php
Normal file
66
classes/api/v1/state.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API\V1;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\API\API;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
class State extends API {
|
||||
/** @var int */
|
||||
protected static $version = 1;
|
||||
|
||||
/** @var string */
|
||||
protected static $name = 'state';
|
||||
|
||||
/**
|
||||
* Register REST API routes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'get_state' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST GET request and returns the current state.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function get_state( WP_REST_Request $request ) {
|
||||
$params = $request->get_params();
|
||||
|
||||
$skip_transient = false;
|
||||
$force = false;
|
||||
$forced_blog_id = 0;
|
||||
|
||||
if ( ! empty( $params['refreshMediaCounts'] ) ) {
|
||||
$skip_transient = true;
|
||||
$force = true;
|
||||
$forced_blog_id = -1;
|
||||
}
|
||||
|
||||
return $this->rest_ensure_response(
|
||||
'get',
|
||||
static::name(),
|
||||
array_merge(
|
||||
$this->endpoint_common_response( Settings::name() ),
|
||||
array(
|
||||
'counts' => $this->as3cf->media_counts( $skip_transient, $force, $forced_blog_id ),
|
||||
'summary_counts' => $this->as3cf->get_summary_counts(),
|
||||
'offload_remaining_upsell' => $this->as3cf->get_offload_remaining_upsell_message(),
|
||||
'upgrades' => $this->as3cf->get_upgrades_info(),
|
||||
'settings_validation' => $this->as3cf->settings_validation_status(),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
74
classes/api/v1/url-preview.php
Normal file
74
classes/api/v1/url-preview.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace DeliciousBrains\WP_Offload_Media\API\V1;
|
||||
|
||||
use DeliciousBrains\WP_Offload_Media\API\API;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
|
||||
class URL_Preview extends API {
|
||||
/** @var int */
|
||||
protected static $version = 1;
|
||||
|
||||
protected static $name = 'url-preview';
|
||||
|
||||
/**
|
||||
* Register REST API routes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( $this, 'get_url_preview' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
static::api_namespace(),
|
||||
static::route(),
|
||||
array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array( $this, 'post_url_preview' ),
|
||||
'permission_callback' => array( $this, 'check_permissions' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST GET request and returns the current url_preview.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function get_url_preview( WP_REST_Request $request ) {
|
||||
return $this->rest_ensure_response( 'get', static::name(), array(
|
||||
'url_example' => $this->as3cf->get_url_preview(),
|
||||
'url_parts' => $this->as3cf->get_url_preview( true ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a REST POST request and returns the url_preview for given settings.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response|mixed
|
||||
*/
|
||||
public function post_url_preview( WP_REST_Request $request ) {
|
||||
$data = $request->get_json_params();
|
||||
|
||||
// If no settings provided, don't provide any urls to signify a soft error.
|
||||
if ( empty( $data['settings'] ) || ! is_array( $data['settings'] ) ) {
|
||||
return $this->rest_ensure_response( 'post', static::name(), array() );
|
||||
}
|
||||
|
||||
return $this->rest_ensure_response( 'post', static::name(), array(
|
||||
'url_example' => $this->as3cf->get_url_preview( false, null, $data['settings'] ),
|
||||
'url_parts' => $this->as3cf->get_url_preview( true, null, $data['settings'] ),
|
||||
) );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user