Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add check capability endpoint. #883

Merged
merged 2 commits into from

6 participants

@lezama
Owner

@enejb could you give it a check to the logic?
@justinshreve I am not sure what should be the path for this endpoint. What do you suggest?

@lezama lezama Add check capability endpoint.
+ Move the capability check inside `validate_call` to the
`check_capability` method.
b629eee
@georgestephanis

@justinshreve Also, whether this would be useful to have for wpcom sites as well, and not merely Jetpack sites. It may be useful for the API to randomly check what a user can do, so it can tailor UIs to the user.

@enejb
Owner

I checked the logic and it makes sense. Should we check that we have at least one must pass condition ?

Also I still need to test it.

@justinshreve

@georgestephanis I think this would be good to have for both WordPress.com & Jetpack sites.

Not 100% sure what the endpoint should be...
/sites/%s/capabilities or /sites/%s/capabilities/mine ?

@georgestephanis

/mine matches the existing structure already for a lot of endpoints, so I'd think that ... but is there any time someone would need to query for another user's caps?

@lezama
Owner

is there any time someone would need to query for another user's caps?

I can't imagine a good use case but we could allow it just for users of the same blog just in case.

@enejb
Owner

I think an endpoint like current_user_can make sense to me. I would expect to get a list of capabilities if I went to the capabilities endpoint.

@lezama
Owner

Wouldn't be more interesting to return the list of capabilities instead of doing the check endpoint side?
In order to avoid multiple requests, and easier to cache.

@georgestephanis
@lezama
Owner

:+1: good point, no need to rethink that part.

@georgestephanis

@lezama: What's the point of the 'must pass' number?

I think it'd make more sense if the in/out looked something like ..

in:

[
  'capability_1',
  'capability_2',
  'capability_3',
  'capability_4',
  'capability_5'
]

out:

{
  'capability_1' : true,
  'capability_2' : true,
  'capability_3' : false,
  'capability_4' : false,
  'capability_5' : true
}
@enejb
Owner

@georgestephanis The point was that this way you can easier pass in an or condition. So out of all of these conditions we need to pass at least one. If you need to pass all of them you just leave it out.

What you are proposing sounds good. Except for that a non empty array would eventuate as true even if no conditions where passed which might be a cause of errors.

@lezama
Owner

It's true that it makes harder to use the endpoint to cache individual capabilities in one request.

@georgestephanis

@enejb I'm actually fine with that. If you pass an array in, you should expect an array back, not just a boolean.

If you pass in just a string for a single cap, then I'm fine returning a simple boolean.

@justinshreve

but is there any time someone would need to query for another user's caps

Nope.. so I'm not sure what the root level would do if we went with /mine.

@blobaugh

Leaves room for possible future expansion

@lezama lezama REST API: Return an array of capabilities.
The endpoint can be called passing a single capability or an array of
capabilities.
In the first case, It returns a boolean indicating if the current user
has that capability.
In the second case, an array with the capabilities as keys and
current_user_can( key ) as values.
056d864
@georgestephanis

@lezama Looks good, but can you move it to the shared endpoints, so it can be used on wpcom as well, as per @justinshreve? Then hit that awesome Merge button! :+1:

@justinshreve

I think the /me/* thing was an interesting idea. Nice. I think that should probably be /me/capabilities though (see the FieldGuide page for naming guidelines).

In addition to moving it to shared endpoints - I would change the group to 'sites'. I would also like to see a test or two for this in the current test suite.

@georgestephanis

Just so I can get the strings into master and the pot file, I'm going to merge this, then any further tweaks can be done in master.

@georgestephanis georgestephanis merged commit 657871f into from
@georgestephanis

cc: @lezama @justinshreve ^^ -- we can also leave it just in Jetpack until we have all the tests for wpcom correctly in place.

@georgestephanis georgestephanis deleted the branch
@justinshreve

I'd like to see tests for JP anyway though :).

@georgestephanis

Oh, agreed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 23, 2014
  1. @lezama

    Add check capability endpoint.

    lezama authored
    + Move the capability check inside `validate_call` to the
    `check_capability` method.
  2. @lezama

    REST API: Return an array of capabilities.

    lezama authored
    The endpoint can be called passing a single capability or an array of
    capabilities.
    In the first case, It returns a boolean indicating if the current user
    has that capability.
    In the second case, an array with the capabilities as keys and
    current_user_can( key ) as values.
This page is out of date. Refresh to see the latest.
Showing with 82 additions and 19 deletions.
  1. +82 −19 json-endpoints/class.json-api-jetpack-endpoints.php
View
101 json-endpoints/class.json-api-jetpack-endpoints.php
@@ -11,40 +11,54 @@
*/
protected function validate_call( $_blog_id, $capability, $check_full_management = true ) {
$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $_blog_id ) );
- if ( is_wp_error( $blog_id ) )
+ if ( is_wp_error( $blog_id ) ) {
return $blog_id;
+ }
+
+ if ( is_wp_error( $error = $this->check_capability( $capability ) ) ) {
+ return $error;
+ }
- if( is_array ( $capability ) ) {
+ if ( $check_full_management && ! Jetpack_Options::get_option( 'json_api_full_management' ) ) {
+ return new WP_Error( 'unauthorized_full_access', sprintf( __( 'Full management mode is off for this site.' , 'jetpack' ), $capability ), 403 );
+ }
+ return true;
+ }
+
+ /**
+ * @param $capability
+ *
+ * @return bool|WP_Error
+ */
+ protected function check_capability( $capability ) {
+ if ( is_array( $capability ) ) {
// the idea is that the we can pass in an array of capabilitie that the user needs to have before we allowing them to do something
$capabilities = ( isset( $capability['capabilities'] ) ? $capability['capabilities'] : $capability );
-
- // We can pass in the number of conditions we must pass by default it is all.
+
+ // We can pass in the number of conditions we must pass by default it is all.
$must_pass = ( isset( $capability['must_pass'] ) && is_int( $capability['must_pass'] ) ? $capability['must_pass'] : count( $capabilities ) );
-
+
$failed = array(); // store the failed capabilities
- $passed = 0; //
-
- foreach( $capabilities as $cap ) {
- if( current_user_can( $cap ) ) {
- $passed++;
+ $passed = 0; //
+
+ foreach ( $capabilities as $cap ) {
+ if ( current_user_can( $cap ) ) {
+ $passed ++;
} else {
$failed[] = $cap;
}
}
- // Check that must have conditions is less then
- if( $passed < $must_pass ) {
- return new WP_Error( 'unauthorized', sprintf( __( 'This user is not authorized to %s on this blog.' , 'jetpack' ), implode( ', ', $failed ), 403 ) );
+ // Check that must have conditions is less then
+ if ( $passed < $must_pass ) {
+ return new WP_Error( 'unauthorized', sprintf( __( 'This user is not authorized to %s on this blog.', 'jetpack' ), implode( ', ', $failed ), 403 ) );
}
} else {
- if ( ! current_user_can( $capability ) ) {
- return new WP_Error( 'unauthorized', sprintf( __( 'This user is not authorized to %s on this blog.' , 'jetpack' ), $capability ), 403 );
+ if ( !current_user_can( $capability ) ) {
+ return new WP_Error( 'unauthorized', sprintf( __( 'This user is not authorized to %s on this blog.', 'jetpack' ), $capability ), 403 );
}
}
-
- if ( $check_full_management && ! Jetpack_Options::get_option( 'json_api_full_management' ) ) {
- return new WP_Error( 'unauthorized_full_access', sprintf( __( 'Full management mode is off for this site.' , 'jetpack' ), $capability ), 403 );
- }
+
return true;
}
@@ -830,3 +844,52 @@ public function callback( $path = '', $_blog_id = 0 ) {
),
'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/updates'
) );
+
+
+// Jetpack Extras
+
+
+class Jetpack_Check_Capabilities_Endpoint extends Jetpack_JSON_API_Jetpack_Modules_Endpoint {
+ // GET /sites/%s/me/capability
+ public function callback( $path = '', $_blog_id = 0 ) {
+ // Check minimum capability and blog membership first
+ if ( is_wp_error( $error = $this->validate_call( $_blog_id, 'read', false ) ) ) {
+ return $error;
+ }
+
+ $args = $this->input();
+
+ if ( ! isset( $args['capability'] ) || empty( $args['capability'] ) ) {
+ return new WP_Error( 'missing_capability', __( 'You are required to specify a capability to check.', 'jetpack' ), 400 );
+ }
+
+ $capability = $args['capability'];
+ if ( is_array( $capability ) ) {
+ $results = array_map( 'current_user_can', $capability );
+ return array_combine( $capability, $results );
+ } else {
+ return current_user_can( $capability );
+ }
+ }
+}
+
+new Jetpack_Check_Capabilities_Endpoint( array(
+ 'description' => 'Check if the current user has a certain capability over a Jetpack site',
+ 'group' => 'jetpack',
+ 'stat' => 'jetpack:me:capability',
+ 'method' => 'GET',
+ 'path' => '/sites/%s/me/capability',
+ 'path_labels' => array(
+ '$site' => '(int|string) The site ID, The site domain'
+ ),
+ 'response_format' => '(bool) True if the user has the queried capability.',
+ 'example_request_data' => array(
+ 'headers' => array(
+ 'authorization' => 'Bearer YOUR_API_TOKEN'
+ ),
+ 'body' => array(
+ 'capability' => 'A single capability or an array of capabilities'
+ )
+ ),
+ 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/me/capability'
+) );
Something went wrong with that request. Please try again.