This commit is contained in:
weryques 2018-02-22 13:13:41 -03:00
commit 360876c89a
23 changed files with 635 additions and 298 deletions

View File

@ -4,283 +4,348 @@
A REST API for Tainacan Plugin. This API uses the Wordpress REST API.
------
### Routes and Endpoints
#### Summary
1. [Collections](#collections)
1. [Items](#items)
1. [Fields](#fields)
1. [Item Metadata](#item-metadata)
1. [Taxonomies](#taxonomies)
1. [Filters](#filters)
1. [Terms](#terms)
1. [Logs](#logs)
1. [Others](#others)
------
#### Collections
1. Route `wp-json/tainacan/v2/collections/(?P<collection_id>[\d]+)`
1.1. Endpoints supported:
1. Endpoints supported:
1.1.1 GET (Fetch a collection)
1.1.2 DELETE (Delete or Trash a collection and all your dependencies)
```
To delete pass in body of a requisition the parameter is_permanently as true.
To only trash pass false.
```
1.1.3 PATCH or PUT (Update a collection)
1. GET (Fetch a collection)
     
1. DELETE (Delete or Trash a collection and all your dependencies)
*To delete pass in body of a requisition the parameter `is_permanently` as true. To only trash pass false.*
1. PATCH or PUT (Update a collection)
Example of JSON passed in body for updating a collection:
Example of JSON passed in body for updating a collection:
   
```
{
   "name": "string",
   "description": "string",
...
 }
```javascript
{
"name": "string",
"description": "string",
...
}
```
2. Route `wp-json/tainacan/v2/collections`
2.1. Endpoints supported:
1. Endpoints supported:
2.1.1 GET (Fetch all collections)
1. GET (Fetch all collections)
2.1.2 POST (Create a collection).
1. POST (Create a collection).
Example of JSON passed in body for creating a collection:
Example of JSON passed in body for creating a collection:
```javascript
{
  "name": "string",
   "description": "string",
   "status": "string",
   "order": "string",
   "parent": "integer",
   "slug": "string",
   "default_orderby": "string",
   "default_order": "string",
   "columns": "string",
   "default_view_mode": "string"
 }
{
"name": "string",
"description": "string",
"status": "string",
"order": "string",
"parent": "integer",
"slug": "string",
"default_orderby": "string",
"default_order": "string",
"columns": "string",
"default_view_mode": "string"
}
```
------
#### Items
1. Route `wp-json/tainacan/v2/collection/(?P<collection_id>[\d]+)/items`
1.1. Endpoints supported:
1. Endpoints supported:
1.1.1 GET (Fetch all items from a collection)
1. GET (Fetch all items from a collection)
1.1.2 POST (Create a item in a collection)
Example of JSON passed in body for creating a item:
1. POST (Create a item in a collection)
Example of JSON passed in body for creating a item:
```javascript
{
  "title": "string",
   "description": "string",
   "status": "string",
 }
{
"title": "string",
"description": "string",
"status": "string",
}
```
2. Route `wp-json/tainacan/v2/items/(?P<item_id>[\d]+)`
2.1. Endpoints supported:
1. Endpoints supported:
2.1.1 GET (Fetch a item)
1. GET (Fetch a item)
2.1.2 DELETE (Delete or Trash a item and all your dependencies)
1. DELETE (Delete or Trash a item and all your dependencies)
```
To delete pass in body of a requisition the parameter is_permanently as true.
To only trash pass false.
```
*To delete pass in body of a requisition the parameter is_permanently as true. To only trash pass false.*
2.1.3 PATCH or PUT (Update a item)
1. PATCH or PUT (Update a item)
Example of JSON passed in body for updating a item:
Example of JSON passed in body for updating a item:
   
```
{
   "title": "string",
   "description": "string",
...
 }
```javascript
{
"title": "string",
"description": "string",
...
}
```
#### Metadata
------
#### Fields
1. Route `wp-json/tainacan/v2/collection/(?P<collection_id>[\d]+)/metadata`
1. Route `wp-json/tainacan/v2/collection/(?P<collection_id>[\d]+)/fields`
1.1. Endpoints supported:
1. Endpoints supported:
1. GET (Fetch all collection field)
1. POST (Create a field in collection and all it items)
1.1.1 POST (Create a metadata in collection and all your items)
In body of requisition pass a JSON with the attributes of metadata like:
In body of requisition pass a JSON with the attributes of field like:
```javascript
{
      "name": "string",
      "description": "string",
      "field_type": "string",
      "order": "string",
      "parent": "integer",
      "required": "string",
      "collection_key": "string",
      "multiple": "string",
      "cardinality": "string",
      "privacy": "string",
      "mask": "string",
      "default_value": "string",
      "field_type_options": "string",
   }
{
"name": "string",
"description": "string",
"field_type": "string",
"order": "string",
"parent": "integer",
"required": "string",
"collection_key": "string",
"multiple": "string",
"cardinality": "string",
"privacy": "string",
"mask": "string",
"default_value": "string",
"field_type_options": "string",
}
```
2. Route `wp-json/tainacan/v2/collection/(?P<collection_id>[\d]+)/fields/(?P<field_id>[\d]+)`
1. Endpoints supported:
1. PATCH or PUT (Update a field in a collection and all it items)
In body of requisition pass a JSON with the attributes you need to update, like:
```javascript
{
"name": "string",
"description": "string",
}
```
------
#### Item Metadata
1. Route `wp-json/tainacan/v2/item/(?P<item_id>[\d]+)/metadata/(?P<metadata_id>[\d]+)`
1. Endpoints supported:
1.1.2 GET (Fetch all collection metadata)
1. PATCH or PUT (Set value of a metadata)
In body of requisition pass a JSON with values of metadata, like:
```javascript
{
"values": [
{ "new": "any_type", "prev": "any_type"},
{ "new": "any_type", "prev": ""}
]
}
```
2. Route `wp-json/tainacan/v2/item/(?P<item_id>[\d]+)/metadata`
2.1. Endpoints supported:
2.1.1 POST (Set a value of item metadata)
In body of requisition pass a JSON with value e and id of metadata like:
```javascript
{
    "metadata_id": "integer",
    "values": "[any, type]"
 }
```
1. Enpoints supported:
2.1.2 GET (Fetch all item metadata, with your values)
1. GET (Fetch all item metadata, with it values)
------
#### Taxonomies
1. Route `wp-json/tainacan/v2/taxonomies`
1.1. Endpoints supported:
1. Endpoints supported:
1.1.1. GET (Fetch all taxonomies)
1. GET (Fetch all taxonomies)
1.1.2. POST (Create a taxonomy)
1. POST (Create a taxonomy)
Example of JSON passed in body for creating a taxonomy:
Example of JSON passed in body for creating a taxonomy:
```javascript
{
  "name": "string",
   "description": "string",
   "status": "string",
   "parent": "string",
   "slug": "string",
   "allow_insert": "string",
   "collections_ids": "array"
 }
{
"name": "string",
"description": "string",
"status": "string",
"parent": "string",
"slug": "string",
"allow_insert": "string",
"collections_ids": "array"
}
```
2. Route `wp-json/tainacan/v2/taxonomies/(?P<taxonomy_id>[\d]+)`
2.1. Endpoints supported:
1. Endpoints supported:
2.1.1 GET (Fetch a taxonomy)
1. GET (Fetch a taxonomy)
2.1.2 DELETE (Delete or trash a taxonomy)
```
To delete pass in body of requisition the parameter is_permanently as true.
To only trash pass false.
```
1. DELETE (Delete or trash a taxonomy)
2.1.3 PATCH or PUT (Update a taxonomy)
*To delete pass in body of requisition the parameter is_permanently as true. To only trash pass false.*
1. PATCH or PUT (Update a taxonomy)
Example of JSON passed in body for updating a taxonomy:
Example of JSON passed in body for updating a taxonomy:
   
```javascript
{
   "name": "string",
   "description": "string",
...
 }
{
"name": "string",
"description": "string",
...
}
```
3. Route `wp-json/tainacan/v2/taxonomies/(?P<taxonomy_id>[\d]+)/collection/(?P<collection_id>[\d]+)`
1. Routes supported:
1. PATCH or PUT (Add a Collection in a Taxonomy)
------
#### Filters
1. Route `wp-json/tainacan/v2/filters`
1.1 Endpoints supported:
1. Route `wp-json/tainacan/v2/collection/(?P<collection_id>[\d]+)/field/(?P<field_id>[\d]+)/filters`
1.1.1 POST (Create a filter)
1. Endpoints supported:
Example of JSON passed in body for creating a filter:
1. POST (Create a filter)
```javascript
{
  "collection_id": "int",
  "metadata_id": "int",
"filter_type": "string",
  "filter": {
    "name": "string",
    "description": "string",
...
  }
}
```
1.1.2 GET (Fetch all filters)
2. Route `wp-json/tainacan/v2/filters/(?P<filter_id>[\d]+)`
2.1. Endpoints supported:
2.1.1 DELETE (Delete or trash a filter)
```
To delete pass in body of requisition the parameter is_permanently as true.
To only trash pass false.
```
2.1.2 PATCH or PUT (Update a filter)
Example of JSON passed in body for updating a filter:
Example of JSON passed in body for creating a filter:
```javascript
{
"name": "string",
...
}
{
"filter_type": "string",
"filter": {
"name": "string",
"description": "string",
...
}
}
```
2.1.3 GET (Fetch a filter)
2. Route `wp-json/tainacan/v2/filters/(?P<filter_id>[\d]+)`
1. Endpoints supported:
1. GET (Fetch a filter)
1. DELETE (Delete or trash a filter)
*To delete pass in body of requisition the parameter is_permanently as true. To only trash pass false.*
1. PATCH or PUT (Update a filter)
Example of JSON passed in body for updating a filter:
```javascript
{
"name": "string",
...
}
```
3. Route `wp-json/tainacan/v2/filters`
1. Endpoints supported:
1. GET (Fetch all filters)
------
#### Terms
1. Route `wp-json/tainacan/v2/taxonomy/(?P<taxonomy_id>[\d]+)/terms`
1.1 Endpoints supported:
1. Endpoints supported:
1. GET (Fetch all tems of a taxonomy)
1.1.1 POST (Create a term in a taxonomy)
Example of JSON passed in body for creating a term:
1. POST (Create a term in a taxonomy)
Example of JSON passed in body for creating a term:
```javascript
{
  "name": "string",
  "user": "int",
...
}
```
   1.1.2 GET (Fetch all tems of a taxonomy)
{
"name": "string",
"user": "int",
...
}
```
2. Route `wp-json/tainacan/v2/taxonomy/(?P<taxonomy_id>[\d]+)/terms/(?P<term_id>[\d]+)`
2.1 Endpoints supported:
1. Endpoints supported:
2.1.1 GET (Fecth a term of a taxonomy)
1. GET (Fecth a term of a taxonomy)
1. DELETE (Delete a term of a taxonoy)
2.1.2 PATCH or PUT (Update a term in a taxonomy)
1. PATCH or PUT (Update a term in a taxonomy)
Example of JSON passed in body for updating a term:
Example of JSON passed in body for updating a term:
```javascript
{
  "name": "string",
...
}
{
"name": "string",
...
}
```
2.1.3 DELETE (Delete a term of a taxonoy)
------
#### Logs
1. Route `wp-json/tainacan/v2/logs`
1. Endpoints supported:
1. GET (Get all logs)
2. Route `wp-json/tainacan/v2/logs/(?P<log_id>[\d]+)`
1. Enpoints supported:
1. GET (Get a log)
------
#### Others
To Create, Read, Update or Delete Media or Users you can use the default routes of Wordpress.
See about Media in [Media | REST API Handbook](https://developer.wordpress.org/rest-api/reference/media/);
See about Users in [Users | REST API Handbook](https://developer.wordpress.org/rest-api/reference/users/).

View File

@ -233,7 +233,12 @@ class TAINACAN_REST_Items_Controller extends WP_REST_Controller {
* @throws Exception
*/
public function create_item_permissions_check( $request ) {
return $this->items_repository->can_edit($this->item);
$collection = $this->collections_repository->fetch($request['collection_id']);
if ($collection instanceof Entities\Collection) {
return $collection->get_items_capabilities()->edit_posts;
}
return false;
}
/**

View File

@ -39,7 +39,10 @@ class TAINACAN_REST_Metadata_Controller extends WP_REST_Controller {
* Both of GETs return the metadata of matched objects
*/
public function register_routes() {
register_rest_route($this->namespace, '/' . $this->rest_base . '/collection/(?P<collection_id>[\d]+)',
/*
Removing this undocumented endpoint.. it seems wrong.
register_rest_route($this->namespace, '/' . $this->rest_base . '/collection/(?P<collection_id>[\d]+)',
array(
array(
'methods' => WP_REST_Server::READABLE,
@ -64,6 +67,7 @@ class TAINACAN_REST_Metadata_Controller extends WP_REST_Controller {
)
)
);
*/
register_rest_route($this->namespace, '/' . $this->rest_base . '/item/(?P<item_id>[\d]+)',
array(
array(
@ -328,6 +332,8 @@ class TAINACAN_REST_Metadata_Controller extends WP_REST_Controller {
}
}
// We need to rethink this endpoint. Its confusing...
// and there is no need to iterato through all items...
$collection_id = $request['collection_id'];
$body = json_decode($request->get_body(), true);
@ -374,7 +380,7 @@ class TAINACAN_REST_Metadata_Controller extends WP_REST_Controller {
*/
public function update_item_permissions_check( $request ) {
$item = $this->item_repository->fetch($request['item_id'] ? $request['item_id'] : $request['collection_id']);
return $this->item_repository->can_edit($item);
return $this->item_repository->can_edit($item);
}
}

View File

@ -130,7 +130,11 @@ class TAINACAN_REST_Terms_Controller extends WP_REST_Controller {
* @return bool|WP_Error
*/
public function create_item_permissions_check( $request ) {
return $this->terms_repository->can_edit($this->term);
$taxonomy = $this->taxonomy_repository->fetch($request['taxonomy_id']);
if ($taxonomy instanceof Entities\Taxonomy) {
return $taxonomy->can_edit();
}
return false;
}
/**
@ -163,8 +167,11 @@ class TAINACAN_REST_Terms_Controller extends WP_REST_Controller {
* @return bool|WP_Error
*/
public function delete_item_permissions_check( $request ) {
$term = new Entities\Term($this->terms_repository->fetch($request['term_id']));
return $this->terms_repository->can_delete($term);
$taxonomy = $this->taxonomy_repository->fetch($request['taxonomy_id']);
if ($taxonomy instanceof Entities\Taxonomy) {
return $taxonomy->can_edit();
}
return false;
}
/**
@ -209,8 +216,11 @@ class TAINACAN_REST_Terms_Controller extends WP_REST_Controller {
* @return bool|WP_Error
*/
public function update_item_permissions_check( $request ) {
$term = new Entities\Term($this->terms_repository->fetch($request['term_id']));
return $this->terms_repository->can_edit($term);
$taxonomy = $this->taxonomy_repository->fetch($request['taxonomy_id']);
if ($taxonomy instanceof Entities\Taxonomy) {
return $taxonomy->can_edit();
}
return false;
}
/**

View File

@ -277,6 +277,11 @@ class Capabilities {
function __construct() {
add_action('init', array(&$this, 'init'), 11);
add_action('tainacan-insert-tainacan-collections', array(&$this, 'new_collection'));
add_action('tainacan-add-collection-moderators', array(&$this, 'add_moderators'), 10, 2);
add_action('tainacan-remove-collection-moderators', array(&$this, 'remove_moderators'), 10, 2);
}
/**
@ -314,9 +319,9 @@ class Capabilities {
*/
public function set_items_capabilities($collection, $defaults_caps = null) {
if(is_null($defaults_caps)) $defaults_caps = apply_filters('tainacan-defaults-capabilities', $this->defaults); // External Call
$item = new \Tainacan\Entities\Item();
$item->set_collection($collection);
$collection_items_caps = $collection->get_items_capabilities();
foreach ($defaults_caps['tainacan-items'] as $role_name => $caps) {
$role = get_role($role_name);
if(!is_object($role)) {
@ -324,7 +329,7 @@ class Capabilities {
}
foreach ($caps as $cap) {
$role->add_cap($collection->cap->$cap);
$role->add_cap($collection_items_caps->$cap);
}
}
}
@ -353,4 +358,53 @@ class Capabilities {
{
$this->set_items_capabilities($collection);
}
/**
* Hooke to revoke the capabilities for the items post type of the collection
* @param \Tainacan\Entities\Collection $collection The collection object
* @param array $moderators List of IDs of user IDs removed from the moderators list of the collection
* @return void
*/
public function remove_moderators($collection, $moderators) {
$defaults_caps = apply_filters('tainacan-defaults-capabilities', $this->defaults);
if (is_array($moderators)) {
$collection_items_caps = $collection->get_items_capabilities();
foreach ($moderators as $moderator) {
$user = get_userdata($moderator);
if ($user instanceof \WP_User && is_object($collection_items_caps)) {
$caps = $defaults_caps['tainacan-items']['editor'];
foreach ($caps as $cap) {
$user->remove_cap($collection_items_caps->$cap);
}
}
}
}
}
/**
* Hooke to grant the capabilities for the items post type of the collection
* @param \Tainacan\Entities\Collection $collection The collection object
* @param array $moderators List of IDs of user IDs added to the moderators list of the collection
* @return void
*/
public function add_moderators($collection, $moderators) {
$defaults_caps = apply_filters('tainacan-defaults-capabilities', $this->defaults);
if (is_array($moderators)) {
$collection_items_caps = $collection->get_items_capabilities();
foreach ($moderators as $moderator) {
$user = get_userdata($moderator);
if ($user instanceof \WP_User && is_object($collection_items_caps)) {
$caps = $defaults_caps['tainacan-items']['editor'];
foreach ($caps as $cap) {
$user->add_cap($collection_items_caps->$cap);
}
}
}
}
}
}

View File

@ -64,6 +64,7 @@ class Collection extends Entity {
);
$cpt_slug = $this->get_db_identifier();
$capabilities = $this->get_items_capabilities();
$args = array(
'labels' => $cpt_labels,
@ -84,7 +85,7 @@ class Collection extends Entity {
'slug' => $this->get_slug()
],
'map_meta_cap' => true,
'capability_type' => $this->get_db_identifier(),
'capabilities' => (array) $capabilities,
'supports' => [
'title',
'editor',
@ -100,6 +101,26 @@ class Collection extends Entity {
return register_post_type($cpt_slug, $args);
}
/**
* 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()
];
return get_post_type_capabilities((object) $args);
}
/**
* Get collection name
@ -322,6 +343,42 @@ class Collection extends Entity {
$this->set_mapped_property('moderators_ids', $value);
}
// Moderators methods
/**
* Add a moderator ID to the moderators_ids list
* @param int $user_id The user ID to be added
* @return boolean Wether the ID was added or not. (if it already existed in the list it returns false)
*/
function add_moderator_id($user_id) {
if (is_integer($user_id)) {
$current_moderators = $this->get_moderators_ids();
if (!in_array($user_id, $current_moderators)) {
$current_moderators[] = $user_id;
$this->set_moderators_ids($current_moderators);
return true;
}
}
return false;
}
/**
* Remove a moderator ID to the moderators_ids list
* @param int $user_id The user ID to be removed
* @return boolean Wether the ID was added or not. (if it did not exist in the list it returns false)
*/
function remove_moderator_id($user_id) {
if (is_integer($user_id)) {
$current_moderators = $this->get_moderators_ids();
if (($key = array_search($user_id, $current_moderators)) !== false) {
unset($current_moderators[$key]);
$this->set_moderators_ids($current_moderators);
return true;
}
}
return false;
}
/**
* TODO implement the following methods to handle moderators_ids
*
@ -329,10 +386,6 @@ class Collection extends Entity {
* get_moderators
* (the same as moderators_ids but gets and sets WP_User objects)
*
* add_moderator_id
* remove moderator_id
* (add or remove one moderator from the moderators_ids array)
*
*/
}

View File

@ -94,6 +94,7 @@ class Entity {
}
if(
is_int($which) &&
$this->WP_Post instanceof \WP_Post &&
$which != 0 &&
(
( $this->get_post_type() !== false && $this->WP_Post->post_type != $this->get_post_type() ) ||
@ -111,11 +112,14 @@ class Entity {
if($this->get_post_type() !== false) {
$post_type_obj = get_post_type_object(self::get_post_type());
if(!is_object($post_type_obj)) { //may be called before post_type registration
global ${$this->repository};
${$this->repository}->register_post_type();
$post_type_obj = get_post_type_object(self::get_post_type());
throw new \Exception(sprintf("The post type %s need to be registered, need the init hook!"));
}
$this->cap = $post_type_obj->cap;
} elseif ($this instanceof Item) {
$item_collection = $this->get_collection();
if ($item_collection) {
$this->cap = $item_collection->get_items_capabilities();
}
}
}

View File

@ -179,20 +179,16 @@ class Item extends Entity {
* set meta cap object
*/
protected function set_cap() {
$db_identifier = $this->get_db_identifier();
if(!empty($db_identifier))
{
$post_type_obj = get_post_type_object($db_identifier);
if(!is_object($post_type_obj)) { //may be called before post_type registration
$collection = $this->get_collection();
if(is_object($collection)) {
$post_type_obj = $collection->register_collection_item_post_type();
}
if(!empty($this->get_db_identifier())) {
$db_identifier = Collection::$db_identifier_prefix.$this->get_db_identifier().Collection::$db_identifier_sufix;
if(!empty($db_identifier))
{
$post_type_obj = get_post_type_object($db_identifier);
if(!is_object($post_type_obj)) {
throw new \Exception(sprintf("Collection post type (%s) is not setted and cannot be registred", $db_identifier));
}
$this->cap = $post_type_obj->cap;
}
if(!is_object($post_type_obj)) {
throw new \Exception(sprintf("Collection post type (%s) is not setted and cannot be registred", $db_identifier));
}
$this->cap = $post_type_obj->cap;
} //TODO Item without collection? treat as error?
}
}
}

View File

@ -152,7 +152,7 @@ class Metadata extends Entity {
function get_field_options(){
return $this->get_mapped_property('field_type_options');
}
/**
* Set the metadata name
*

View File

@ -13,7 +13,7 @@ class Collections extends Repository {
public function __construct() {
parent::__construct();
add_filter('user_has_cap', array($this, 'user_has_cap'), 10, 3);
add_filter('map_meta_cap', array($this, 'map_meta_cap'), 10, 4);
}
/**
* {@inheritDoc}
@ -171,8 +171,11 @@ class Collections extends Repository {
* @see \Tainacan\Repositories\Repository::insert()
*/
public function insert($collection){
$new_collection = parent::insert($collection);
$collection->register_collection_item_post_type();
$this->pre_update_moderators($collection);
$new_collection = parent::insert($collection);
$collection->register_collection_item_post_type();
$this->update_moderators($new_collection);
return $new_collection;
}
@ -219,7 +222,13 @@ class Collections extends Repository {
*/
public function fetch($args = [], $output = null){
if(is_numeric( $args )){
return new Entities\Collection($args);
$existing_post = get_post($args);
if ($existing_post instanceof \WP_Post) {
return new Entities\Collection($existing_post);
} else {
return [];
}
} elseif(is_array($args)) {
$args = array_merge([
'posts_per_page' => -1,
@ -242,43 +251,66 @@ class Collections extends Repository {
}
function pre_update_moderators($collection) {
$current_moderators = $this->get_mapped_property($collection, 'moderators_ids');
$this->current_moderators = is_array($current_moderators) ? $current_moderators : [];
}
function update_moderators($collection) {
$moderators = $collection->get_moderators_ids();
$deleted = array_diff($this->current_moderators, $moderators);
$added = array_diff($moderators, $this->current_moderators);
do_action('tainacan-add-collection-moderators', $collection, $added);
do_action('tainacan-remove-collection-moderators', $collection, $deleted);
}
/**
* Filter to handle special permissions
*
* @see https://codex.wordpress.org/Plugin_API/Filter_Reference/user_has_cap
*
* Filter on the current_user_can() function.
* This function is used to explicitly allow authors to edit contributors and other
* authors posts if they are published or pending.
*
* @param array $allcaps All the capabilities of the user
* @param array $cap [0] Required capability
* @param array $args [0] Requested capability
* [1] User ID
* [2] Associated object ID
*/
public function user_has_cap($allcaps, $cap, $args) {
if(count($args) > 2) {
$entity = Repository::get_entity_by_post($args[2]);
$collection = false;
if($entity) {
if($entity instanceof Entities\Collection) { // TODO others entity types
$collection = $entity;
}
if($entity instanceof Entities\Item) { // TODO others entity types
$collection = $entity->get_collection();
}
if($collection) {
$moderators = $collection->get_moderators_ids();
if (is_array($moderators) && in_array($args[1], $moderators)) {
$allcaps[$cap[0]] = true;
}
}
}
}
return $allcaps;
* @see https://developer.wordpress.org/reference/hooks/map_meta_cap/
*
*/
public function map_meta_cap($caps, $cap, $user_id, $args) {
// Filters meta caps edit_tainacan-collection and check if user is moderator
if ($cap == 'edit_post') { // edit_tainacan-colletion is mapped to edit_post
$entity = $args[0];
if (is_numeric($entity) || $entity instanceof Entities\Collection) {
if (is_numeric($entity)) {
$post = get_post($entity);
if ($post instanceof \WP_Post && $post->post_type == Entities\Collection::get_post_type()) {
$entity = new Entities\Collection($post);
}
}
if ($entity instanceof Entities\Collection) {
$moderators = $entity->get_moderators_ids();
if (is_array($moderators) && in_array($user_id, $moderators)) {
// if user is moderator, we clear the current caps
// (that might fave edit_others_posts) and leave only read, that everybody has
$collection_cpt = get_post_type_object(Entities\Collection::get_post_type());
$caps = ['read'];
}
}
}
}
return $caps;
}
}

View File

@ -104,7 +104,7 @@ class Filters extends Repository {
'can_export' => true,
'rewrite' => true,
'map_meta_cap' => true,
'capability_type' => Entities\Filter::get_post_type(),
'capability_type' => 'tainacan-filter',
'supports' => [
'title',
'editor',
@ -198,7 +198,13 @@ class Filters extends Repository {
*/
public function fetch($args = [], $output = null){
if( is_numeric($args) ){
return new Entities\Filter($args);
$existing_post = get_post($args);
if ($existing_post instanceof \WP_Post) {
return new Entities\Filter($existing_post);
} else {
return [];
}
} elseif (is_array($args)) {
// TODO: get filters from parent collections
$args = array_merge([

View File

@ -149,7 +149,13 @@ class Items extends Repository {
global $Tainacan_Collections;
if(is_numeric($args)){
return new Entities\Item($args);
$existing_post = get_post($args);
if ($existing_post instanceof \WP_Post) {
return new Entities\Item($existing_post);
} else {
return [];
}
}
if (empty($collections)){

View File

@ -157,7 +157,13 @@ class Logs extends Repository {
*/
public function fetch($args = [], $output = null){
if(is_numeric($args)){
return new Entities\Log($args);
$existing_post = get_post($args);
if ($existing_post instanceof \WP_Post) {
return new Entities\Log($existing_post);
} else {
return [];
}
} elseif (is_array($args)) {
$args = array_merge([
'post_status' => 'publish',

View File

@ -233,7 +233,12 @@ class Metadatas extends Repository {
public function fetch( $args, $output = null ) {
if( is_numeric($args) ){
return new Entities\Metadata($args);
$existing_post = get_post($args);
if ($existing_post instanceof \WP_Post) {
return new Entities\Metadata($existing_post);
} else {
return [];
}
} elseif (is_array($args)) {
$args = array_merge([

View File

@ -387,13 +387,13 @@ abstract class Repository {
/**
* Check if $user can edit/create a entity
*
* @param int|array|\WP_Post|Entities\Entity $entity
* @param Entities\Entity $entity
* @param int|\WP_User|null $user default is null for the current user
*
* @return boolean
* @throws \Exception
*/
public function can_edit($entity, $user = null) {
public function can_edit(Entities\Entity $entity, $user = null) {
if(is_null($user)) {
$user = get_current_user_id();
}
@ -402,12 +402,17 @@ abstract class Repository {
}
$entity = self::get_entity_by_post($entity);
$post_type = $entity::get_post_type();
if($post_type === false) { // There is no post
return user_can($user, 'edit_posts');
}
return user_can($user, $entity->cap->edit_post, $entity);
if (!isset($entity->cap->edit_post)) {
return false;
}
if (is_integer($entity->get_id())) {
return user_can($user, $entity->cap->edit_post, $entity->get_id());
} else {
// creating new
return user_can($user, $entity->cap->edit_posts);
}
}
/**
@ -428,12 +433,14 @@ abstract class Repository {
}
$entity = self::get_entity_by_post($entity);
$post_type = $entity::get_post_type();
if($post_type === false) { // There is no post
return user_can($user, 'read');
}
if (!isset($entity->cap->read)) {
if($entity->get_post_type() === false) { // Allow read of not post entities
return true;
}
return false;
}
return user_can($user, $entity->cap->read_post, $entity);
return user_can($user, $entity->cap->read, $entity->get_id());
}
/**
@ -453,12 +460,12 @@ abstract class Repository {
$user = $user->ID;
}
$entity = self::get_entity_by_post($entity);
$post_type = $entity::get_post_type();
if($post_type === false) { // There is no post
return user_can($user, 'delete_posts');
}
if (!isset($entity->cap->delete_post)) {
return false;
}
return user_can($user, $entity->cap->delete_post, $entity);
return user_can($user, $entity->cap->delete_post, $entity->get_id());
}
/**
@ -478,13 +485,12 @@ abstract class Repository {
$user = $user->ID;
}
$entity = self::get_entity_by_post($entity);
$post_type = $entity::get_post_type();
if($post_type === false) { // There is no post
return user_can($user, 'publish_posts');
if (!isset($entity->cap->publish_posts)) {
return false;
}
return user_can($user, $entity->cap->publish_posts, $entity);
return user_can($user, $entity->cap->publish_posts, $entity->get_id());
}
}
?>
?>

View File

@ -162,7 +162,12 @@ class Taxonomies extends Repository {
// TODO: Pegar taxonomias registradas via código
if( is_numeric($args) ){
return new Entities\Taxonomy($args);
$existing_post = get_post($args);
if ($existing_post instanceof \WP_Post) {
return new Entities\Taxonomy($existing_post);
} else {
return [];
}
} elseif (is_array($args)) {
$args = array_merge([

View File

@ -24,7 +24,7 @@ trait Entity_Collection_Relation {
/**
* Return Collection from relation
* @return \Entities\Collection|NULL Return Collection or null on errors
* @return Entities\Collection|NULL Return Collection or null on errors
*/
public function get_collection() {
if (isset($this->collection) && $this->collection instanceof Entities\Collection)

View File

@ -39,7 +39,7 @@ class TAINACAN_REST_Collections_Controller extends TAINACAN_UnitApiTestCase {
$request->set_body($collection_JSON);
$response = $this->server->dispatch( $request );
$this->assertEquals( 201, $response->get_status() );
$this->assertEquals( 201, $response->get_status(), sprintf('response: %s', print_r($response, true)) );
$collection = $response->get_data();
$id = $collection['id'];

View File

@ -44,7 +44,7 @@ class TAINACAN_REST_Terms_Controller extends TAINACAN_UnitApiTestCase {
$response = $this->server->dispatch($request);
$data = $response->get_data();
$this->assertTrue(is_array($data) && array_key_exists('filter_type', $data), sprintf('cannot create a range, response: %s', print_r($data, true)));
$this->assertEquals('Tainacan\Filter_Types\Range', $data['filter_type']);
$this->assertEquals('Filter name', $data['name']);
}

View File

@ -31,7 +31,7 @@ class TAINACAN_REST_Metadata_Controller extends TAINACAN_UnitApiTestCase {
'field_type' => $field->get_primitive_type(),
)
);
/*
$request = new \WP_REST_Request(
'POST',
$this->namespace . '/metadata/collection/' . $collection->get_id()
@ -41,8 +41,9 @@ class TAINACAN_REST_Metadata_Controller extends TAINACAN_UnitApiTestCase {
$response = $this->server->dispatch($request);
$metadata_added = $response->get_data();
$this->assertTrue(is_array($metadata_added) && array_key_exists('name', $metadata_added), sprintf('cannot create metadata, response: %s', print_r($metadata_added, true)));
$this->assertEquals('Moeda', $metadata_added['name']);
*/
}
@ -89,7 +90,7 @@ class TAINACAN_REST_Metadata_Controller extends TAINACAN_UnitApiTestCase {
$Tainacan_Item_Metadata->insert($item_metadata);
#################### Get metadata of collection ######################
/*
$request = new \WP_REST_Request(
'GET',
$this->namespace . '/metadata/collection/' . $collection->get_id()
@ -102,7 +103,7 @@ class TAINACAN_REST_Metadata_Controller extends TAINACAN_UnitApiTestCase {
$metadata = $data[0];
$this->assertEquals('Data', $metadata['name']);
*/
################### Get metadata of item with value #######################
$request = new \WP_REST_Request(
@ -113,7 +114,7 @@ class TAINACAN_REST_Metadata_Controller extends TAINACAN_UnitApiTestCase {
$response = $this->server->dispatch($request);
$data = $response->get_data();
$this->assertTrue(is_array($data) && array_key_exists(0, $data), sprintf('cannot read metadata, response: %s', print_r($data, true)));
$item_metadata = $data[0];
$metadata = $item_metadata['metadata'];
@ -182,7 +183,7 @@ class TAINACAN_REST_Metadata_Controller extends TAINACAN_UnitApiTestCase {
#### UPDATE METADATA IN COLLECTION ####
/*
$values = json_encode([
'metadata_id' => $metadata->get_id(),
'values' => [
@ -209,6 +210,7 @@ class TAINACAN_REST_Metadata_Controller extends TAINACAN_UnitApiTestCase {
$metav = get_post_meta($item->get_id(), $data['id'], true);
$this->assertEquals('19/01/2018', $metav);
*/
}
}

View File

@ -65,7 +65,7 @@ class TAINACAN_REST_Taxonomies_Controller extends TAINACAN_UnitApiTestCase {
$response = $this->server->dispatch($request);
$data = $response->get_data();
$this->assertTrue(is_array($data) && array_key_exists('name', $data), sprintf('cannot create a range, response: %s', print_r($data, true)));
$this->assertEquals('Nome', $data['name']);
}

View File

@ -31,8 +31,6 @@ class Collections extends TAINACAN_UnitTestCase {
$user_id = get_current_user_id();
$this->assertEquals($new_user, $user_id);
$this->assertFalse(current_user_can('edit_collection'));
$autor1 = $this->factory()->user->create(array( 'role' => 'author' ));
wp_set_current_user($autor1);
$autor1_id = get_current_user_id();
@ -63,6 +61,18 @@ class Collections extends TAINACAN_UnitTestCase {
$this->assertTrue(current_user_can($collection_test2->cap->edit_post, $collection_test2->WP_Post->ID));
$this->assertFalse(user_can($autor2, $collection_test->cap->edit_post, $collection_test->WP_Post->ID));
// add current user to moderators list of collection test.
// Test add_moderator method and granting permissions
$collection_test->add_moderator_id($current_user_id);
$collection_test->validate();
global $Tainacan_Collections;
$collection_test = $Tainacan_Collections->insert($collection_test);
$this->assertContains($current_user_id, $collection_test->get_moderators_ids());
$this->assertTrue(current_user_can($collection_test->cap->edit_post, $collection_test->WP_Post->ID));
wp_set_current_user($this->user_id);
$collection_test_moderator = $this->tainacan_entity_factory->create_entity(
'collection',
@ -75,7 +85,38 @@ class Collections extends TAINACAN_UnitTestCase {
true
);
$this->assertEquals([$autor2], $collection_test_moderator->get_moderators_ids());
wp_set_current_user($autor2);
$this->assertTrue(current_user_can($collection_test_moderator->cap->edit_post, $collection_test_moderator->WP_Post->ID));
$this->assertTrue($collection_test_moderator->can_edit($autor2), 'Moderators cannot edit a collection!');
// now lets test adding a moderator in a collection that already has one
// and then lets test remove_moderator_id method
// first, subscriber user should not be able to edit the collection
$this->assertFalse(user_can($new_user, $collection_test_moderator->cap->edit_post, $collection_test_moderator->WP_Post->ID));
// lets add him as moderator
$collection_test_moderator->add_moderator_id($new_user);
$collection_test_moderator->validate();
$collection_test_moderator = $Tainacan_Collections->insert($collection_test_moderator);
$this->assertContains($new_user, $collection_test_moderator->get_moderators_ids());
// now he can edit
$this->assertTrue(user_can($new_user, $collection_test_moderator->cap->edit_post, $collection_test_moderator->WP_Post->ID));
// lets remove him and check if he can no longer edit
$collection_test_moderator->remove_moderator_id($new_user);
$collection_test_moderator->validate();
$collection_test_moderator = $Tainacan_Collections->insert($collection_test_moderator);
$this->assertNotContains($new_user, $collection_test_moderator->get_moderators_ids());
// now he can edit
$this->assertFalse(user_can($new_user, $collection_test_moderator->cap->edit_post, $collection_test_moderator->WP_Post->ID));
}
function debug_meta($user = false)

View File

@ -16,10 +16,11 @@ use Tainacan\Entities;
class Items extends TAINACAN_UnitTestCase {
/**
* @group permissions
* @group permissions2
*/
public function test_permissions () {
$collection = $this->tainacan_entity_factory->create_entity(
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'testePerm',
@ -36,6 +37,40 @@ class Items extends TAINACAN_UnitTestCase {
);
$this->assertTrue($item->can_read(), 'Administrator cannot read the Item');
$this->assertTrue($item->can_edit(), 'Administrator cannot edit the Item');
// another administrator should be able to edit items
$new_admin = $this->factory()->user->create(array( 'role' => 'administrator' ));
wp_set_current_user($new_admin);
$this->assertTrue($item->can_read(), 'Administrator cannot read the Item');
$this->assertTrue($item->can_edit(), 'Administrator cannot edit the Item');
$this->assertTrue(current_user_can($collection->get_items_capabilities()->edit_post, $item->get_id()), 'Administrator cannot edit an item!');
$sub = $this->factory()->user->create(array( 'role' => 'subscriber', 'display_name' => 'Sub' ));
$collectionM = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'testePermModerator',
'moderators_ids' => [$sub]
),
true
);
$itemM = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'testeItemModerator',
'collection' => $collectionM,
),
true
);
$this->assertEquals([$sub], $collectionM->get_moderators_ids());
wp_set_current_user($sub);
$this->assertTrue(current_user_can($collectionM->get_items_capabilities()->edit_post, $itemM->get_id()), 'Moderators cannot edit an item!');
$this->assertTrue($itemM->can_edit($sub), 'Moderators cannot edit an item!');
}
function teste_query(){