Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 117 additions & 7 deletions src/php/rest-api/class-snippets-rest-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use WP_REST_Response;
use WP_REST_Server;
use function Code_Snippets\activate_snippet;
use function Code_Snippets\clean_active_snippets_cache;
use function Code_Snippets\code_snippets;
use function Code_Snippets\deactivate_snippet;
use function Code_Snippets\trash_snippet;
Expand Down Expand Up @@ -369,7 +370,23 @@ public function delete_item( $request ) {
*/
public function activate_item( WP_REST_Request $request ) {
$item = $this->prepare_item_for_database( $request );
$result = activate_snippet( $item->id, $item->network );
$snippet = $item ? get_snippet( $item->id, $item->network ) : null;

if ( ! $snippet || ! $snippet->id ) {
return new WP_Error(
'rest_cannot_activate',
__( 'The snippet could not be found.', 'code-snippets' ),
[ 'status' => 404 ]
);
}

if ( $snippet->shared_network ) {
$this->set_shared_network_active( $snippet->id, true );
$snippet->active = true;
return rest_ensure_response( $snippet );
}

$result = activate_snippet( $snippet->id, $snippet->network );

return $result instanceof Snippet ?
rest_ensure_response( $result ) :
Expand All @@ -389,7 +406,23 @@ public function activate_item( WP_REST_Request $request ) {
*/
public function deactivate_item( WP_REST_Request $request ) {
$item = $this->prepare_item_for_database( $request );
$result = deactivate_snippet( $item->id, $item->network );
$snippet = $item ? get_snippet( $item->id, $item->network ) : null;

if ( ! $snippet || ! $snippet->id ) {
return new WP_Error(
'rest_cannot_activate',
__( 'The snippet could not be found.', 'code-snippets' ),
[ 'status' => 404 ]
);
}

if ( $snippet->shared_network ) {
$this->set_shared_network_active( $snippet->id, false );
$snippet->active = false;
return rest_ensure_response( $snippet );
}

$result = deactivate_snippet( $snippet->id, $snippet->network );

return $result instanceof Snippet ?
rest_ensure_response( $result ) :
Expand All @@ -400,6 +433,35 @@ public function deactivate_item( WP_REST_Request $request ) {
);
}

/**
* Toggle a shared network snippet's active state for the current site only.
*
* @param int $snippet_id Snippet identifier.
* @param bool $active Whether the snippet should be active on the current site.
*
* @return void
*/
private function set_shared_network_active( int $snippet_id, bool $active ): void {
$active_shared_snippets = get_option( 'active_shared_network_snippets', [] );

if ( ! is_array( $active_shared_snippets ) ) {
$active_shared_snippets = [];
}

$already_active = in_array( $snippet_id, $active_shared_snippets, true );

if ( $active === $already_active ) {
return;
}

$active_shared_snippets = $active ?
array_merge( $active_shared_snippets, [ $snippet_id ] ) :
array_values( array_diff( $active_shared_snippets, [ $snippet_id ] ) );

update_option( 'active_shared_network_snippets', $active_shared_snippets );
clean_active_snippets_cache( code_snippets()->db->ms_table );
}

/**
* Prepare an instance of the Export class from a request.
*
Expand Down Expand Up @@ -480,6 +542,54 @@ public function prepare_item_for_response( $item, $request ) {
return rest_ensure_response( $response );
}

/**
* Determine whether a request targets network-scoped snippets.
*
* Only the literal boolean `true` (or its common string/integer equivalents)
* is treated as a network-scoped request. A missing or null `network` param
* means "site-scoped", and must not be escalated to the network capability.
*
* @param WP_REST_Request $request Full data about the request.
*
* @return bool
*/
private function is_network_scoped_request( $request ): bool {
if ( ! is_multisite() ) {
return false;
}

if ( ! $request instanceof WP_REST_Request || ! $request->has_param( 'network' ) ) {
return false;
}

$network = $request->get_param( 'network' );

if ( is_bool( $network ) ) {
return $network;
}

if ( is_string( $network ) ) {
return in_array( strtolower( $network ), [ '1', 'true', 'yes' ], true );
}

return (bool) $network;
}

/**
* Verify the current user has permission for the scope implied by the request.
*
* @param WP_REST_Request $request Full data about the request.
*
* @return bool
*/
private function check_request_capability( $request ): bool {
if ( $this->is_network_scoped_request( $request ) ) {
return code_snippets()->user_can_manage_network_snippets();
}

return code_snippets()->current_user_can();
}

/**
* Check if a given request has access to get items.
*
Expand All @@ -488,7 +598,7 @@ public function prepare_item_for_response( $item, $request ) {
* @return boolean
*/
public function get_items_permissions_check( $request ): bool {
return code_snippets()->current_user_can();
return $this->check_request_capability( $request );
}

/**
Expand All @@ -499,7 +609,7 @@ public function get_items_permissions_check( $request ): bool {
* @return boolean
*/
public function get_item_permissions_check( $request ): bool {
return $this->get_items_permissions_check( $request );
return $this->check_request_capability( $request );
}

/**
Expand All @@ -510,7 +620,7 @@ public function get_item_permissions_check( $request ): bool {
* @return boolean
*/
public function create_item_permissions_check( $request ): bool {
return code_snippets()->current_user_can();
return $this->check_request_capability( $request );
}

/**
Expand All @@ -521,7 +631,7 @@ public function create_item_permissions_check( $request ): bool {
* @return boolean
*/
public function update_item_permissions_check( $request ): bool {
return $this->create_item_permissions_check( $request );
return $this->check_request_capability( $request );
}

/**
Expand All @@ -532,7 +642,7 @@ public function update_item_permissions_check( $request ): bool {
* @return boolean
*/
public function delete_item_permissions_check( $request ): bool {
return $this->create_item_permissions_check( $request );
return $this->check_request_capability( $request );
}

/**
Expand Down
Loading