diff --git a/includes/datastream.inc b/includes/datastream.inc index 23eb44f9..dc01bdfe 100644 --- a/includes/datastream.inc +++ b/includes/datastream.inc @@ -84,9 +84,12 @@ function islandora_datastream_get_url(AbstractDatastream $datastream, $type = 'd * The datastream to generated the url to. */ function islandora_datastream_get_delete_link(AbstractDatastream $datastream) { - $datastreams = module_invoke_all('islandora_undeletable_datastreams', $datastream->parent->models); - $can_delete = !in_array($datastream->id, $datastreams); - return $can_delete ? l(t('delete'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete") : ''; + $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_delete_link" theme implementation.'); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + + return theme('islandora_datastream_delete_link', array( + 'datastream' => $datastream, + )); } /** @@ -96,9 +99,12 @@ function islandora_datastream_get_delete_link(AbstractDatastream $datastream) { * The datastream to generated the url to. */ function islandora_datastream_edit_get_link(AbstractDatastream $datastream) { - $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream); - $can_edit = count($edit_registry) > 0 && user_access(FEDORA_METADATA_EDIT); - return $can_edit ? l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") : ''; + $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_edit_link" theme implementation.'); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + + return theme('islandora_datastream_edit_link', array( + 'datastream' => $datastream, + )); } /** @@ -144,3 +150,41 @@ function islandora_edit_datastream_registry_render(array $edit_registry) { '#markup' => $markup, ); } + +/** + * Get markup for a download link. + * + * @param AbstractDatastream $datastream + * The datastream for which to generate a link. + * + * @return string + * Either the link markup if the user has access or an empty string if the + * user is not allowed to see the given datastream. + */ +function islandora_datastream_get_download_link(AbstractDatastream $datastream) { + $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_download_link" theme implementation.'); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + + return theme('islandora_datastream_download_link', array( + 'datastream' => $datastream, + )); +} + +/** + * Get markup for a view link. + * + * @param AbstractDatastream $datastream + * The datastream for which to generate a link. + * + * @return string + * Either the link markup if the user has access or a string containing the + * datastream ID if the user is not allowed to see the given datastream. + */ +function islandora_datastream_get_view_link(AbstractDatastream $datastream) { + $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_view_link" theme implementation.'); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + + return theme('islandora_datastream_view_link', array( + 'datastream' => $datastream, + )); +} diff --git a/includes/object_properties.form.inc b/includes/object_properties.form.inc index 543fa6dd..44d016b7 100644 --- a/includes/object_properties.form.inc +++ b/includes/object_properties.form.inc @@ -60,6 +60,7 @@ function islandora_object_properties_form(array $form, array &$form_state, Abstr ), 'delete' => array( '#type' => 'submit', + '#access' => islandora_object_access(FEDORA_PURGE, $object), '#value' => t('Delete'), '#submit' => array('islandora_object_properties_form_delete'), '#limit_validation_errors' => array(array('pid')), diff --git a/includes/utilities.inc b/includes/utilities.inc index 32b05158..66c03d26 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -389,7 +389,7 @@ function islandora_get_datastreams_requirements_from_models(array $models) { * - "optional": A boolean indicating if the given stream is optional. */ function islandora_get_datastreams_requirements_from_content_model(AbstractObject $object) { - if (empty($object[DS_COMP_STREAM])) { + if (empty($object[DS_COMP_STREAM]) || !islandora_datastream_access(FEDORA_VIEW_OBJECTS, $object[DS_COMP_STREAM])) { return array(); } $xml = new SimpleXMLElement($object[DS_COMP_STREAM]->content); @@ -673,6 +673,9 @@ function islandora_get_comp_ds_mappings($pid) { * TRUE if the account has all the given permissions, FALSE otherwise. */ function islandora_user_access_all(array $perms, $account = NULL) { + $message = islandora_deprecated('7.x-1.2', 'Roll your own code or use islandora_user_access().'); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + foreach ($perms as $perm) { if (!user_access($perm, $account)) { return FALSE; @@ -694,6 +697,9 @@ function islandora_user_access_all(array $perms, $account = NULL) { * otherwise. */ function islandora_user_access_any(array $perms, $account = NULL) { + $message = islandora_deprecated('7.x-1.2', 'Roll your own code or use islandora_user_access().'); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + foreach ($perms as $perm) { if (user_access($perm, $account)) { return TRUE; diff --git a/islandora.api.php b/islandora.api.php index 89e1e048..129787f4 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -443,3 +443,79 @@ function hook_islandora_ingest_steps(array $form_state) { */ function hook_CMODEL_PID_islandora_ingest_steps(array $form_state) { } + +/** + * Object-level access callback hook. + * + * @param string $op + * A string define an operation to check. Should be defined via + * hook_permission(). + * @param AbstractObject $object + * An object to check the operation on. + * @param object $user + * A loaded user object, as the global $user variable might contain. + * + * @return bool|NULL + * Either boolean TRUE or FALSE to explicitly allow or deny the operation on + * the given object, or NULL to indicate that we are making no assertion + * about the outcome. + */ +function hook_islandora_object_access($op, $object, $user) { + switch ($op) { + case 'create stuff': + return TRUE; + + case 'break stuff': + return FALSE; + + case 'do a barrel roll!': + return NULL; + + } +} + +/** + * Content model specific version of hook_islandora_object_access(). + * + * @see hook_islandora_object_access() + */ +function hook_CMODEL_PID_islandora_object_access($op, $object, $user) { +} + +/** + * Datastream-level access callback hook. + * + * @param string $op + * A string define an operation to check. Should be defined via + * hook_permission(). + * @param AbstractDatastream $object + * An object to check the operation on. + * @param object $user + * A loaded user object, as the global $user variable might contain. + * + * @return bool|NULL + * Either boolean TRUE or FALSE to explicitly allow or deny the operation on + * the given object, or NULL to indicate that we are making no assertion + * about the outcome. + */ +function hook_islandora_datastream_access($op, $object, $user) { + switch ($op) { + case 'create stuff': + return TRUE; + + case 'break stuff': + return FALSE; + + case 'do a barrel roll!': + return NULL; + + } +} + +/** + * Content model specific version of hook_islandora_datastream_access(). + * + * @see hook_islandora_datastream_access() + */ +function hook_CMODEL_PID_islandora_datastream_access($op, $object, $user) { +} diff --git a/islandora.info b/islandora.info index 4f6a5858..ce6ba947 100644 --- a/islandora.info +++ b/islandora.info @@ -15,5 +15,6 @@ files[] = tests/islandora_web_test_case.inc files[] = tests/authtokens.test files[] = tests/hooks.test files[] = tests/ingest.test +files[] = tests/hooked_access.test files[] = tests/islandora_manage_permissions.test php = 5.3 diff --git a/islandora.module b/islandora.module index 32410596..7e1936c3 100644 --- a/islandora.module +++ b/islandora.module @@ -190,8 +190,8 @@ function islandora_menu() { 'page arguments' => array(4, FALSE), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', - 'access callback' => 'islandora_object_datastream_access_callback', - 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4), + 'access callback' => 'islandora_datastream_access', + 'access arguments' => array(FEDORA_VIEW_OBJECTS, 4), 'load arguments' => array(2), ); // This menu item uses token authentication in islandora_tokened_object. @@ -208,8 +208,8 @@ function islandora_menu() { 'page arguments' => array(4), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', - 'access callback' => 'islandora_object_datastream_access_callback', - 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4), + 'access callback' => 'islandora_datastream_access', + 'access arguments' => array(FEDORA_VIEW_OBJECTS, 4), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array( @@ -218,8 +218,8 @@ function islandora_menu() { 'page arguments' => array(4), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', - 'access callback' => 'islandora_object_datastream_access_callback', - 'access arguments' => array(FEDORA_METADATA_EDIT, 2, 4), + 'access callback' => 'islandora_datastream_access', + 'access arguments' => array(FEDORA_METADATA_EDIT, 4), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream/delete'] = array( @@ -228,8 +228,8 @@ function islandora_menu() { 'page arguments' => array('islandora_delete_datastream_form', 4), 'file' => 'includes/delete_datastream.form.inc', 'type' => MENU_CALLBACK, - 'access callback' => 'islandora_object_datastream_access_callback', - 'access arguments' => array(FEDORA_PURGE, 2, 4), + 'access callback' => 'islandora_datastream_access', + 'access arguments' => array(FEDORA_PURGE, 4), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/print'] = array( @@ -237,7 +237,7 @@ function islandora_menu() { 'page callback' => 'islandora_print_object', 'page arguments' => array(2), 'type' => MENU_CALLBACK, - 'access callback' => 'islandora_object_access_callback', + 'access callback' => 'islandora_object_access', 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'load arguments' => array(2), ); @@ -245,7 +245,7 @@ function islandora_menu() { 'page callback' => 'islandora_download_clip', 'page arguments' => array(2), 'type' => MENU_CALLBACK, - 'access callback' => 'islandora_object_access_callback', + 'access callback' => 'islandora_object_access', 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'load arguments' => array(2), ); @@ -322,6 +322,22 @@ function islandora_theme() { 'template' => 'theme/islandora-objects-list', 'variables' => array('objects' => NULL), ), + 'islandora_datastream_edit_link' => array( + 'file' => 'theme/theme.inc', + 'variables' => array('datastream' => NULL), + ), + 'islandora_datastream_delete_link' => array( + 'file' => 'theme/theme.inc', + 'variables' => array('datastream' => NULL), + ), + 'islandora_datastream_view_link' => array( + 'file' => 'theme/theme.inc', + 'variables' => array('datastream' => NULL), + ), + 'islandora_datastream_download_link' => array( + 'file' => 'theme/theme.inc', + 'variables' => array('datastream' => NULL), + ), ); } @@ -381,7 +397,7 @@ function islandora_forms($form_id) { * * @global $user * - * @param mixed $object + * @param mixed $object_or_datastream * The AbstractObject or AbstractDatastream to test for accessibility, if NULL * is given the object is assumed to not exist or be inaccessible. * @param array $permissions @@ -392,7 +408,7 @@ function islandora_forms($form_id) { * (optional) TRUE to grant access if any single requirement is met from both * the permissions and content models parameters. FALSE if all requirements * must be met from both the permissions and content model parameters. - * @param object $account + * @param object $user * (optional) The account to check, if not given check the GET parameters for * a token to restore the user. If no GET parameter is present use currently * logged in user. @@ -401,9 +417,10 @@ function islandora_forms($form_id) { * TRUE if the user is allowed to access this object/datastream, FALSE * otherwise. */ -function islandora_user_access($object, array $permissions, $content_models = array(), $access_any = TRUE, $account = NULL) { +function islandora_user_access($object_or_datastream, array $permissions, $content_models = array(), $access_any = TRUE, $user = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); $is_repository_accessible = &drupal_static(__FUNCTION__); + // If the repository is inaccessible then access always fails. if (!isset($is_repository_accessible)) { $is_repository_accessible = islandora_describe_repository(); @@ -413,43 +430,74 @@ function islandora_user_access($object, array $permissions, $content_models = ar return FALSE; } } - if (!$is_repository_accessible || !is_object($object)) { + if (!$is_repository_accessible || !is_object($object_or_datastream) || empty($permissions)) { return FALSE; } + + // Determine what has been passed as $object. + if (is_subclass_of($object_or_datastream, 'AbstractObject')) { + $object = $object_or_datastream; + $datastream = NULL; + } + elseif (is_subclass_of($object_or_datastream, 'AbstractDatastream')) { + $datastream = $object_or_datastream; + $object = $datastream->parent; + } + // Determine the user account to test against. - if (!isset($account)) { + if (!isset($user)) { $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING); if ($token) { module_load_include('inc', 'islandora', 'includes/authtokens'); - $user = islandora_validate_object_token($object->id, $datastream->id, $token); + $token_user = islandora_validate_object_token($object->id, $datastream->id, $token); if ($user) { - $account = user_load($user->uid); + $user = user_load($token_user->uid); } } else { global $user; - $account = $user; } } - // Determine what has been passed as $object. - if (is_subclass_of($object, 'FedoraObject')) { - $object = $object; - } - elseif (is_subclass_of($object, 'FedoraDatastream')) { - $datastream = $object; - $object = $datastream->parent; - } + // Check for access. - $accessible_namespace = islandora_namespace_accessible($object->id); if ($access_any) { - $has_required_permissions = islandora_user_access_any($permissions, $account); $has_required_content_models = empty($content_models) ? TRUE : count(array_intersect($object->models, $content_models)) > 0; + if ($has_required_content_models) { + foreach ($permissions as $p) { + if ($datastream !== NULL) { + $check = islandora_datastream_access($p, $datastream, $user); + } + else { + $check = islandora_object_access($p, $object, $user); + } + + if ($check) { + return TRUE; + } + } + return FALSE; + } } else { - $has_required_permissions = islandora_user_access_all($permissions, $account); $has_required_content_models = count(array_diff($content_models, $object->models)) == 0; + if ($has_required_content_models) { + foreach ($permissions as $p) { + if ($datastream !== NULL) { + $check = islandora_datastream_access($p, $datastream, $user); + } + else { + $check = islandora_object_access($p, $object, $user); + } + + if (!$check) { + return FALSE; + } + } + // Should already have failed if there are no $permissions. + return TRUE; + } } - return $accessible_namespace && $has_required_permissions && $has_required_content_models; + return FALSE; } /** @@ -475,7 +523,7 @@ function islandora_object_access_callback($perm, $object = NULL) { return FALSE; } - return user_access($perm) && is_object($object) && islandora_namespace_accessible($object->id); + return islandora_object_access($perm, $object); } /** @@ -500,7 +548,10 @@ function islandora_object_access_callback($perm, $object = NULL) { */ function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL, $account = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); - return user_access($perm, $account) && is_object($object) && islandora_namespace_accessible($object->id) && is_object($datastream); + $message = islandora_deprecated('7.x-1.2', 'Use islandora_datastream_access().'); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + + return islandora_datastream_access($perm, $datastream, $account); } /** @@ -508,10 +559,8 @@ function islandora_object_datastream_access_callback($perm, $object = NULL, $dat * * This function will validate and use a token if present in the GET parameters. * - * Checks for object existance, accessiblitly, namespace permissions, + * Checks for object existance, accessibility, namespace permissions, * and user permissions - * - * @see islandora_object_datastream_tokened_access_callback() */ function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); @@ -526,7 +575,7 @@ function islandora_object_datastream_tokened_access_callback($perm, $object = NU } } - return islandora_object_datastream_access_callback($perm, $object, $datastream, $token_account); + return islandora_datastream_access($perm, $datastream, $token_account); } /** @@ -554,10 +603,10 @@ function islandora_object_manage_access_callback($perms, $object = NULL) { $has_access = FALSE; for ($i = 0; $i < count($perms) && !$has_access; $i++) { - $has_access = $has_access || user_access($perms[$i]); + $has_access = $has_access || islandora_object_access($perms[$i], $object); } - return $has_access && is_object($object) && islandora_namespace_accessible($object->id); + return $has_access; } /** @@ -1170,3 +1219,103 @@ function islandora_file_mimetype_mapping_alter(&$mapping) { $mapping['extensions'][$ext] = key($mapping['mimetypes']); } } + +/** + * Hookable object access callback. + * + * @param string $op + * String identifying an operation to check. Should correspond to a + * permission declared via hook_permission(). + * @param AbstractObject $object + * An object to check for permissions. + * @param object $user + * An optional loaded user object. Defaults to the global $user. + * + * @return bool + * TRUE if at least one implementation of hook_islandora_object_access() + * returned TRUE, and no implementation return FALSE; FALSE otherwise. + */ +function islandora_object_access($op, $object, $user = NULL) { + $cache = &drupal_static(__FUNCTION__); + + if (!is_object($object)) { + // The object could not be loaded... Presumably, we don't have + // permission. + return FALSE; + } + if ($user === NULL) { + global $user; + } + + // Populate the cache on a miss. + if (!isset($cache[$op][$object->id][$user->uid])) { + module_load_include('inc', 'islandora', 'includes/utilities'); + + $results = islandora_invoke_hook_list('islandora_object_access', $object->models, array( + $op, + $object, + $user, + )); + + // Nothing returned FALSE, and something returned TRUE. + $cache[$op][$object->id][$user->uid] = (!in_array(FALSE, $results, TRUE) && in_array(TRUE, $results, TRUE)); + } + + return $cache[$op][$object->id][$user->uid]; +} + +/** + * Implements hook_islandora_object_access(). + * + * Denies according to PID namespace restrictions, then passes or denies + * according to core Drupal permissions according to user_access(). + */ +function islandora_islandora_object_access($op, $object, $user) { + module_load_include('inc', 'islandora', 'includes/utilities'); + + return islandora_namespace_accessible($object->id) && user_access($op, $user); +} + +/** + * Hookable access callback for datastreams. + * + * Requires the equivalent permissions on the object. + */ +function islandora_datastream_access($op, $datastream, $user = NULL) { + $cache = &drupal_static(__FUNCTION__); + + if (!is_object($datastream)) { + // The object could not be loaded... Presumably, we don't have + // permission. + return NULL; + } + if ($user === NULL) { + global $user; + } + + // Populate the cache on a miss. + if (!isset($cache[$op][$datastream->parent->id][$datastream->id][$user->uid])) { + module_load_include('inc', 'islandora', 'includes/utilities'); + $object_results = islandora_invoke_hook_list('islandora_object_access', $datastream->parent->models, array( + $op, + $datastream->parent, + $user, + )); + + $datastream_results = islandora_invoke_hook_list('islandora_datastream_access', $datastream->parent->models, array( + $op, + $datastream, + $user, + )); + + // Neither the object nor the datastream check returned FALSE, and one in + // the object or datastream checks returned TRUE. + $cache[$op][$datastream->parent->id][$datastream->id][$user->uid] = ( + !in_array(FALSE, $object_results, TRUE) && + !in_array(FALSE, $datastream_results, TRUE) && + (in_array(TRUE, $object_results, TRUE) || in_array(TRUE, $datastream_results, TRUE)) + ); + } + + return $cache[$op][$datastream->parent->id][$datastream->id][$user->uid]; +} diff --git a/tests/hooked_access.test b/tests/hooked_access.test new file mode 100644 index 00000000..0039460e --- /dev/null +++ b/tests/hooked_access.test @@ -0,0 +1,149 @@ + 'Islandora Hooked Access Callback', + 'description' => 'Ensure that the hooked access callback returns appropriate results.', + 'group' => 'Islandora', + ); + } + + /** + * Creates an admin user and a connection to a fedora repository. + * + * @see IslandoraWebTestCase::setUp() + */ + public function setUp() { + parent::setUp('islandora_hooked_access_test'); + $this->repository = $this->admin->repository; + $this->objects = array( + 'test:testAccessHook', + ); + $this->op = FEDORA_VIEW_OBJECTS; + $this->other_op = FEDORA_INGEST; + $this->denied_op = FEDORA_PURGE; + $this->purgeTestObjects(); + $this->dsid = 'asdf'; + $this->createTestObjects(); + $this->object = $this->repository->getObject('test:testAccessHook'); + } + + /** + * Free any objects/resources created for this test. + * + * @see IslandoraWebTestCase::tearDown() + */ + public function tearDown() { + $this->purgeTestObjects(); + unset($this->repository); + unset($_SESSION['islandora_hooked_access_test']); + parent::tearDown(); + } + + /** + * Create the test object(s) to use during the test. + */ + public function createTestObjects() { + foreach ($this->objects as $object_id) { + $object = $this->repository->constructObject($object_id); + $object->label = $object_id; + + $datastream = $object->constructDatastream($this->dsid, 'M'); + $datastream->label = 'fdsa'; + $datastream->mimetype = 'text/plain'; + $datastream->content = 'Some kinda awesome content stuffs...'; + + $object->ingestDatastream($datastream); + $this->repository->ingestObject($object); + } + } + + /** + * Purge any objects created by the test's in this class. + */ + public function purgeTestObjects() { + foreach ($this->objects as $object) { + try { + $object = $this->repository->getObject($object); + $this->repository->purgeObject($object->id); + } + catch (Exception $e) { + // Meh... Either it didn't exist or the purge failed. + } + } + } + + /** + * Deny an object permission check without an object. + */ + public function testDenyBadObject() { + $this->assertFalse(islandora_object_access($this->op, 'this is not an object'), 'Deny bad objects.'); + } + + /** + * Deny a datastream permission check without a datastream. + */ + public function testDenyBadDatastream() { + $this->assertFalse(islandora_datastream_access($this->op, 'this is not a datastream'), 'Deny bad datastreams.'); + } + + /** + * Allow operation on object. + */ + public function testAllowObject() { + $user = $this->drupalCreateUser(array($this->op)); + + $_SESSION['islandora_hooked_access_test'] = array( + $this->op, + $this->object, + $user, + ); + $this->assertTrue(islandora_object_access($this->op, $this->object, $user), 'Allow object access.'); + } + + /** + * Allow operation on datastream. + */ + public function testAllowDatastream() { + $user = $this->drupalCreateUser(array($this->op)); + + $_SESSION['islandora_hooked_access_test'] = array( + $this->op, + $this->object['asdf'], + $user, + ); + $this->assertTrue(islandora_datastream_access($this->op, $this->object['asdf'], $user), 'Allow datastream access.'); + } + + /** + * Deny an operation which was not explicitly allowed on an object. + */ + public function testDenyObjectExplicit() { + $this->assertFalse(islandora_object_access($this->denied_op, $this->object), 'Explicit denial of object access.'); + } + + /** + * Deny an operation which was not explicitly allowed on a datastream. + */ + public function testDenyDatastreamExplicit() { + $this->assertFalse(islandora_datastream_access($this->denied_op, $this->object['asdf']), 'Explicit denial of datastream access.'); + } +} diff --git a/tests/islandora_hooked_access_test.info b/tests/islandora_hooked_access_test.info new file mode 100644 index 00000000..6c585daf --- /dev/null +++ b/tests/islandora_hooked_access_test.info @@ -0,0 +1,7 @@ +name = Islandora Hooked Access Callback testing +description = Tests callback hooks. Do not enable. +core = 7.x +package = Testing +hidden = TRUE +files[] = islandora_hooks_test.module +dependencies[] = islandora diff --git a/tests/islandora_hooked_access_test.module b/tests/islandora_hooked_access_test.module new file mode 100644 index 00000000..de417738 --- /dev/null +++ b/tests/islandora_hooked_access_test.module @@ -0,0 +1,31 @@ + 'datastream-id', - 'data' => l($ds->id, islandora_datastream_get_url($ds, 'view')), + 'data' => theme('islandora_datastream_view_link', array( + 'datastream' => $ds, + )), ), array( 'class' => 'datastream-label', @@ -49,15 +51,21 @@ function islandora_preprocess_islandora_default_edit(array &$variables) { ), array( 'class' => 'datastream-download', - 'data' => l(t('download'), islandora_datastream_get_url($ds, 'download')), + 'data' => theme('islandora_datastream_download_link', array( + 'datastream' => $ds, + )), ), array( 'class' => 'datstream-edit', - 'data' => islandora_datastream_edit_get_link($ds), + 'data' => theme('islandora_datastream_edit_link', array( + 'datastream' => $ds, + )), ), array( 'class' => 'datastream-delete', - 'data' => islandora_datastream_get_delete_link($ds), + 'data' => theme('islandora_datastream_delete_link', array( + 'datastream' => $ds, + )), ), ); } @@ -95,7 +103,9 @@ function islandora_preprocess_islandora_default(&$variables) { $download_path = islandora_datastream_get_url($ds, 'download'); $datastreams[$id]['id'] = $id; $datastreams[$id]['label'] = $label; - $datastreams[$id]['label_link'] = l($label, $download_path); + $datastreams[$id]['label_link'] = islandora_datastream_access(FEDORA_VIEW_OBJECTS, $ds) ? + l($label, $download_path) : + $label; $datastreams[$id]['download_url'] = $download_path; $datastreams[$id]['mimetype'] = $ds->mimetype; $datastreams[$id]['size'] = islandora_datastream_get_human_readable_size($ds); @@ -108,14 +118,14 @@ function islandora_preprocess_islandora_default(&$variables) { } $variables['datastreams'] = $datastreams; // Objects in fcrepo4 don't always contain a DC datastream. - if (isset($islandora_object['DC'])) { + if (isset($islandora_object['DC']) && islandora_datastream_access(FEDORA_VIEW_OBJECTS, $islandora_object['DC'])) { $dc_object = DublinCore::importFromXMLString($islandora_object['DC']->content); $dc_array = $dc_object->asArray(); } $variables['dc_array'] = isset($dc_array) ? $dc_array : array(); $variables['islandora_dublin_core'] = isset($dc_object) ? $dc_object : NULL; $variables['islandora_object_label'] = $islandora_object->label; - if (isset($islandora_object['TN'])) { + if (isset($islandora_object['TN']) && islandora_datastream_access(FEDORA_VIEW_OBJECTS, $islandora_object['TN'])) { $variables['islandora_thumbnail_url'] = url("islandora/object/{$islandora_object->id}/datastream/TN/view"); } } @@ -197,12 +207,16 @@ function islandora_preprocess_islandora_objects(array &$variables) { $o = islandora_object_load($o); $url = "islandora/object/{$o->id}"; $link_options = array('html' => TRUE, 'attributes' => array('title' => $o->label)); - $img = theme_image(array('path' => url("$url/datastream/TN/view"), 'attributes' => array())); + $img = islandora_datastream_access(FEDORA_VIEW_OBJECTS, $o['TN']) ? + theme('image', array('path' => url("$url/datastream/TN/view"), 'attributes' => array())) : + ''; $description = NULL; - $dc = DublinCore::importFromXMLString($o['DC']->content); - if ($dc) { - $dc = $dc->asArray(); - $description = $dc['dc:description']['value']; + if (isset($o['DC']) && islandora_datastream_access(FEDORA_VIEW_OBJECTS, $o['DC'])) { + $dc = DublinCore::importFromXMLString($o['DC']->content); + if ($dc) { + $dc = $dc->asArray(); + $description = $dc['dc:description']['value']; + } } return array( 'label' => $o->label, @@ -218,3 +232,75 @@ function islandora_preprocess_islandora_objects(array &$variables) { $module_path = drupal_get_path('module', 'islandora'); drupal_add_css("$module_path/css/islandora.objects.css"); } + +/** + * Renders a link to allow downloading of a datatream. + * + * @param array $vars + * An array containing: + * - datastream: An AbstractDatastream for which to generate a download link. + */ +function theme_islandora_datastream_download_link(array $vars) { + $datastream = $vars['datastream']; + module_load_include('inc', 'islandora', 'includes/utilities'); + + $label = t('download'); + return islandora_datastream_access(FEDORA_VIEW_OBJECTS, $datastream) ? + l($label, islandora_datastream_get_url($datastream, 'download')) : + ''; +} + +/** + * Renders a link to allow viewing of a datatream. + * + * @param array $vars + * An array containing: + * - datastream: An AbstractDatastream for which to generate a view link. + */ +function theme_islandora_datastream_view_link(array $vars) { + $datastream = $vars['datastream']; + module_load_include('inc', 'islandora', 'includes/utilities'); + + $label = check_plain($datastream->label); + return islandora_datastream_access(FEDORA_VIEW_OBJECTS, $datastream) ? + l($label, islandora_datastream_get_url($datastream, 'view')) : + $label; +} + +/** + * Renders a link to allow deleting of a datatream. + * + * @param array $vars + * An array containing: + * - datastream: An AbstractDatastream for which to generate a delete link. + */ +function theme_islandora_datastream_delete_link(array $vars) { + $datastream = $vars['datastream']; + + $datastreams = module_invoke_all('islandora_undeletable_datastreams', $datastream->parent->models); + + $can_delete = !in_array($datastream->id, $datastreams) && islandora_datastream_access(FEDORA_PURGE, $datastream); + + return $can_delete ? + l(t('delete'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete") : + ''; +} + +/** + * Renders a link to allow editing of a datatream. + * + * @param array $vars + * An array containing: + * - datastream: An AbstractDatastream for which to generate a edit link. + */ +function theme_islandora_datastream_edit_link(array $vars) { + $datastream = $vars['datastream']; + + $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream); + + $can_edit = count($edit_registry) > 0 && islandora_datastream_access(FEDORA_METADATA_EDIT, $datastream); + + return $can_edit ? + l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") : + ''; +}