Browse Source

Merge pull request #352 from adam-vessey/7.x-hooked-access

Implement hooked access callback.
pull/355/head
Jonathan Green 12 years ago
parent
commit
77529491c7
  1. 56
      includes/datastream.inc
  2. 1
      includes/object_properties.form.inc
  3. 8
      includes/utilities.inc
  4. 76
      islandora.api.php
  5. 1
      islandora.info
  6. 225
      islandora.module
  7. 149
      tests/hooked_access.test
  8. 7
      tests/islandora_hooked_access_test.info
  9. 31
      tests/islandora_hooked_access_test.module
  10. 110
      theme/theme.inc

56
includes/datastream.inc

@ -84,9 +84,12 @@ function islandora_datastream_get_url(AbstractDatastream $datastream, $type = 'd
* The datastream to generated the url to. * The datastream to generated the url to.
*/ */
function islandora_datastream_get_delete_link(AbstractDatastream $datastream) { function islandora_datastream_get_delete_link(AbstractDatastream $datastream) {
$datastreams = module_invoke_all('islandora_undeletable_datastreams', $datastream->parent->models); $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_delete_link" theme implementation.');
$can_delete = !in_array($datastream->id, $datastreams); trigger_error(filter_xss($message), E_USER_DEPRECATED);
return $can_delete ? l(t('delete'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete") : '';
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. * The datastream to generated the url to.
*/ */
function islandora_datastream_edit_get_link(AbstractDatastream $datastream) { function islandora_datastream_edit_get_link(AbstractDatastream $datastream) {
$edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream); $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_edit_link" theme implementation.');
$can_edit = count($edit_registry) > 0 && user_access(FEDORA_METADATA_EDIT); trigger_error(filter_xss($message), E_USER_DEPRECATED);
return $can_edit ? l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") : '';
return theme('islandora_datastream_edit_link', array(
'datastream' => $datastream,
));
} }
/** /**
@ -144,3 +150,41 @@ function islandora_edit_datastream_registry_render(array $edit_registry) {
'#markup' => $markup, '#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,
));
}

1
includes/object_properties.form.inc

@ -60,6 +60,7 @@ function islandora_object_properties_form(array $form, array &$form_state, Abstr
), ),
'delete' => array( 'delete' => array(
'#type' => 'submit', '#type' => 'submit',
'#access' => islandora_object_access(FEDORA_PURGE, $object),
'#value' => t('Delete'), '#value' => t('Delete'),
'#submit' => array('islandora_object_properties_form_delete'), '#submit' => array('islandora_object_properties_form_delete'),
'#limit_validation_errors' => array(array('pid')), '#limit_validation_errors' => array(array('pid')),

8
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. * - "optional": A boolean indicating if the given stream is optional.
*/ */
function islandora_get_datastreams_requirements_from_content_model(AbstractObject $object) { 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(); return array();
} }
$xml = new SimpleXMLElement($object[DS_COMP_STREAM]->content); $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. * TRUE if the account has all the given permissions, FALSE otherwise.
*/ */
function islandora_user_access_all(array $perms, $account = NULL) { 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) { foreach ($perms as $perm) {
if (!user_access($perm, $account)) { if (!user_access($perm, $account)) {
return FALSE; return FALSE;
@ -694,6 +697,9 @@ function islandora_user_access_all(array $perms, $account = NULL) {
* otherwise. * otherwise.
*/ */
function islandora_user_access_any(array $perms, $account = NULL) { 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) { foreach ($perms as $perm) {
if (user_access($perm, $account)) { if (user_access($perm, $account)) {
return TRUE; return TRUE;

76
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) { 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) {
}

1
islandora.info

@ -15,5 +15,6 @@ files[] = tests/islandora_web_test_case.inc
files[] = tests/authtokens.test files[] = tests/authtokens.test
files[] = tests/hooks.test files[] = tests/hooks.test
files[] = tests/ingest.test files[] = tests/ingest.test
files[] = tests/hooked_access.test
files[] = tests/islandora_manage_permissions.test files[] = tests/islandora_manage_permissions.test
php = 5.3 php = 5.3

225
islandora.module

@ -190,8 +190,8 @@ function islandora_menu() {
'page arguments' => array(4, FALSE), 'page arguments' => array(4, FALSE),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
// This menu item uses token authentication in islandora_tokened_object. // This menu item uses token authentication in islandora_tokened_object.
@ -208,8 +208,8 @@ function islandora_menu() {
'page arguments' => array(4), 'page arguments' => array(4),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array( $items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array(
@ -218,8 +218,8 @@ function islandora_menu() {
'page arguments' => array(4), 'page arguments' => array(4),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc', 'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_METADATA_EDIT, 2, 4), 'access arguments' => array(FEDORA_METADATA_EDIT, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/delete'] = array( $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), 'page arguments' => array('islandora_delete_datastream_form', 4),
'file' => 'includes/delete_datastream.form.inc', 'file' => 'includes/delete_datastream.form.inc',
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_datastream_access_callback', 'access callback' => 'islandora_datastream_access',
'access arguments' => array(FEDORA_PURGE, 2, 4), 'access arguments' => array(FEDORA_PURGE, 4),
'load arguments' => array(2), 'load arguments' => array(2),
); );
$items['islandora/object/%islandora_object/print'] = array( $items['islandora/object/%islandora_object/print'] = array(
@ -237,7 +237,7 @@ function islandora_menu() {
'page callback' => 'islandora_print_object', 'page callback' => 'islandora_print_object',
'page arguments' => array(2), 'page arguments' => array(2),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_access_callback', 'access callback' => 'islandora_object_access',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2),
'load arguments' => array(2), 'load arguments' => array(2),
); );
@ -245,7 +245,7 @@ function islandora_menu() {
'page callback' => 'islandora_download_clip', 'page callback' => 'islandora_download_clip',
'page arguments' => array(2), 'page arguments' => array(2),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_access_callback', 'access callback' => 'islandora_object_access',
'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2),
'load arguments' => array(2), 'load arguments' => array(2),
); );
@ -322,6 +322,22 @@ function islandora_theme() {
'template' => 'theme/islandora-objects-list', 'template' => 'theme/islandora-objects-list',
'variables' => array('objects' => NULL), '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 * @global $user
* *
* @param mixed $object * @param mixed $object_or_datastream
* The AbstractObject or AbstractDatastream to test for accessibility, if NULL * The AbstractObject or AbstractDatastream to test for accessibility, if NULL
* is given the object is assumed to not exist or be inaccessible. * is given the object is assumed to not exist or be inaccessible.
* @param array $permissions * @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 * (optional) TRUE to grant access if any single requirement is met from both
* the permissions and content models parameters. FALSE if all requirements * the permissions and content models parameters. FALSE if all requirements
* must be met from both the permissions and content model parameters. * 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 * (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 * a token to restore the user. If no GET parameter is present use currently
* logged in user. * logged in user.
@ -401,9 +417,10 @@ function islandora_forms($form_id) {
* TRUE if the user is allowed to access this object/datastream, FALSE * TRUE if the user is allowed to access this object/datastream, FALSE
* otherwise. * 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'); module_load_include('inc', 'islandora', 'includes/utilities');
$is_repository_accessible = &drupal_static(__FUNCTION__); $is_repository_accessible = &drupal_static(__FUNCTION__);
// If the repository is inaccessible then access always fails. // If the repository is inaccessible then access always fails.
if (!isset($is_repository_accessible)) { if (!isset($is_repository_accessible)) {
$is_repository_accessible = islandora_describe_repository(); $is_repository_accessible = islandora_describe_repository();
@ -413,43 +430,74 @@ function islandora_user_access($object, array $permissions, $content_models = ar
return FALSE; return FALSE;
} }
} }
if (!$is_repository_accessible || !is_object($object)) { if (!$is_repository_accessible || !is_object($object_or_datastream) || empty($permissions)) {
return FALSE; 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. // Determine the user account to test against.
if (!isset($account)) { if (!isset($user)) {
$token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING); $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING);
if ($token) { if ($token) {
module_load_include('inc', 'islandora', 'includes/authtokens'); 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) { if ($user) {
$account = user_load($user->uid); $user = user_load($token_user->uid);
} }
} }
else { else {
global $user; 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. // Check for access.
$accessible_namespace = islandora_namespace_accessible($object->id);
if ($access_any) { 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; $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 { else {
$has_required_permissions = islandora_user_access_all($permissions, $account);
$has_required_content_models = count(array_diff($content_models, $object->models)) == 0; $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 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) { function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL, $account = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities'); 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. * 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 * and user permissions
*
* @see islandora_object_datastream_tokened_access_callback()
*/ */
function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) { function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities'); 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; $has_access = FALSE;
for ($i = 0; $i < count($perms) && !$has_access; $i++) { 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']); $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];
}

149
tests/hooked_access.test

@ -0,0 +1,149 @@
<?php
/**
* @file
* Tests to see if the hooks get called when appropriate.
*
* In the test module 'islandora_hooked_access_test' there are implementations
* of hooks being tested. These implementations modifies the session, and
* that's how we test if the hook gets called.
*
* To make sense of these tests reference islandora_hooked_access_test.module.
*/
class IslandoraHookedAccessTestCase extends IslandoraWebTestCase {
/**
* Gets info to display to describe this test.
*
* @see IslandoraWebTestCase::getInfo()
*/
public static function getInfo() {
return array(
'name' => '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.');
}
}

7
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

31
tests/islandora_hooked_access_test.module

@ -0,0 +1,31 @@
<?php
/**
* @file
* Hook implementations tested in hooked_access.test
*/
/**
* Implements hook_islandora_object_access().
*/
function islandora_hooked_access_test_islandora_object_access($op, $object, $user) {
if ($op == FEDORA_PURGE) {
return FALSE;
}
if (isset($_SESSION['islandora_hooked_access_test']) && $_SESSION['islandora_hooked_access_test'] === func_get_args()) {
return TRUE;
}
return NULL;
}
/**
* Implements hook_islandora_datastream_access().
*/
function islandora_hooked_access_test_islandora_datastream_access($op, $datastream, $user) {
if (isset($_SESSION['islandora_hooked_access_test']) && $_SESSION['islandora_hooked_access_test'] === func_get_args()) {
return TRUE;
}
return NULL;
}

110
theme/theme.inc

@ -29,7 +29,9 @@ function islandora_preprocess_islandora_default_edit(array &$variables) {
$rows[] = array( $rows[] = array(
array( array(
'class' => 'datastream-id', 'class' => 'datastream-id',
'data' => l($ds->id, islandora_datastream_get_url($ds, 'view')), 'data' => theme('islandora_datastream_view_link', array(
'datastream' => $ds,
)),
), ),
array( array(
'class' => 'datastream-label', 'class' => 'datastream-label',
@ -49,15 +51,21 @@ function islandora_preprocess_islandora_default_edit(array &$variables) {
), ),
array( array(
'class' => 'datastream-download', 'class' => 'datastream-download',
'data' => l(t('download'), islandora_datastream_get_url($ds, 'download')), 'data' => theme('islandora_datastream_download_link', array(
'datastream' => $ds,
)),
), ),
array( array(
'class' => 'datstream-edit', 'class' => 'datstream-edit',
'data' => islandora_datastream_edit_get_link($ds), 'data' => theme('islandora_datastream_edit_link', array(
'datastream' => $ds,
)),
), ),
array( array(
'class' => 'datastream-delete', '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'); $download_path = islandora_datastream_get_url($ds, 'download');
$datastreams[$id]['id'] = $id; $datastreams[$id]['id'] = $id;
$datastreams[$id]['label'] = $label; $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]['download_url'] = $download_path;
$datastreams[$id]['mimetype'] = $ds->mimetype; $datastreams[$id]['mimetype'] = $ds->mimetype;
$datastreams[$id]['size'] = islandora_datastream_get_human_readable_size($ds); $datastreams[$id]['size'] = islandora_datastream_get_human_readable_size($ds);
@ -108,14 +118,14 @@ function islandora_preprocess_islandora_default(&$variables) {
} }
$variables['datastreams'] = $datastreams; $variables['datastreams'] = $datastreams;
// Objects in fcrepo4 don't always contain a DC datastream. // 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_object = DublinCore::importFromXMLString($islandora_object['DC']->content);
$dc_array = $dc_object->asArray(); $dc_array = $dc_object->asArray();
} }
$variables['dc_array'] = isset($dc_array) ? $dc_array : array(); $variables['dc_array'] = isset($dc_array) ? $dc_array : array();
$variables['islandora_dublin_core'] = isset($dc_object) ? $dc_object : NULL; $variables['islandora_dublin_core'] = isset($dc_object) ? $dc_object : NULL;
$variables['islandora_object_label'] = $islandora_object->label; $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"); $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); $o = islandora_object_load($o);
$url = "islandora/object/{$o->id}"; $url = "islandora/object/{$o->id}";
$link_options = array('html' => TRUE, 'attributes' => array('title' => $o->label)); $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; $description = NULL;
$dc = DublinCore::importFromXMLString($o['DC']->content); if (isset($o['DC']) && islandora_datastream_access(FEDORA_VIEW_OBJECTS, $o['DC'])) {
if ($dc) { $dc = DublinCore::importFromXMLString($o['DC']->content);
$dc = $dc->asArray(); if ($dc) {
$description = $dc['dc:description']['value']; $dc = $dc->asArray();
$description = $dc['dc:description']['value'];
}
} }
return array( return array(
'label' => $o->label, 'label' => $o->label,
@ -218,3 +232,75 @@ function islandora_preprocess_islandora_objects(array &$variables) {
$module_path = drupal_get_path('module', 'islandora'); $module_path = drupal_get_path('module', 'islandora');
drupal_add_css("$module_path/css/islandora.objects.css"); 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") :
'';
}

Loading…
Cancel
Save