PluginProbe ʕ •ᴥ•ʔ
Advanced Access Manager – Access Governance for WordPress / trunk
Advanced Access Manager – Access Governance for WordPress vtrunk
6.8.4 6.8.5 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13 6.9.14 6.9.15 6.9.16 6.9.17 6.9.18 6.9.19 6.9.2 6.9.20 6.9.21 6.9.22 6.9.23 6.9.24 6.9.25 6.9.26 6.9.27 6.9.28 6.9.29 6.9.3 6.9.30 6.9.31 6.9.32 6.9.33 6.9.34 6.9.35 6.9.36 6.9.37 6.9.38 6.9.39 6.9.4 6.9.41 6.9.42 6.9.43 6.9.44 6.9.45 6.9.46 6.9.47 6.9.48 6.9.49 6.9.5 6.9.51 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.0-alpha.6 7.0.0-alpha.7 7.0.0-beta.1 7.0.0-rc1 7.0.0-rc2 7.0.0-rc3 7.0.1 7.0.10 7.0.11 7.0.2 7.0.3 7.0.4 7.0.5 7.0.6 7.0.7 7.0.8 7.0.9 7.1.0 7.1.1 trunk 3.0 4.0 4.0.1 4.1 4.2 4.3 4.4 4.4.1 4.5 4.6 4.6.1 4.6.2 4.7 4.7.1 4.7.2 4.7.5 4.7.6 4.8 4.8.1 4.9 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.5.1 4.9.5.2 5.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1 5.1.1 5.10 5.11 5.2 5.2.1 5.2.5 5.2.6 5.2.7 5.3 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.4 5.4.1 5.4.2 5.4.3 5.4.3.1 5.4.3.2 5.5 5.5.1 5.5.2 5.6 5.6.1 5.6.1.1 5.7 5.7.1 5.7.2 5.7.3 5.8 5.8.1 5.8.2 5.8.3 5.9 5.9.1 5.9.1.1 5.9.2 5.9.2.1 5.9.3 5.9.4 5.9.5 5.9.6 5.9.6.1 5.9.6.2 5.9.6.3 5.9.7 5.9.7.1 5.9.7.2 5.9.7.3 5.9.8 5.9.8.1 5.9.9 5.9.9.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.2.0 6.2.1 6.2.2 6.3.0 6.3.1 6.3.2 6.3.3 6.4.0 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.6.0 6.6.1 6.6.2 6.6.3 6.6.4 6.7.0 6.7.1 6.7.2 6.7.3 6.7.4 6.7.5 6.7.6 6.7.7 6.7.8 6.7.9 6.8.0 6.8.1 6.8.2 6.8.3
advanced-access-manager / application / Restful / Roles.php
advanced-access-manager / application / Restful Last commit date
AccessDeniedRedirect.php 1 year ago AdminToolbar.php 1 year ago ApiRoute.php 1 year ago BackendMenu.php 1 year ago BackwardCompatibility.php 1 year ago Capability.php 1 year ago Configs.php 5 months ago Content.php 1 year ago Identity.php 1 year ago Jwt.php 5 months ago LoginRedirect.php 1 year ago LogoutRedirect.php 1 year ago Metabox.php 1 year ago Mu.php 1 year ago NotFoundRedirect.php 1 year ago Policies.php 1 year ago Roles.php 1 year ago SecureLogin.php 1 year ago SecurityAudit.php 1 year ago ServiceTrait.php 1 year ago Settings.php 1 year ago Urls.php 1 year ago Users.php 1 year ago Widgets.php 1 year ago
Roles.php
578 lines
1 <?php
2
3 /**
4 * ======================================================================
5 * LICENSE: This file is subject to the terms and conditions defined in *
6 * file 'license.txt', which is part of this source code package. *
7 * ======================================================================
8 */
9
10 /**
11 * RESTful API for role management
12 *
13 * @package AAM
14 * @version 7.0.0
15 */
16 class AAM_Restful_Roles
17 {
18
19 use AAM_Restful_ServiceTrait;
20
21 /**
22 * Constructor
23 *
24 * @return void
25 * @access protected
26 *
27 * @version 7.0.0
28 */
29 protected function __construct()
30 {
31 // Register API endpoint
32 add_action('rest_api_init', function() {
33 // Get the list of roles
34 $this->_register_route('/roles', [
35 'methods' => WP_REST_Server::READABLE,
36 'callback' => array($this, 'get_role_list'),
37 'args' => array(
38 'fields' => array(
39 'description' => 'List of additional fields to return',
40 'type' => 'string',
41 'validate_callback' => function ($value) {
42 return $this->_validate_fields_input($value);
43 }
44 )
45 )
46 ], [ 'aam_manager', 'aam_list_roles' ], false);
47
48 // Get a specific role
49 $this->_register_route('/role/(?P<role_slug>[\w\-%+]+)', [
50 'methods' => WP_REST_Server::READABLE,
51 'callback' => array($this, 'get_role'),
52 'args' => array(
53 'role_slug' => array(
54 'description' => 'Unique role slug (aka ID)',
55 'type' => 'string',
56 'validate_callback' => function ($value) {
57 return $this->_validate_role_accessibility($value);
58 }
59 ),
60 'fields' => array(
61 'description' => 'List of additional fields to return',
62 'type' => 'string',
63 'validate_callback' => function ($value) {
64 return $this->_validate_fields_input($value);
65 }
66 )
67 )
68 ], [ 'aam_manager', 'aam_list_roles' ], false);
69
70 // Create new role
71 $this->_register_route('/roles', [
72 'methods' => WP_REST_Server::CREATABLE,
73 'callback' => array($this, 'create_role'),
74 'args' => array(
75 'slug' => array(
76 'description' => 'Unique role slug',
77 'type' => 'string',
78 'validate_callback' => function($value, $request) {
79 return $this->_validate_role_slug_uniqueness(
80 $value, $request
81 );
82 }
83 ),
84 'name' => array(
85 'description' => 'Role name',
86 'type' => 'string',
87 'required' => true
88 ),
89 'capabilities' => array(
90 'description' => 'List of capabilities to assign',
91 'type' => 'array',
92 'items' => array(
93 'type' => 'string'
94 )
95 ),
96 'clone_role' => array(
97 'description' => 'Clone role slug (aka ID)',
98 'type' => 'string',
99 'validate_callback' => function ($value) {
100 return $this->_validate_role_accessibility($value);
101 }
102 ),
103 'clone_role_settings' => array(
104 'description' => 'Clone role settings',
105 'type' => 'boolean'
106 ),
107 'fields' => array(
108 'description' => 'List of additional fields to return',
109 'type' => 'string',
110 'validate_callback' => function ($value) {
111 return $this->_validate_fields_input($value);
112 }
113 )
114 )
115 ], [ 'aam_manager', 'aam_create_roles' ], false);
116
117 // Update existing role
118 $this->_register_route('/role/(?P<role_slug>[\w\-%+]+)', [
119 'methods' => WP_REST_Server::EDITABLE,
120 'callback' => array($this, 'update_role'),
121 'args' => array(
122 'role_slug' => array(
123 'description' => 'Unique role slug (aka ID)',
124 'type' => 'string',
125 'validate_callback' => function ($value) {
126 return $this->_validate_role_accessibility($value);
127 }
128 ),
129 'new_slug' => array(
130 'description' => 'Unique role slug',
131 'type' => 'string'
132 ),
133 'name' => array(
134 'description' => 'Role name',
135 'type' => 'string'
136 ),
137 'add_capabilities' => array(
138 'description' => 'List of capabilities to assign',
139 'type' => 'array',
140 'items' => array(
141 'type' => 'string'
142 )
143 ),
144 'remove_capabilities' => array(
145 'description' => 'List of capabilities to remove',
146 'type' => 'array',
147 'items' => array(
148 'type' => 'string'
149 )
150 )
151 )
152 ], [ 'aam_manager', 'aam_edit_roles' ], false);
153
154 // Delete role
155 $this->_register_route('/role/(?P<role_slug>[\w\-%+]+)', [
156 'methods' => WP_REST_Server::DELETABLE,
157 'callback' => array($this, 'delete_role'),
158 'args' => array(
159 'role_slug' => array(
160 'description' => 'Unique role slug (aka ID)',
161 'type' => 'string',
162 'validate_callback' => function ($value) {
163 return $this->_validate_role_accessibility($value);
164 }
165 )
166 )
167 ], [ 'aam_manager', 'aam_delete_roles' ], false);
168 });
169 }
170
171 /**
172 * Get list of all editable roles
173 *
174 * @param WP_REST_Request $request
175 * @return WP_REST_Response
176 *
177 * @version 7.0.0
178 */
179 public function get_role_list(WP_REST_Request $request)
180 {
181 try {
182 $result = [];
183
184 // Determine the list of additional fields to return
185 $fields = $this->_determine_additional_fields($request);
186
187 // Fetch the complete list of editable roles and transform then into the
188 // response array
189 foreach(AAM::api()->roles->get_editable_roles() as $role) {
190 array_push($result, $this->_prepare_output($role, $fields));
191 }
192 } catch (Exception $e) {
193 $result = $this->_prepare_error_response($e);
194 }
195
196 return rest_ensure_response($result);
197 }
198
199 /**
200 * Get specific role by slug
201 *
202 * @param WP_REST_Request $request
203 * @return WP_REST_Response
204 *
205 * @version 7.0.0
206 */
207 public function get_role(WP_REST_Request $request)
208 {
209 try {
210 $result = $this->_prepare_output(
211 AAM::api()->role(urldecode($request->get_param('role_slug'))),
212 $this->_determine_additional_fields($request)
213 );
214 } catch (Exception $ex) {
215 $result = $this->_prepare_error_response($ex);
216 }
217
218 return rest_ensure_response($result);
219 }
220
221 /**
222 * Create new role
223 *
224 * @param WP_REST_Request $request
225 * @return WP_REST_Response
226 *
227 * @version 7.0.0
228 */
229 public function create_role(WP_REST_Request $request)
230 {
231 try {
232 // Prepare the basic data attributes for new role: id, name and list of
233 // capabilities
234 $name = $request->get_param('name');
235 $slug = $request->get_param('slug'); // optional
236 $clone_role = $request->get_param('clone_role'); // optional
237 $clone_role_settings = $request->get_param('clone_role_settings'); // optional
238 $capabilities = $request->get_param('capabilities'); // optional
239
240 // Making sure that we have at least empty array of capabilities
241 $capabilities = is_array($capabilities) ? $capabilities : array();
242
243 // If clone role is specified, verify that role exists and current user
244 // can manage it
245 if (is_string($clone_role) && strlen($clone_role) > 0) {
246 $cloning_role = AAM::api()->role($clone_role);
247 $cloning_caps = array_filter(
248 $cloning_role->capabilities, function($effect) {
249 return !empty($effect);
250 }
251 );
252
253 $capabilities = array_merge(
254 $capabilities,
255 array_keys($cloning_caps),
256 // Also adding role's slug to the list of capabilities
257 // https://github.com/aamplugin/advanced-access-manager/issues/97
258 array($clone_role)
259 );
260 }
261
262 $role = AAM::api()->roles->create($name, $slug, $capabilities);
263
264 // Cloning settings
265 if ($clone_role_settings === true && !empty($cloning_role)) {
266 $this->_clone_settings($role, $cloning_role);
267 }
268
269 // Inform any other processes about new role creation event
270 do_action('aam_role_created_action', $role, $request);
271
272 $result = $this->_prepare_output(
273 $role,
274 $this->_determine_additional_fields($request)
275 );
276 } catch (Exception $ex) {
277 $result = $this->_prepare_error_response($ex);
278 }
279
280 return rest_ensure_response($result);
281 }
282
283 /**
284 * Update existing role
285 *
286 * @param WP_REST_Request $request
287 * @return WP_REST_Response
288 *
289 * @version 7.0.0
290 */
291 public function update_role(WP_REST_Request $request)
292 {
293 try {
294 $name = $request->get_param('name'); // optional
295 $slug = urldecode($request->get_param('role_slug'));
296 $new_slug = $request->get_param('new_slug'); // optional
297 $add_caps = $request->get_param('add_capabilities'); // optional
298 $deprive_caps = $request->get_param('deprive_capabilities'); // optional
299 $remove_caps = $request->get_param('remove_capabilities'); // optional
300
301 // Update role
302 $role = AAM::api()->roles->update($slug, [
303 'name' => $name,
304 'slug' => $new_slug,
305 'add_caps' => $add_caps,
306 'deprive_caps' => $deprive_caps,
307 'remove_caps' => $remove_caps
308 ]);
309
310 // Inform any other processes about role updated event
311 do_action('aam_rest_update_role_action', $role, $request);
312
313 $result = $this->_prepare_output(
314 $role,
315 $this->_determine_additional_fields($request)
316 );
317 } catch (Exception $ex) {
318 $result = $this->_prepare_error_response($ex);
319 }
320
321 return rest_ensure_response($result);
322 }
323
324 /**
325 * Delete existing role
326 *
327 * @param WP_REST_Request $request
328 * @return WP_REST_Response
329 *
330 * @version 7.0.0
331 */
332 public function delete_role(WP_REST_Request $request)
333 {
334 try {
335 // Delete role
336 $result = [
337 'success' => AAM::api()->roles->delete(urldecode(
338 $request->get_param('role_slug')
339 ))
340 ];
341 } catch (Exception $ex) {
342 $result = $this->_prepare_error_response($ex);
343 }
344
345 return rest_ensure_response($result);
346 }
347
348 /**
349 * Clone access settings
350 *
351 * @param AAM_Framework_Proxy_Role $role
352 * @param AAM_Framework_Proxy_Role $parent
353 *
354 * @return boolean
355 * @access private
356 *
357 * @version 7.0.7
358 */
359 private function _clone_settings($role, $parent)
360 {
361 // Base role
362 $service = AAM::api()->settings(sprintf('%s:%s',
363 AAM_Framework_Type_AccessLevel::ROLE,
364 $role->slug
365 ));
366
367 // From role
368 $from = AAM::api()->settings(sprintf('%s:%s',
369 AAM_Framework_Type_AccessLevel::ROLE,
370 $parent->slug
371 ));
372
373 // Clone the settings
374 return $service->set_settings($from->get_settings());
375 }
376
377 /**
378 * Prepare role model for response
379 *
380 * @param AAM_Framework_AccessLevel_Role $role
381 * @param array $fields
382 *
383 * @return array
384 * @access private
385 *
386 * @version 7.0.0
387 */
388 private function _prepare_output($role, $fields = [])
389 {
390 $response = array(
391 'slug' => $role->slug,
392 'name' => translate_user_role($role->display_name),
393 );
394
395 // Adding additional information to each role
396 foreach($fields as $field) {
397 if ($field === 'capabilities') {
398 $response[$field] = $role->capabilities;
399 } elseif ($field === 'permissions') {
400 $response[$field] = $this->_get_role_permissions($role);
401 } elseif ($field === 'user_count') {
402 $response[$field] = $role->user_count;
403 } else {
404 $custom = apply_filters(
405 'aam_role_rest_field_filter', null, $role, $field
406 );
407
408 if ($custom !== null) {
409 $response[$field] = $custom;
410 }
411 }
412 }
413
414 return apply_filters(
415 'aam_rest_role_output_filter', $response, $role, $fields
416 );
417 }
418
419 /**
420 * Get list of actions user can perform upon role
421 *
422 * @param AAM_Framework_AccessLevel_Role $role
423 * @return array
424 *
425 * @version 7.0.0
426 */
427 private function _get_role_permissions($role)
428 {
429 $permissions = array('allow_manage');
430 $user_count = $role->user_count;
431
432 if (current_user_can('aam_edit_roles')) {
433 $permissions[] = 'allow_edit';
434
435 if ($user_count === 0) {
436 $permissions[] = 'allow_slug_update';
437 }
438 }
439
440 if (current_user_can('aam_create_roles')) {
441 $permissions[] = 'allow_clone';
442 }
443
444 if (current_user_can('aam_delete_roles') && ($user_count === 0)) {
445 $permissions[] = 'allow_delete';
446 }
447
448 return $permissions;
449 }
450
451 /**
452 * Determine list of additional fields to return
453 *
454 * @param WP_REST_Request $request
455 *
456 * @return array
457 * @access private
458 *
459 * @version 7.0.0
460 */
461 private function _determine_additional_fields(WP_REST_Request $request)
462 {
463 $fields = $request->get_param('fields');
464
465 return !empty($fields) ? wp_parse_list($fields) : [];
466 }
467
468 /**
469 * Validate the input field "fields"
470 *
471 * @param string|null $value Input value
472 *
473 * @return bool|WP_Error
474 * @access private
475 *
476 * @version 7.0.0
477 */
478 private function _validate_fields_input($value)
479 {
480 $response = true;
481
482 if (is_string($value) && strlen($value) > 0) {
483 $invalid_fields = [];
484
485 foreach(explode(',', $value) as $field) {
486 if (strlen(sanitize_key($field)) !== strlen($field)) {
487 $invalid_fields[] = $field;
488 }
489 }
490
491 if (count($invalid_fields) > 0) {
492 $response = new WP_Error(
493 'rest_invalid_param',
494 sprintf('Invalid fields: %s', implode(', ', $invalid_fields)),
495 array('status' => 400)
496 );
497 }
498 }
499
500 return $response;
501 }
502
503 /**
504 * Validate role slug and its uniqueness
505 *
506 * @param string $value Role slug (aka ID)
507 * @param WP_REST_Request $value Current request
508 *
509 * @return bool|WP_Error
510 * @access private
511 *
512 * @version 7.0.0
513 */
514 private function _validate_role_slug_uniqueness($value, WP_REST_Request $request)
515 {
516 $response = true;
517
518 if (is_string($value)) {
519 $slug = sanitize_key($value);
520
521 if ($slug === $request->get_param('slug')) {
522 $response = true; // do nothing, we do not update the slug
523 } elseif (strlen($slug) > 0) {
524 if (wp_roles()->is_role($slug)) {
525 $response = new WP_Error(
526 'rest_invalid_param',
527 sprintf("The role with '%s' slug already exists", $slug),
528 array('status' => 400)
529 );
530 }
531 } else {
532 $response = new WP_Error(
533 'rest_invalid_param',
534 sprintf("Invalid role slug '%s'", $value),
535 array('status' => 400)
536 );
537 }
538 }
539
540 return $response;
541 }
542
543 /**
544 * Validate the array of keys
545 *
546 * @param array|null $value Input array of values
547 *
548 * @return bool|WP_Error
549 * @access private
550 *
551 * @version 7.0.0
552 */
553 private function _validate_keys_array_input($value)
554 {
555 $response = true;
556
557 if (is_array($value) && count($value) > 0) {
558 $invalid_keys = [];
559
560 foreach($value as $key) {
561 if (strlen(sanitize_key($key)) !== strlen($key)) {
562 $invalid_keys[] = $key;
563 }
564 }
565
566 if (count($invalid_keys) > 0) {
567 $response = new WP_Error(
568 'rest_invalid_param',
569 sprintf('Invalid keys: %s', implode(', ', $invalid_keys)),
570 array('status' => 400)
571 );
572 }
573 }
574
575 return $response;
576 }
577
578 }