Items capabilities #274

This commit is contained in:
leogermani 2019-10-30 10:59:38 -03:00
parent fcf60fe307
commit 2ec0bd1642
7 changed files with 485 additions and 399 deletions

View File

@ -180,6 +180,19 @@ class Roles {
'upload_files'
]
],
'tnc_col_%d_delete_items' => [
'display_name' => __('Delete items', 'tainacan'),
'description' => __('Delete items in this collection', 'tainacan'),
],
'tnc_col_%d_delete_others_items' => [
'display_name' => __('Delete others items', 'tainacan'),
'description' => __('Delete items created by other users in this collection', 'tainacan'),
],
'tnc_col_%d_delete_published_items' => [
'display_name' => __('Delete published items', 'tainacan'),
'description' => __('Delete items in this collection after they are published', 'tainacan'),
],
];

View File

@ -166,10 +166,10 @@ class Collection extends Entity {
'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",
'delete_posts' => "tnc_col_{$id}_delete_items",
'delete_private_posts' => "tnc_col_{$id}_delete_items",
'delete_published_posts' => "tnc_col_{$id}_delete_published_items",
'delete_others_posts' => "tnc_col_{$id}_delete_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

@ -100,7 +100,7 @@ class Item extends Entity {
];
$attachments = get_posts( $attachments_query );
return apply_filters("tainacan-item-get-attachments", $attachments, $exclude, $this);
}
@ -123,11 +123,11 @@ class Item extends Entity {
* @return array
*/
function get_thumbnail() {
$sizes = get_intermediate_image_sizes();
array_unshift($sizes, 'full');
foreach ( $sizes as $size ) {
$thumbs[$size] = wp_get_attachment_image_src( $this->get__thumbnail_id(), $size );
}
@ -226,7 +226,7 @@ class Item extends Entity {
function get_description() {
return $this->get_mapped_property( 'description' );
}
/**
* Return the item document type
*
@ -235,7 +235,7 @@ class Item extends Entity {
function get_document_type() {
return $this->get_mapped_property( 'document_type' );
}
/**
* Return the item document
*
@ -263,7 +263,7 @@ class Item extends Entity {
public function get_capabilities() {
return $this->get_collection()->get_items_capabilities();
}
/**
* Checks if comments are allowed for the current Collection.
* @return string "open"|"closed"
@ -315,7 +315,7 @@ class Item extends Entity {
function set_document_type( $value ) {
$this->set_mapped_property( 'document_type', $value );
}
/**
* Define the document
*
@ -326,7 +326,7 @@ class Item extends Entity {
function set_document( $value ) {
$this->set_mapped_property( 'document', $value );
}
/**
* Define the description
*
@ -363,7 +363,7 @@ class Item extends Entity {
$this->cap = $item_collection->get_items_capabilities();
}
}
/**
* Sets if comments are allowed for the current Item.
*
@ -397,7 +397,7 @@ class Item extends Entity {
$arrayItemMetadata = $this->get_metadata();
if ( $arrayItemMetadata ) {
foreach ( $arrayItemMetadata as $itemMetadata ) {
// skip validation for Compound Metadata
if ( $itemMetadata->get_metadatum()->get_metadata_type() == 'Tainacan\Metadata_Types\Compound' ) {
continue;
@ -435,29 +435,29 @@ class Item extends Entity {
return parent::validate();
}
public function _toHtml() {
$return = '';
$id = $this->get_id();
if ( $id ) {
$link = get_permalink( (int) $id );
if (is_string($link)) {
$return = "<a data-linkto='item' data-id='$id' href='$link'>";
$return.= $this->get_title();
$return .= "</a>";
}
}
return $return;
}
/**
@ -470,25 +470,25 @@ class Item extends Entity {
*
* @param array|string $args {
* Optional. Array or string of arguments.
*
*
* @type mixed $metadata Metadatum object, ID or slug to retrieve only one metadatum. empty returns all metadata
*
*
* @type array $metadata__in Array of metadata IDs or Slugs to be retrieved. Default none
*
*
* @type array $metadata__not_in Array of metadata IDs (slugs not accepted) to excluded. Default none
*
*
* @type bool $exclude_title Exclude the Core Title Metadata from result. Default false
*
*
* @type bool $exclude_description Exclude the Core Description Metadata from result. Default false
*
*
* @type bool $exclude_core Exclude Core Metadata (title and description) from result. Default false
*
*
* @type bool $hide_empty Wether to hide or not metadata the item has no value to
* Default: true
* @type string $before String to be added before each metadata block
* Default '<div class="metadata-type-$type">' where $type is the metadata type slug
* @type string $after String to be added after each metadata block
* Default '</div>'
* Default '</div>'
* @type string $before_title String to be added before each metadata title
* Default '<h3>'
* @type string $after_title String to be added after each metadata title
@ -503,12 +503,12 @@ class Item extends Entity {
* @throws \Exception
*/
public function get_metadata_as_html($args = array()) {
$Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
$Tainacan_Metadata = \Tainacan\Repositories\Metadata::get_instance();
$return = '';
$defaults = array(
'metadata' => null,
'metadata__in' => null,
@ -527,9 +527,9 @@ class Item extends Entity {
$args = wp_parse_args($args, $defaults);
if (!is_null($args['metadata'])) {
$metadatum_object = null;
if ( $metadatum instanceof \Tainacan\Entities\Metadatum ) {
$metadatum_object = $metadatum;
} elseif ( is_int($metadatum) ) {
@ -540,10 +540,10 @@ class Item extends Entity {
$metadatum_object = $metadatum[0];
}
}
if ( $metadatum_object instanceof \Tainacan\Entities\Metadatum ) {
if ( is_array($args['metadata__not_in'])
if ( is_array($args['metadata__not_in'])
&& (
in_array($metadatum_object->get_slug(), $args['metadata__not_in']) ||
in_array($metadatum_object->get_id(), $args['metadata__not_in'])
@ -551,23 +551,23 @@ class Item extends Entity {
) {
return $return;
}
$mto = $metadatum_object->get_metadata_type_object();
$before = str_replace('$type', $mto->get_slug(), $args['before']);
$return .= $before;
$item_meta = new \Tainacan\Entities\Item_Metadata_Entity($this, $metadatum_object);
if ($item_meta->has_value() || !$args['hide_empty']) {
$return .= $args['before_title'] . $metadatum_object->get_name() . $args['after_title'];
$return .= $args['before_value'] . $item_meta->get_value_as_html() . $args['after_value'];
}
$return .= $args['after'];
}
return $return;
}
@ -604,13 +604,13 @@ class Item extends Entity {
$query_args['post__name_in'] = $post__name_in;
}
$metadata = $this->get_metadata($query_args);
foreach ( $metadata as $item_meta ) {
$fto = $item_meta->get_metadatum()->get_metadata_type_object();
$before = str_replace('$type', $fto->get_slug(), $args['before']);
$return .= $before;
@ -628,21 +628,21 @@ class Item extends Entity {
$return .= $args['before_title'] . $item_meta->get_metadatum()->get_name() . $args['after_title'];
$return .= $args['before_value'] . $item_meta->get_value_as_html() . $args['after_value'];
}
$return .= $args['after'];
}
return $return;
}
public function get_document_as_html($img_size = 'large') {
$type = $this->get_document_type();
$output = '';
if ( $type == 'url' ) {
global $wp_embed;
$_embed = $wp_embed->autoembed($this->get_document());
@ -653,47 +653,46 @@ class Item extends Entity {
} elseif ( $type == 'text' ) {
$output .= $this->get_document();
} elseif ( $type == 'attachment' ) {
if ( wp_attachment_is_image($this->get_document()) ) {
$img = wp_get_attachment_image($this->get_document(), $img_size);
$img_full = wp_get_attachment_url($this->get_document());
$image_attributes = wp_get_attachment_image_src( $this->get_document(), $img_size );
$img = "<img style='max-width: 100%;' src='" . $image_attributes[0] . "' />";
$output .= sprintf("<a href='%s' target='blank'>%s</a>", $img_full, $img);
} else {
global $wp_embed;
$url = wp_get_attachment_url($this->get_document());
$embed = $wp_embed->autoembed($url);
if ( $embed == $url ) {
$output .= sprintf("<a href='%s' target='blank'>%s</a>", $url, $url);
} else {
$output .= $embed;
}
}
}
return apply_filters("tainacan-item-get-document-as-html", $output, $img_size, $this);
}
/**
* Gets the url to the edit page for this item
* Gets the url to the edit page for this item
*/
public function get_edit_url() {
$collection_id = $this->get_collection_id();
$id = $this->get_id();
return admin_url("?page=tainacan_admin#/collections/$collection_id/items/$id/edit");
}
}
}

View File

@ -13,6 +13,9 @@ class Items extends Repository {
private static $instance = null;
// temporary variable used to filter items query
private $fetching_from_collections = [];
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
@ -23,8 +26,6 @@ class Items extends Repository {
protected function __construct() {
parent::__construct();
add_filter( 'posts_where', array( &$this, 'title_in_posts_where' ), 10, 2 );
add_filter( 'posts_where', array( &$this, 'content_in_posts_where' ), 10, 2 );
add_filter( 'comments_open', [$this, 'hook_comments_open'], 10, 2);
add_action( 'tainacan-api-item-updated', array( &$this, 'hook_api_updated_item' ), 10, 2 );
add_filter( 'map_meta_cap', array( $this, 'map_meta_cap' ), 10, 4 );
@ -172,16 +173,16 @@ class Items extends Repository {
$collection->register_collection_item_post_type();
}
// register taxonomies
// register taxonomies
if ( is_array( $taxonomies ) && sizeof( $taxonomies ) > 0 ) {
foreach ( $taxonomies as $taxonomy ) {
$taxonomy->tainacan_register_taxonomy();
}
}
// register taxonomies to collections considering metadata inheritance
$Tainacan_Taxonomies->register_taxonomies_for_all_collections();
}
public function insert( $item ) {
@ -195,7 +196,7 @@ class Items extends Repository {
* to learn all args accepted in the $args parameter (@see https://developer.wordpress.org/reference/classes/wp_query/)
* You can also use a mapped property, such as name and description, as an argument and it will be mapped to the
* appropriate WP_Query argument
*
*
* If a number is passed to $args, it will return a \Tainacan\Entities\Item object. But if the post is not found or
* does not match the entity post type, it will return an empty array
*
@ -213,7 +214,7 @@ class Items extends Repository {
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
if ( is_numeric( $args ) ) {
$existing_post = get_post( $args );
if ( $existing_post instanceof \WP_Post ) {
try {
@ -227,8 +228,20 @@ class Items extends Repository {
}
$no_collection_set = false;
/**
* We can not user $collections->fetch() here because facets
* filter wp_query to just return the query and not the results
* See Repositories\Metadata::fetch_all_metadatum_values()
*
* Conceptually, it's a good idea that a fetch() method like this only
* produces one WP_Query request
*/
if ( empty( $collections ) ) {
$no_collection_set = true;
$post_types = get_post_types();
$collections = array_map( function($el) use ($Tainacan_Collections) {
if ( $id = $Tainacan_Collections->get_id_by_db_identifier($el) ) {
return $id;
@ -258,15 +271,13 @@ class Items extends Repository {
foreach ( $collections_objects as $collection ) {
/**
* If no specific status is defined in the query, WordPress will fetch
* public items and private items for users withe the correct permission.
*
* If a collection is private, it must have the same behavior, despite its
* items are public or not.
* If no specific collection was queried, we will fetch
* mimick WordPress behavior and return only collections current user can read
*/
if ( ! isset( $args['post_status'] ) ) {
if ( $no_collection_set) {
$status_obj = get_post_status_object( $collection->get_status() );
if ( $status_obj->public || current_user_can( $collection->cap->read_private_posts ) ) {
$cpt[] = $collection->get_db_identifier();
}
} else {
@ -275,21 +286,30 @@ class Items extends Repository {
}
$this->fetching_from_collections = $collections_objects;
if ( empty( $cpt ) ) {
$cpt[] = 'please-return-nothing';
}
//TODO: get collection order and order by options
$args = $this->parse_fetch_args( $args );
$args['post_type'] = $cpt;
$args = apply_filters( 'tainacan_fetch_args', $args, 'items' );
$should_filter = is_user_logged_in() && ! isset($args['post_status']) && sizeof($cpt) > 1;
if ( $should_filter ) {
add_filter('posts_where', [$this, '_filter_where'], 10, 2);
}
$wp_query = new \WP_Query( $args );
if ( $should_filter ) {
remove_filter('posts_where', [$this, '_filter_where']);
}
return $this->fetch_output( $wp_query, $output );
}
@ -315,67 +335,68 @@ class Items extends Repository {
return $this->fetch( $args, $collections )->get_posts();
}
/**
* When querying posts without explictly asking for a post_status, WordPress will
* check current user capabilities and return posts user can read based on read_private_posts capabilities.
*
* However, when querying for multiple post types, WordPress does not handle a per post type permission check. It either
* return only public posts or all private posts if read_private_multiple_post_types cap is present.
*
* This hook fixes this, modifying the where clause.
*
* @param string $where the wehere clause
* @param \WP_Query $wp_query
* @return string The modified where clause
*/
public function _filter_where($where, $wp_query) {
global $wpdb;
$clauses = [];
$user_id = get_current_user_id();
foreach ($this->fetching_from_collections as $collection) {
$read_private_cap = $collection->get_items_capabilities()->read_private_posts;
$clause = '(';
$clause .= "{$wpdb->posts}.post_type = '{$collection->get_db_identifier()}' AND (";
// public status
$public_states = get_post_stati( array( 'public' => true ) );
$status_clause = [];
foreach ( (array) $public_states as $state ) {
$status_clause[] = "{$wpdb->posts}.post_status = '$state'";
}
$clause .= implode(' OR ', $status_clause);
// private statuses
$private_states = get_post_stati( array( 'private' => true ) );
foreach ( (array) $private_states as $state ) {
$clause .= current_user_can( $read_private_cap ) ? " OR {$wpdb->posts}.post_status = '$state'" : " OR {$wpdb->posts}.post_author = $user_id AND {$wpdb->posts}.post_status = '$state'";
}
$clause .= ')';
$clause .= ')';
$clauses[] = $clause;
}
$final = '(' . implode(' OR ', $clauses) . ')';
// find post_type and post_status queries. They always come one right after another
$regexp = '/(' . $wpdb->posts . '\.post_type.+AND \(' . $wpdb->posts . '\.post_status.+\))/';
return \preg_replace($regexp, $final, $where);
}
public function update( $object, $new_values = null ) {
return $this->insert( $object );
}
/**
* allow wp query filter post by array of titles
*
* @param $where
* @param $wp_query
*
* @return string
*/
public function title_in_posts_where( $where, $wp_query ) {
global $wpdb;
if ( $post_title_in = $wp_query->get( 'post_title_in' ) ) {
if ( is_array( $post_title_in ) && isset( $post_title_in['value'] ) ) {
$quotes = [];
foreach ( $post_title_in['value'] as $title ) {
$quotes[] = " $wpdb->posts.post_title LIKE '%" . esc_sql( $wpdb->esc_like( $title ) ) . "%'";
}
}
// retrieve only posts for the specified collection and status
$type = " $wpdb->posts.post_type = '" . $wp_query->get( 'post_type' )[0] . "' ";
$status = " ( $wpdb->posts.post_status = 'publish' OR $wpdb->posts.post_status = 'private') ";
$where .= ' ' . $post_title_in['relation'] . '( ( ' . implode( ' OR ', $quotes ) . ' ) AND ' .
$status . ' AND ' . $type . ' )';
}
return $where;
}
/**
* allow wp query filter post by array of content
*
* @param $where
* @param $wp_query
*
* @return string
*/
public function content_in_posts_where( $where, $wp_query ) {
global $wpdb;
if ( $post_content_in = $wp_query->get( 'post_content_in' ) ) {
if ( is_array( $post_content_in ) && isset( $post_content_in['value'] ) ) {
$quotes = [];
foreach ( $post_content_in['value'] as $title ) {
$quotes[] = " $wpdb->posts.post_content LIKE '%" . esc_sql( $wpdb->esc_like( $title ) ) . "%'";
}
}
// retrieve only posts for the specified collection and status
$type = " $wpdb->posts.post_type = '" . $wp_query->get( 'post_type' )[0] . "' ";
$status = " ( $wpdb->posts.post_status = 'publish' OR $wpdb->posts.post_status = 'private') ";
$where .= ' ' . $post_content_in['relation'] . '( ( ' . implode( ' OR ', $quotes ) . ' ) AND ' .
$status . ' AND ' . $type . ' )';
}
return $where;
}
/**
* generate a content of document to index.
*
@ -480,23 +501,23 @@ class Items extends Repository {
}
/**
* Return if comment are open for this item (post_id) and the collection too
*
* Return if comment are open for this item (post_id) and the collection too
*
* @param bool $open_comment
* @param integer $post_id Item id
* @return bool
*/
public function hook_comments_open($open_comment, $post_id) {
$item = self::get_entity_by_post($post_id);
if($item != false && $item instanceof Entities\Item) {
$collection = $item->get_collection();
if( $collection->get_allow_comments() !== 'open' ) return false;
}
return $open_comment;
}
/**
* Filter to handle special permissions
*
@ -506,9 +527,9 @@ class Items extends Repository {
public function map_meta_cap( $caps, $cap, $user_id, $args ) {
// Even if the item is public, user must have read_private_posts if the collection is private
if ( $cap == 'read_post' && is_array( $args ) && array_key_exists( 0, $args ) ) {
//return $caps;
if ( $cap == 'read_post' && is_array( $args ) && array_key_exists( 0, $args ) ) {
$entity = $args[0];
if ( is_numeric( $entity ) || $entity instanceof Entities\Item ) {
@ -518,24 +539,24 @@ class Items extends Repository {
}
if ( $entity instanceof Entities\Item ) {
$collection = $entity->get_collection();
if ( $collection instanceof Entities\Collection ) {
$status_obj = get_post_status_object( $collection->get_status() );
if ( ! $status_obj->public ) {
$caps[] = $entity->get_capabilities()->read_private_posts;
$caps[] = $collection->get_capabilities()->read_private_posts;
}
}
}
}
}
return $caps;
}
/**
* Check if $user can read the item based on the colletion
*
@ -545,38 +566,38 @@ class Items extends Repository {
* @return boolean
* @throws \Exception
*/
public function can_read( Entities\Entity $entity, $user = null ) {
if ( ! $entity instanceof Entities\Item) {
throw new InvalidArgumentException('Items::can_read() expects an Item entity as the first parameter');
}
// can read the item looking only to the item
$can_read = parent::can_read($entity, $user);
if ( $can_read ) {
$collection = $entity->get_collection();
$status_obj = get_post_status_object( $collection->get_status() );
if ( $status_obj->public ) {
return $can_read;
}
}
if ( is_null($user) ) {
$user = get_current_user_id();
}
if ( ! $user ) {
return false;
} elseif ( is_object( $user ) ) {
$user = $user->ID;
}
$entity_cap = $entity->get_capabilities();
return user_can( $user, $entity_cap->read_private_posts, $entity->get_id() );
}
// public function can_read( Entities\Entity $entity, $user = null ) {
// if ( ! $entity instanceof Entities\Item) {
// throw new InvalidArgumentException('Items::can_read() expects an Item entity as the first parameter');
// }
// // can read the item looking only to the item
// $can_read = parent::can_read($entity, $user);
// if ( $can_read ) {
// $collection = $entity->get_collection();
// $status_obj = get_post_status_object( $collection->get_status() );
// if ( $status_obj->public ) {
// return $can_read;
// }
// }
// if ( is_null($user) ) {
// $user = get_current_user_id();
// }
// if ( ! $user ) {
// return false;
// } elseif ( is_object( $user ) ) {
// $user = $user->ID;
// }
// $entity_cap = $entity->get_capabilities();
// return user_can( $user, $entity_cap->read_private_posts, $entity->get_id() );
// }
}

View File

@ -28,7 +28,7 @@ abstract class Repository {
* @var Repositories\Logs
*/
protected $logs_repository;
private $map = [];
/**
@ -52,7 +52,7 @@ abstract class Repository {
protected function __construct() {
add_action( 'init', array( &$this, 'register_post_type' ) );
add_action( 'init', array( &$this, 'init_objects' ) );
add_filter( 'tainacan-get-map-' . $this->get_name(), array( $this, 'get_default_properties' ) );
}
@ -128,7 +128,7 @@ abstract class Repository {
$old = '';
$diffs = [];
do_action( 'tainacan-pre-insert', $obj );
do_action( 'tainacan-pre-insert-' . $obj->get_post_type(), $obj );
@ -273,7 +273,7 @@ abstract class Repository {
*
* @see https://core.trac.wordpress.org/ticket/18408
*/
foreach ( $WP_Query->get_posts() as $p ) {
foreach ( $WP_Query->posts as $p ) {
$result[] = new $this->entities_type( $p->ID );
}
}
@ -588,10 +588,10 @@ abstract class Repository {
return false;
}
/**
* Shortcut to delete($entity, false)
*
*
* @param Entities\Entity $entity
*
* @return mixed|Entity @see https://developer.wordpress.org/reference/functions/wp_delete_post/
@ -607,24 +607,24 @@ abstract class Repository {
* @return mixed|Entity @see https://developer.wordpress.org/reference/functions/wp_delete_post/
*/
public function delete( Entities\Entity $entity, $permanent = true ) {
do_action( 'tainacan-pre-delete', $entity, $permanent );
do_action( 'tainacan-pre-delete-' . $entity->get_post_type(), $entity, $permanent );
if ($permanent === true) {
$return = wp_delete_post( $entity->get_id(), $permanent );
} elseif ($permanent === false) {
$return = wp_trash_post( $entity->get_id() );
}
if ( $return instanceof \WP_Post && $this->use_logs ) {
do_action( 'tainacan-deleted', $entity, $permanent );
do_action( 'tainacan-deleted-' . $entity->get_post_type(), $entity, $permanent );
$return = $this->get_entity_by_post($return);
}
return $return;
@ -701,7 +701,7 @@ abstract class Repository {
$user = $user->ID;
}
$entity_cap = $entity->get_capabilities();
if ( ! isset( $entity_cap->read ) ) {
if ( $entity->get_post_type() === false ) { // Allow read of not post entities
return true;
@ -737,6 +737,31 @@ abstract class Repository {
return user_can( $user, $entity_cap->delete_post, $entity->get_id() );
}
/**
* Check if $user can publish 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_publish(Entities\Entity $entity, $user = null) {
if ( is_null( $user ) ) {
$user = get_current_user_id();
} elseif ( is_object( $user ) ) {
$user = $user->ID;
}
$entity_cap = $entity->get_capabilities();
if ( ! $user || ! isset( $entity_cap->publish_posts ) ) {
return false;
}
return user_can( $user, $entity_cap->publish_posts );
}
/**
* Removes duplicates from multidimensional array
*
@ -817,7 +842,7 @@ abstract class Repository {
return $diffs;
}
/**
* Get IDs for all children, grand children till the depth parameter is reached
* @param int|\Tainacan\Entities\Entity $id The Entity ID or object
@ -829,17 +854,17 @@ abstract class Repository {
if (is_integer($id)) {
$object = $this->fetch($id);
}
if ( ! $object instanceof \Tainacan\Entities\Entity) {
return [];
}
global $wpdb;
$go_deeper = false === $depth || (is_integer($depth) && $depth > 1);
$new_depth = is_integer($depth) ? $depth - 1 : $depth;
$children = $wpdb->get_col( $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s", $object->get_id(), $object->get_post_type() ) );
if ($go_deeper && sizeof($children) > 0) {
$gchildren = [];
foreach ($children as $child) {
@ -849,13 +874,13 @@ abstract class Repository {
}
}
$children = array_merge($children, $gchildren);
}
return $children;
}
/**
* Get the capabilities list for the post type of the entity
*
@ -867,12 +892,12 @@ abstract class Repository {
* @return object Object with all the capabilities as member variables.
*/
public function get_capabilities() {
$entity = new $this->entities_type();
return $entity->get_capabilities();
}
}
?>

View File

@ -28,13 +28,13 @@ class Capabilities extends TAINACAN_UnitTestCase {
* - private_repo_metadatum
* - public_repo_filter
* - private_repo_filter
* - public_collection (5 items)
* - public_collection (10 items, 5 public, 5 private)
* --- (Core Title adn Description)
* --- public_metadatum
* --- private_metadatum
* --- public_filter
* --- private_filter
* - private_collection (5 items)
* - private_collection (10 items, 5 public, 5 private)
* --- (Core Title adn Description)
* --- meta_relationshipt (with public collection)
*/
@ -239,6 +239,7 @@ class Capabilities extends TAINACAN_UnitTestCase {
);
$this->private_repo_filter = $filter;
$this->items = [];
for ($i = 1; $i<=10; $i++) {
@ -246,6 +247,7 @@ class Capabilities extends TAINACAN_UnitTestCase {
$title = 'testeItem ' . str_pad($i, 2, "0", STR_PAD_LEFT);
$col = $i <= 5 ? $collection1 : $collection2;
$col_slug = $i <= 5 ? 'public_col' : 'private_col';
$item = $this->tainacan_entity_factory->create_entity(
'item',
@ -257,6 +259,8 @@ class Capabilities extends TAINACAN_UnitTestCase {
true
);
$this->items[$col_slug]['public'][] = $item;
$this->tainacan_item_metadata_factory->create_item_metadata($item, $metadatum_repo, 'Value ' . $i);
$this->tainacan_item_metadata_factory->create_item_metadata($item, $metadatum_repo2, 'Value ' . $i);
@ -265,6 +269,17 @@ class Capabilities extends TAINACAN_UnitTestCase {
$this->tainacan_item_metadata_factory->create_item_metadata($item, $metadatum_text2, $i % 2 == 0 ? 'even' : 'odd');
}
$private_item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'private' . $title,
'collection' => $col,
'status' => 'private'
),
true
);
$this->items[$col_slug]['private'][] = $private_item;
}
$subscriber = $this->factory()->user->create(array( 'role' => 'subscriber' ));
@ -315,22 +330,6 @@ class Capabilities extends TAINACAN_UnitTestCase {
}
// 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();
//
// }
/**
* @group metadata
*/
@ -737,4 +736,196 @@ class Capabilities extends TAINACAN_UnitTestCase {
}
/**
* @group items
*/
function test_items_metacaps() {
global $current_user;
wp_set_current_user($this->subscriber2->ID);
$col1prefix = 'tnc_col_' . $this->public_collection->get_id() . '_';
$col2prefix = 'tnc_col_' . $this->private_collection->get_id() . '_';
$public = $this->items['public_col']['public'][0];
$public_in_private = $this->items['private_col']['public'][0];
$private = $this->items['public_col']['private'][0];
$private_in_private = $this->items['private_col']['private'][0];
$this->assertTrue( $public->can_read() );
$this->assertFalse( $public_in_private->can_read() );
$this->assertFalse( $private->can_read() );
$this->assertFalse( $private_in_private->can_read() );
$this->subscriber2->add_cap( $col1prefix . 'read_private_items' );
$this->assertTrue( $public->can_read() );
$this->assertFalse( $public_in_private->can_read() );
$this->assertTrue( $private->can_read() );
$this->assertFalse( $private_in_private->can_read() );
$this->subscriber2->add_cap( $col2prefix . 'read_private_items' );
$this->assertTrue( $public->can_read() );
$this->assertFalse( $public_in_private->can_read() );
$this->assertTrue( $private->can_read() );
$this->assertFalse( $private_in_private->can_read(), 'user must also have read_private_collections to read items in private collections' );
$this->subscriber2->add_cap( 'tnc_rep_read_private_collections' );
$this->assertTrue( $public->can_read() );
$this->assertTrue( $public_in_private->can_read() );
$this->assertTrue( $private->can_read() );
$this->assertTrue( $private_in_private->can_read() );
$own_item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'my item',
'collection' => $this->public_collection,
'status' => 'draft'
),
true
);
$this->assertFalse( $own_item->can_edit() );
$this->subscriber2->add_cap( $col1prefix . 'edit_items' );
$this->assertTrue( $own_item->can_edit() );
$this->assertFalse( $own_item->can_publish() );
$this->subscriber2->add_cap( $col1prefix . 'publish_items' );
$this->assertTrue( $own_item->can_publish() );
$this->assertFalse( $own_item->can_delete() );
$this->subscriber2->add_cap( $col1prefix . 'delete_items' );
$this->assertTrue( $own_item->can_delete() );
$own_item->set_status('publish');
$own_item->validate();
$own_item = \tainacan_items()->insert($own_item);
$this->assertFalse( $own_item->can_edit() );
$this->subscriber2->add_cap( $col1prefix . 'edit_published_items' );
$this->assertTrue( $own_item->can_edit() );
$this->assertFalse( $own_item->can_delete() );
$this->subscriber2->add_cap( $col1prefix . 'delete_published_items' );
$this->assertTrue( $own_item->can_delete() );
}
/**
* @group items
*/
function test_items_edit_others() {
global $current_user;
wp_set_current_user($this->subscriber2->ID);
$col1prefix = 'tnc_col_' . $this->public_collection->get_id() . '_';
$other_draft = $this->items['public_col']['public'][0];
$other_draft->set_status('draft');
$other_draft->validate();
$other_draft = \tainacan_items()->insert($other_draft);
$other_published = $this->items['public_col']['public'][1];
$this->assertFalse( $other_draft->can_edit() );
$this->assertFalse( $other_published->can_edit() );
$this->subscriber2->add_cap( $col1prefix . 'edit_others_items' );
$this->assertTrue( $other_draft->can_edit() );
$this->assertFalse( $other_published->can_edit() );
$this->subscriber2->add_cap( $col1prefix . 'edit_published_items' );
$this->assertTrue( $other_draft->can_edit() );
$this->assertTrue( $other_published->can_edit() );
}
/**
* @group items
*/
function test_fetch_items() {
global $current_user;
wp_set_current_user($this->subscriber2->ID);
$col1prefix = 'tnc_col_' . $this->public_collection->get_id() . '_';
$col2prefix = 'tnc_col_' . $this->private_collection->get_id() . '_';
$repo = tainacan_items()->fetch(['nopaging' => true], [], 'OBJECT');
$this->assertEquals(5, sizeof($repo));
$this->subscriber2->add_cap( $col1prefix . 'read_private_items' );
$current_user = $this->subscriber2; // force update current user object with new capabilities
$repo = tainacan_items()->fetch(['nopaging' => true], [], 'OBJECT');
$this->assertEquals(10, sizeof($repo));
$this->subscriber2->add_cap( 'tnc_rep_read_private_collections' );
//$this->subscriber2->add_cap( 'read_private_multiple_post_types' );
$current_user = $this->subscriber2; // force update current user object with new capabilities
$repo = tainacan_items()->fetch(['nopaging' => true], [], 'OBJECT');
$this->assertEquals(15, sizeof($repo));
$this->subscriber2->add_cap( $col2prefix . 'read_private_items' );
$current_user = $this->subscriber2; // force update current user object with new capabilities
$repo = tainacan_items()->fetch(['nopaging' => true], [], 'OBJECT');
$this->assertEquals(20, sizeof($repo));
$col1 = tainacan_items()->fetch(['nopaging' => true], $this->public_collection, 'OBJECT');
}
/**
* @group items
*/
function test_fetch_collection_items() {
global $current_user;
wp_set_current_user($this->subscriber2->ID);
$col1prefix = 'tnc_col_' . $this->public_collection->get_id() . '_';
$col2prefix = 'tnc_col_' . $this->private_collection->get_id() . '_';
$col1 = tainacan_items()->fetch(['nopaging' => true], $this->public_collection, 'OBJECT');
$this->assertEquals(5, sizeof($col1));
$this->subscriber2->add_cap( $col1prefix . 'read_private_items' );
$current_user = $this->subscriber2; // force update current user object with new capabilities
$col1 = tainacan_items()->fetch(['nopaging' => true], $this->public_collection, 'OBJECT');
$this->assertEquals(10, sizeof($col1));
}
}

View File

@ -1,163 +0,0 @@
<?php
namespace Tainacan\Tests;
/**
* Class TestCollections
*
* @package Test_Tainacan
*/
use Tainacan\Entities;
/**
* Test fetch methods to see if they return private objects (items, fiels, collections) correctly
*
* Private items should only be visible by logged users who have the rights
*
*/
/**
* @group privateObjects
*/
class PrivateObjects extends TAINACAN_UnitTestCase {
// TODO Test the same things via API
public function test_private_items () {
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'testePerm',
'status' => 'publish'
),
true
);
$privateItem = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'testPrivateItem',
'collection' => $collection,
'status' => 'private'
),
true
);
$item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'testItem',
'collection' => $collection,
'status' => 'publish'
),
true
);
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$items = $Tainacan_Items->fetch([], $collection);
$this->assertEquals(2, $items->found_posts, 'admins should see all 2 items');
$items = $Tainacan_Items->fetch(['post_status' => 'private', 'perm' => 'readable'], $collection);
$this->assertEquals(1, $items->found_posts, 'contributors should not see private items');
$new_contributor_user = $this->factory()->user->create(array( 'role' => 'contributor' ));
wp_set_current_user($new_contributor_user);
$items = $Tainacan_Items->fetch([], $collection);
$this->assertEquals(1, $items->found_posts, 'contributors should not see private items');
$items = $Tainacan_Items->fetch(['post_status' => 'private', 'perm' => 'readable'], $collection);
$this->assertEquals(0, $items->found_posts, 'contributors should not see private items');
$items = $Tainacan_Items->fetch(['post_status' => 'private'], $collection);
$this->assertEquals(1, $items->found_posts, 'contributors should not see private items');
}
public function test_items_in_private_collections () {
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'testePerm',
'status' => 'publish'
),
true
);
$privateCollection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'testePerm',
'status' => 'private'
),
true
);
$item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'testItem',
'collection' => $collection,
'status' => 'publish'
),
true
);
$item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'testItem',
'collection' => $collection,
'status' => 'publish'
),
true
);
$item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'testItem',
'collection' => $privateCollection,
'status' => 'publish'
),
true
);
$item = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'testItem',
'collection' => $privateCollection,
'status' => 'publish'
),
true
);
$new_contributor_user = $this->factory()->user->create(array( 'role' => 'contributor' ));
wp_set_current_user($new_contributor_user);
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$Tainacan_Collections = \Tainacan\Repositories\Collections::get_instance();
$items = $Tainacan_Items->fetch([], $collection);
$this->assertEquals(2, $items->found_posts, 'items of a public collections should be visible');
$items = $Tainacan_Items->fetch([], $privateCollection);
$this->assertEquals(0, $items->found_posts, 'items of a private collection should not be visible');
$privateCollection->set_status('publish');
$privateCollection->validate();
$privateCollection = $Tainacan_Collections->insert($privateCollection);
$items = $Tainacan_Items->fetch([], $privateCollection);
$this->assertEquals(2, $items->found_posts, 'items should be visible after collections is made public');
$privateCollection->set_status('private');
$privateCollection->validate();
$privateCollection = $Tainacan_Collections->insert($privateCollection);
$items = $Tainacan_Items->fetch([], $privateCollection);
$this->assertEquals(0, $items->found_posts, 'items should not be visible after collection is made private');
}
}