Structuring capabilities #274

This commit is contained in:
Leo Germani 2019-10-17 16:36:23 -03:00
parent 3e5abcbd57
commit eea135a5d2
4 changed files with 335 additions and 8 deletions

View File

@ -0,0 +1,241 @@
<?php
namespace Tainacan;
use Tainacan\Repositories\Repository;
class Roles {
public static $dependencies = [
"tainacan-items" => [
'edit_posts' => 'upload_files',
"edit_private_posts" => 'upload_files',
"edit_published_posts" => 'upload_files',
"edit_others_posts" => 'upload_files'
]
];
private static $instance = null;
private $capabilities;
public static function get_instance()
{
if(!isset(self::$instance))
{
self::$instance = new self();
}
return self::$instance;
}
/**
*
*/
private function __construct() {
$this->capabilities = [
'manage_tainacan' => [
'display_name' => __('Manage Tainacan', 'tainacan'),
'description' => __('Manage all Tainacan features and all Collections', 'tainacan')
],
'tnc_rep_edit_users' => [
'display_name' => __('Manage Users', 'tainacan'),
'description' => __('Manage users roles and permissions', 'tainacan')
],
'tnc_rep_create_collections' => [
'display_name' => __('Create Collections', 'tainacan'),
'description' => __('Create new collections to the repository', 'tainacan')
],
'tnc_rep_create_taxonomies' => [
'display_name' => __('Create and edit taxonomies', 'tainacan'),
'description' => __('Create new taxonomies and edit its terms', 'tainacan')
],
'tnc_rep_manage_taxonomies' => [
'display_name' => __('Manage Taxonomies', 'tainacan'),
'description' => __('Manage all taxonomies and terms, including taxonomies created by other users', 'tainacan')
],
'tnc_rep_manage_metadata' => [
'display_name' => __('Manage Repository Metadata', 'tainacan'),
'description' => __('Create/edit/delete metadata in repository level', 'tainacan')
],
'tnc_rep_manage_filters' => [
'display_name' => __('Manage Repository Filters', 'tainacan'),
'description' => __('Create/edit/delete filters in repository level', 'tainacan')
],
'tnc_rep_read_private_collections' => [
'display_name' => __('View private collections', 'tainacan'),
'description' => __('Access to view and browse private collections', 'tainacan')
],
'tnc_rep_read_private_taxonomies' => [
'display_name' => __('View private taxonomies', 'tainacan'),
'description' => __('Access to private taxonomies information', 'tainacan')
],
'tnc_rep_read_private_metadata' => [
'display_name' => __('View private repository metadata', 'tainacan'),
'description' => __('Access to private metadata in repository level', 'tainacan')
],
'tnc_rep_read_private_filters' => [
'display_name' => __('View private repository filters', 'tainacan'),
'description' => __('Access to private filters in repository level', 'tainacan')
],
'tnc_rep_read_logs' => [
'display_name' => __('View Logs', 'tainacan'),
'description' => __('Access to activities logs. Note that activity logs might contain information on private collections, items and metadata.', 'tainacan')
],
'tnc_rep_bulk_edit' => [
'display_name' => __('Bulk edit items', 'tainacan'),
'description' => __('Access to the Bulk edit items feature.', 'tainacan')
],
/**
* Collections capabilities
* There is a set of this capabilities for each collection, suffixed with collection ID
*/
'manage_tainacan_collection_%d' => [
'display_name' => __('Manage Collection', 'tainacan'),
'description' => __('Manage all collection settings, items, metadata, filters, etc.', 'tainacan')
],
'tnc_col_%d_edit' => [
'display_name' => __('Manage Collection settings', 'tainacan'),
'description' => __('Manage collection settings, such as name and description', 'tainacan'),
'dependencies' => [
'upload_files'
]
],
'tnc_col_%d_manage_metadata' => [
'display_name' => __('Manage metadata', 'tainacan'),
'description' => __('Create/edit/delete metadata in this collection', 'tainacan')
],
'tnc_col_%d_manage_filters' => [
'display_name' => __('Manage filters', 'tainacan'),
'description' => __('Create/edit/delete filters in this collection', 'tainacan')
],
'tnc_col_%d_read_private_metadata' => [
'display_name' => __('View private metadata', 'tainacan'),
'description' => __('Access private metadata in this collection', 'tainacan')
],
'tnc_col_%d_read_private_filters' => [
'display_name' => __('View private filters', 'tainacan'),
'description' => __('Access private filters in this collection', 'tainacan')
],
'tnc_col_%d_read_private_items' => [
'display_name' => __('View private items', 'tainacan'),
'description' => __('Access to view private items in this collection', 'tainacan')
],
'tnc_col_%d_edit_items' => [
'display_name' => __('Edit items', 'tainacan'),
'description' => __('Create and edit items in this collection', 'tainacan'),
'dependencies' => [
'upload_files'
]
],
'tnc_col_%d_publish_items' => [
'display_name' => __('Publish items', 'tainacan'),
'description' => __('Publish items in this collection', 'tainacan'),
'dependencies' => [
'upload_files'
]
],
'tnc_col_%d_edit_others_items' => [
'display_name' => __('Edit others items', 'tainacan'),
'description' => __('Edit items created by other users in this collection', 'tainacan'),
'dependencies' => [
'upload_files'
]
],
'tnc_col_%d_edit_published_items' => [
'display_name' => __('Edit published items', 'tainacan'),
'description' => __('Edit items in this collection after they are published', 'tainacan'),
'dependencies' => [
'upload_files'
]
],
];
add_filter( 'user_has_cap', [$this, 'user_has_cap_filter'], 10, 4 );
}
public function get_all_caps() {
return $this->capabilities;
}
public function get_all_caps_slugs() {
return array_keys($this->capabilities);
}
public function user_has_cap_filter( $allcaps, $caps, $args, $user ) {
$requested_cap = $args[0];
foreach ( $caps as $cap ) {
if ( array_key_exists($cap, $allcaps) && $allcaps[$cap] === true ) {
continue;
}
if ( \strpos($cap, 'tnc_') === 0 ) {
if ( $user->has_cap('manage_tainacan') ) {
$allcaps = array_merge($allcaps, [ $cap => true ]);
} elseif ( \strpos($cap, 'tnc_col_') === 0 ) {
$col_id = preg_replace('/[a-z_]+(\d+)[a-z_]+?$/', '$1', $cap );
if ( $user->has_cap('manage_tainacan_collection_' . $col_id) ) {
$allcaps = array_merge($allcaps, [ $cap => true ]);
}
}
}
}
return $allcaps;
}
protected function check_dependencies($role, $post_type, $cap, $add = true) {
if(
array_key_exists($post_type, self::$dependencies) &&
array_key_exists($cap, self::$dependencies[$post_type])
) {
$added = false;
if(! $role->has_cap(self::$dependencies[$post_type][$cap]) && $add) {
$role->add_cap(self::$dependencies[$post_type][$cap]);
$added = true;
}
if($role instanceof \WP_User && $add) { //moderator
$append_caps = get_user_meta($role->ID, '.tainacan-dependecies-caps', true);
if(! is_array($append_caps)) $append_caps = [];
if(
(! array_key_exists(self::$dependencies[$post_type][$cap], $append_caps) && $added ) || // we never added and need to add
(
array_key_exists(self::$dependencies[$post_type][$cap], $append_caps) &&
$append_caps[self::$dependencies[$post_type][$cap]] === false &&
$added
) // we added but before is not need to add
) {
$append_caps[self::$dependencies[$post_type][$cap]] = 0;
}
else { // we to not added this cap
$append_caps[self::$dependencies[$post_type][$cap]] = false;
}
if($append_caps[self::$dependencies[$post_type][$cap]] !== false) {
$append_caps[self::$dependencies[$post_type][$cap]]++; // add 1 to each collection he is a moderator
update_user_meta($role->ID, '.tainacan-dependecies-caps', $append_caps);
}
}
return self::$dependencies[$post_type][$cap];
}
return false;
}
}

View File

@ -145,21 +145,35 @@ class Collection extends Entity {
/**
* Get the capabilities list for the post type of the items of this collection
*
* @uses get_post_type_capabilities to get the list.
*
* This method is usefull for getting the capabilities of the collection's items post type
* regardless if it has been already registered or not.
*
* @return object Object with all the capabilities as member variables.
*/
function get_items_capabilities() {
$args = [
'map_meta_cap' => true,
'capability_type' => $this->get_db_identifier(),
'capabilities' => array()
];
$id = $this->get_id();
return get_post_type_capabilities( (object) $args );
return (object) [
// meta
'edit_post' => "tnc_col_{$id}_edit_item",
'read_post' => "tnc_col_{$id}_edit_item",
'delete_post' => "tnc_col_{$id}_edit_item",
// primitive
'edit_posts' => "tnc_col_{$id}_edit_items",
'edit_others_posts' => "tnc_col_{$id}_edit_others_items",
'publish_posts' => "tnc_col_{$id}_publish_items",
'read_private_posts' => "tnc_col_{$id}_read_private_items",
'read' => "read",
'delete_posts' => "tnc_col_{$id}_edit_items",
'delete_private_posts' => "tnc_col_{$id}_edit_items",
'delete_published_posts' => "tnc_col_{$id}_edit_published_items",
'delete_others_posts' => "tnc_col_{$id}_edit_others_items",
'edit_private_posts' => "tnc_col_{$id}_edit_others_items",
'edit_published_posts' => "tnc_col_{$id}_edit_published_items",
'create_posts' => "tnc_col_{$id}_edit_items"
];
}
/**

View File

@ -179,6 +179,8 @@ $Tainacan_Importer_Heartbeat = new \Tainacan\Background_Importer_Heartbeat();
$Tainacan_Capabilities = \Tainacan\Capabilities::get_instance();
$Tainacan_Roles = \Tainacan\Roles::get_instance();
$TainacanPrivateFiles = \Tainacan\Private_Files::get_instance();
if (class_exists('WP_CLI')) {

View File

@ -0,0 +1,70 @@
<?php
namespace Tainacan\Tests;
use Tainacan\Entities\Collection;
/**
* Class Capabilities
*
* @package Test_Tainacan
*/
/**
* @group permissions
*/
class Capabilities extends TAINACAN_UnitTestCase {
function setUp() {
parent::setUp();
$subscriber = $this->factory()->user->create(array( 'role' => 'subscriber' ));
$this->subscriber = get_userdata( $subscriber );
}
/**
*
*/
function test_super_manage_tainacan () {
$this->assertFalse( user_can($this->subscriber, 'tnc_rep_manage_taxonomies') );
$this->subscriber->add_cap('manage_tainacan');
$this->subscriber->get_role_caps();
$this->assertTrue( user_can($this->subscriber, 'tnc_rep_manage_taxonomies') );
}
function test_super_manage_tainacan_collection () {
$this->assertFalse( user_can($this->subscriber, 'tnc_col_25_read_private_filters') );
$this->subscriber->add_cap('manage_tainacan_collection_25');
$this->subscriber->get_role_caps();
$this->assertTrue( user_can($this->subscriber, 'tnc_col_25_read_private_filters') );
$this->assertFalse( user_can($this->subscriber, 'tnc_col_36_read_private_filters') );
}
function test_items_capabilities() {
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'Javascript Frameworks',
'description' => 'The best framework to javascript',
'status' => 'publish'
),
true
);
$caps = $collection->get_items_capabilities();
}
}