. */ // Common datastreams. define('DS_COMP_STREAM', 'DS-COMPOSITE-MODEL'); // Permissions. define('FEDORA_VIEW_OBJECTS', 'view fedora repository objects'); define('FEDORA_METADATA_EDIT', 'edit fedora metadata'); define('FEDORA_ADD_DS', 'add fedora datastreams'); define('FEDORA_INGEST', 'ingest fedora objects'); define('FEDORA_PURGE', 'delete fedora objects and datastreams'); define('FEDORA_MANAGE_PROPERTIES', 'manage object properties'); define('ISLANDORA_VIEW_DATASTREAM_HISTORY', 'view old datastream versions'); // Hooks. define('ISLANDORA_VIEW_HOOK', 'islandora_view_object'); define('ISLANDORA_EDIT_HOOK', 'islandora_edit_object'); define('ISLANDORA_OVERVIEW_HOOK', 'islandora_overview_object'); define('ISLANDORA_PRE_INGEST_HOOK', 'islandora_ingest_pre_ingest'); define('ISLANDORA_POST_INGEST_HOOK', 'islandora_ingest_post_ingest'); define('ISLANDORA_PRE_PURGE_OBJECT_HOOK', 'islandora_pre_purge_object'); define('ISLANDORA_POST_PURGE_OBJECT_HOOK', 'islandora_post_purge_object'); // @todo Add Documentation. define('ISLANDORA_OBJECT_INGESTED_HOOK', 'islandora_object_ingested'); define('ISLANDORA_OBJECT_MODIFIED_HOOK', 'islandora_object_modified'); define('ISLANDORA_OBJECT_PURGED_HOOK', 'islandora_object_purged'); define('ISLANDORA_DATASTREAM_INGESTED_HOOK', 'islandora_datastream_ingested'); define('ISLANDORA_DATASTREAM_MODIFIED_HOOK', 'islandora_datastream_modified'); define('ISLANDORA_DATASTREAM_PURGED_HOOK', 'islandora_datastream_purged'); define('ISLANDORA_INGEST_STEP_HOOK', 'islandora_ingest_steps'); // Autocomplete paths. define('ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE', 'islandora/autocomplete/content-models'); /** * Implements hook_menu(). * * We need some standard entry points so we can have consistent urls for * different Object actions */ function islandora_menu() { $items = array(); $items['admin/islandora'] = array( 'title' => 'Islandora', 'description' => "Configure settings associated with Islandora.", 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); $items['admin/islandora/configure'] = array( 'title' => 'Configuration', 'description' => 'Configure settings for Islandora.', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_repository_admin'), 'file' => 'includes/admin.form.inc', 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, 'weight' => -1, ); $items['admin/islandora/solution_packs'] = array( 'title' => 'Solution packs', 'description' => 'Install content models and collections required by installed solution packs.', 'page callback' => 'islandora_solution_packs_admin', 'access arguments' => array(FEDORA_ADD_DS), 'file' => 'includes/solution_packs.inc', 'type' => MENU_NORMAL_ITEM, ); $items['islandora'] = array( 'title' => 'Islandora Repository', 'page callback' => 'islandora_view_default_object', 'type' => MENU_NORMAL_ITEM, 'access arguments' => array(FEDORA_VIEW_OBJECTS), ); $items['islandora/object/%islandora_object'] = array( 'title callback' => 'islandora_drupal_title', 'title arguments' => array(2), 'page callback' => 'islandora_view_object', 'page arguments' => array(2), 'type' => MENU_NORMAL_ITEM, 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), ); $items['islandora/object/%islandora_object/view'] = array( 'title' => 'View', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -1, ); $items['islandora/object/%islandora_object/view/default'] = array( 'title' => 'View', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -1, ); $items['islandora/object/%islandora_object/manage'] = array( 'title' => 'Manage', 'page callback' => 'islandora_manage_overview_object', 'page arguments' => array(2), 'type' => MENU_LOCAL_TASK, 'access callback' => 'islandora_object_manage_access_callback', 'access arguments' => array( array( FEDORA_MANAGE_PROPERTIES, FEDORA_METADATA_EDIT, FEDORA_ADD_DS, FEDORA_PURGE, FEDORA_INGEST, ), 2), ); $items['islandora/object/%islandora_object/manage/overview'] = array( 'title' => 'Overview', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -20, ); $items['islandora/object/%islandora_object/manage/datastreams'] = array( 'title' => 'Datastreams', 'type' => MENU_LOCAL_TASK, 'page callback' => 'islandora_edit_object', 'page arguments' => array(2), 'access callback' => 'islandora_object_manage_access_callback', 'access arguments' => array( array( FEDORA_METADATA_EDIT, FEDORA_ADD_DS, FEDORA_PURGE, ), 2), 'weight' => -10, ); $items['islandora/object/%islandora_object/manage/properties'] = array( 'title' => 'Properties', 'page callback' => 'drupal_get_form', 'file' => 'includes/object_properties.form.inc', 'page arguments' => array('islandora_object_properties_form', 2), 'type' => MENU_LOCAL_TASK, 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_MANAGE_PROPERTIES, 2), 'weight' => -5, ); $items['islandora/object/%islandora_object/delete'] = array( 'title' => 'Delete object', 'file' => 'includes/delete_object.form.inc', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_delete_object_form', 2), 'type' => MENU_CALLBACK, 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_PURGE, 2), ); $items['islandora/object/%islandora_object/manage/datastreams/add'] = array( 'title' => 'Add a datastream', 'file' => 'includes/add_datastream.form.inc', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_add_datastream_form', 2), 'type' => MENU_LOCAL_ACTION, 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_ADD_DS, 2), ); $items['islandora/object/%islandora_object/manage/datastreams/add/autocomplete'] = array( 'file' => 'includes/add_datastream.form.inc', 'page callback' => 'islandora_add_datastream_form_autocomplete_callback', 'page arguments' => array(2), 'type' => MENU_CALLBACK, 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_ADD_DS, 2), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream'] = array( 'title' => 'View datastream', 'page callback' => 'islandora_view_datastream', 'page arguments' => array(4, FALSE), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', '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. $items['islandora/object/%islandora_tokened_object/datastream/%islandora_tokened_datastream/view'] = array( 'title' => 'View datastream', 'load arguments' => array('%map'), 'access callback' => 'islandora_object_datastream_tokened_access_callback', 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2, 4), 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream/download'] = array( 'title' => 'Download datastream', 'page callback' => 'islandora_download_datastream', 'page arguments' => array(4), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', '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( 'title' => 'Edit datastream', 'page callback' => 'islandora_edit_datastream', 'page arguments' => array(4), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', '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( 'title' => 'Delete data stream', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_delete_datastream_form', 4), 'file' => 'includes/delete_datastream.form.inc', 'type' => MENU_CALLBACK, 'access callback' => 'islandora_datastream_access', 'access arguments' => array(FEDORA_PURGE, 4), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream/version'] = array( 'title' => 'Datastream Versions', 'page arguments' => array(4), 'page callback' => 'islandora_datastream_version_table', 'file' => 'includes/datastream.version.inc', 'type' => MENU_CALLBACK, 'access callback' => 'islandora_datastream_access', 'access arguments' => array(ISLANDORA_VIEW_DATASTREAM_HISTORY, 4), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream/version/%/delete'] = array( 'title' => 'Delete datastream version', 'page arguments' => array('islandora_delete_datastream_version_form', 4, 6), 'page callback' => 'drupal_get_form', 'file' => 'includes/datastream.version.inc', 'type' => MENU_CALLBACK, 'access callback' => 'islandora_datastream_access', 'access arguments' => array(FEDORA_PURGE, 4), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream/version/%/view'] = array( 'title' => 'View datastream version', 'page callback' => 'islandora_view_datastream', 'page arguments' => array(4, FALSE, 6), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', 'access callback' => 'islandora_datastream_access', 'access arguments' => array(ISLANDORA_VIEW_DATASTREAM_HISTORY, 4), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/print'] = array( 'title' => 'Print Object', 'page callback' => 'islandora_print_object', 'page arguments' => array(2), 'type' => MENU_CALLBACK, 'access callback' => 'islandora_object_access', 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'load arguments' => array(2), ); $items['islandora/object/%islandora_object/download_clip'] = array( 'page callback' => 'islandora_download_clip', 'page arguments' => array(2), 'type' => MENU_CALLBACK, 'access callback' => 'islandora_object_access', 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'load arguments' => array(2), ); $items[ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE] = array( 'title' => 'Autocomplete callback', 'description' => 'Autocomplete a Fedora content model PID.', 'file' => 'includes/content_model.autocomplete.inc', 'page callback' => 'islandora_content_model_autocomplete', 'page arguments' => array(3), 'access arguments' => array('administer site configuration'), 'type' => MENU_CALLBACK, ); return $items; } /** * Implements hook_admin_paths(). */ function islandora_admin_paths() { $paths = array(); $paths['islandora/object/*/manage*'] = TRUE; $paths['islandora/object/*/delete*'] = TRUE; $paths['islandora/object/*/datastream/*/edit'] = TRUE; $paths['islandora/object/*/datastream/*/versions'] = TRUE; return $paths; } /** * Implements hook_theme(). */ function islandora_theme() { return array( // Default object template. 'islandora_default' => array( 'file' => 'theme/theme.inc', 'template' => 'theme/islandora-object', 'variables' => array('islandora_object' => NULL), ), // Default edit page. 'islandora_default_edit' => array( 'file' => 'theme/theme.inc', 'template' => 'theme/islandora-object-edit', 'variables' => array('islandora_object' => NULL), ), // Admin table for solution pack viewer selection. 'islandora_viewers_table' => array( 'file' => 'includes/solution_packs.inc', 'render element' => 'form', ), // Print object view. 'islandora_object_print' => array( 'file' => 'theme/theme.inc', 'variables' => array('object' => NULL, 'content' => array()), ), // Render a bunch of objects as either a grid or a list. 'islandora_objects' => array( 'file' => 'theme/theme.inc', 'template' => 'theme/islandora-objects', 'variables' => array( 'objects' => NULL, 'display' => NULL, 'page_size' => 20, 'limit' => 10, ), ), // Render a bunch of objects as a grid. 'islandora_objects_grid' => array( 'file' => 'theme/theme.inc', 'template' => 'theme/islandora-objects-grid', 'variables' => array('objects' => NULL), ), // Render a bunch of objects as a list. 'islandora_objects_list' => array( 'file' => 'theme/theme.inc', '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, 'version' => NULL), ), 'islandora_datastream_view_link' => array( 'file' => 'theme/theme.inc', 'variables' => array( 'datastream' => NULL, 'version' => NULL, 'label' => NULL, ), ), 'islandora_datastream_download_link' => array( 'file' => 'theme/theme.inc', 'variables' => array('datastream' => NULL), ), 'islandora_datastream_version_link' => array( 'file' => 'theme/theme.inc', 'variables' => array('datastream' => NULL), ), ); } /** * Implements hook_permission(). */ function islandora_permission() { return array( FEDORA_VIEW_OBJECTS => array( 'title' => t('View repository objects'), 'description' => t('View objects in the repository. Note: Fedora XACML security policies may override this permission.'), ), FEDORA_ADD_DS => array( 'title' => t('Add datastreams to repository objects'), 'description' => t('Add datastreams to objects in the repository. Note: Fedora XACML security policies may override this position.'), ), FEDORA_METADATA_EDIT => array( 'title' => t('Edit metadata'), 'description' => t('Edit metadata for objects in the repository.'), ), FEDORA_INGEST => array( 'title' => t('Create new repository objects'), 'description' => t('Create new objects in the repository.'), ), FEDORA_PURGE => array( 'title' => t('Permanently remove objects from the repository'), 'description' => t('Permanently remove objects from the repository.'), ), FEDORA_MANAGE_PROPERTIES => array( 'title' => t('Manage object properties'), 'description' => t('Modify object labels, owner IDs, and states.'), ), ISLANDORA_VIEW_DATASTREAM_HISTORY => array( 'title' => t('View datastream history'), 'description' => t('View all previous versions of a datastream.'), ), ); } /** * Implements hook_forms(). */ function islandora_forms($form_id) { $forms = array(); if (strpos($form_id, 'islandora_solution_pack_form_') !== FALSE) { $forms[$form_id] = array( 'callback' => 'islandora_solution_pack_form', ); } return $forms; } /** * Checks whether the user can access the given object. * * Checks for repository access, object/datastream existance, namespace access, * user permissions, content models. * * Will check the given user or the user repersented by the GET token parameter, * failing that it will use the global user. * * @global $user * * @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 * The required user permissions. * @param array $content_models * The required content models. * @param bool $access_any * (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 $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. * * @return bool * TRUE if the user is allowed to access this object/datastream, FALSE * otherwise. */ 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(); if (!$is_repository_accessible) { // Only display the inaccessible message once. islandora_display_repository_inaccessible_message(); return FALSE; } } 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($user)) { $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING); if ($token) { module_load_include('inc', 'islandora', 'includes/authtokens'); $token_user = islandora_validate_object_token($object->id, $datastream->id, $token); if ($user) { $user = user_load($token_user->uid); } } else { global $user; } } // Check for access. if ($access_any) { $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_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 FALSE; } /** * Checks whether the user can access the given object. * * Checks for object existance, accessiblitly, namespace permissions, * and user permissions * * @param string $perm * User permission to test for. * @param AbstractObject $object * The object to test, if NULL given the object doesn't exist or is * inaccessible. * * @return bool * TRUE if the user is allowed to access this object, FALSE otherwise. */ function islandora_object_access_callback($perm, $object = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); if (!$object && !islandora_describe_repository()) { islandora_display_repository_inaccessible_message(); return FALSE; } return islandora_object_access($perm, $object); } /** * Checks whether the user can access the given object and datastream. * * Checks for object existance, accessiblitly, namespace permissions, * and user permissions * * @param string $perm * The user permission to test for. * @param AbstractObject $object * The object to test, if NULL given the object doesn't exist or is * inaccessible. * @param AbstractDatastream $datastream * The datastream to test, if NULL given the datastream doesn't exist * or is inaccessible. * @param StdObject $account * The account to test permissions as or NULL for current user. * * @return bool * TRUE if the user is allowed to access this object, FALSE otherwise. */ function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL, $account = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); $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); } /** * Checks whether the user can access the given object and datastream. * * This function will validate and use a token if present in the GET parameters. * * Checks for object existance, accessibility, namespace permissions, * and user permissions */ function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); $token_account = NULL; $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING); if ($token) { $user = islandora_validate_object_token($object->id, $datastream->id, $token); if ($user) { $token_account = user_load($user->uid); } } return islandora_datastream_access($perm, $datastream, $token_account); } /** * Checks whether the user can access the given object's manage tab. * * Checks for object existance, accessiblitly, namespace permissions, * and user permissions * * @param array $perms * Array of user permission to test for. * @param AbstractObject $object * The object to test, if NULL given the object doesn't exist or is * inaccessible. * * @return bool * TRUE if the user is allowed to access this object, FALSE otherwise. */ function islandora_object_manage_access_callback($perms, $object = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); if (!$object && !islandora_describe_repository()) { islandora_display_repository_inaccessible_message(); return FALSE; } $has_access = FALSE; for ($i = 0; $i < count($perms) && !$has_access; $i++) { $has_access = $has_access || islandora_object_access($perms[$i], $object); } return $has_access; } /** * Renders the given objects manage overview page. * * @param AbstractObject $object * The object to manage. * * @return string * The HTML repersentation of the manage object page. */ function islandora_manage_overview_object(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/utilities'); $output = array(); foreach (islandora_build_hook_list(ISLANDORA_OVERVIEW_HOOK, $object->models) as $hook) { $temp = module_invoke_all($hook, $object); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } } if (empty($output)) { // Add in the default, if we did not get any results. $output = islandora_default_islandora_manage_overview_object($object); } arsort($output); drupal_alter(ISLANDORA_OVERVIEW_HOOK, $object, $output); return implode('', $output); } /** * Renders the default manage object page for the given object. * * @param AbstractObject $object * The object used to render the manage object page. * * @return array * The default rendering of the object manage page, indexed at * 'Default Edit output'. */ function islandora_default_islandora_manage_overview_object(AbstractObject $object) { $output = theme('islandora_default_overview', array('islandora_object' => $object)); return array('Default overview output' => $output); } /** * Renders the given objects manage page. * * Its possible to modify the output of this function if 'ISLANDORA_EDIT_HOOK' * is implemented in other modules. * * If no modules implement 'ISLANDORA_EDIT_HOOK' then this function returns the * default manage view. * * @param AbstractObject $object * The object to manage. * * @return string * The HTML repersentation of the manage object page. */ function islandora_edit_object(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); module_load_include('inc', 'islandora', 'includes/utilities'); drupal_set_title($object->label); drupal_set_breadcrumb(islandora_get_breadcrumbs($object)); $output = array(); foreach (islandora_build_hook_list(ISLANDORA_EDIT_HOOK, $object->models) as $hook) { $temp = module_invoke_all($hook, $object); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } } if (empty($output)) { // Add in the default, if we did not get any results. $output = islandora_default_islandora_edit_object($object); } arsort($output); drupal_alter(ISLANDORA_EDIT_HOOK, $object, $output); return implode('', $output); } /** * Renders the default manage object page for the given object. * * @param AbstractObject $object * The object used to render the manage object page. * * @return array * The default rendering of the object manage page, indexed at * 'Default Edit output'. */ function islandora_default_islandora_edit_object(AbstractObject $object) { $output = theme('islandora_default_edit', array('islandora_object' => $object)); return array('Default Edit output' => $output); } /** * Page callback for the path "islandora". * * Redirects to the view of the object indicated by the Drupal variable * 'islandora_repository_pid'. */ function islandora_view_default_object() { $pid = variable_get('islandora_repository_pid', 'islandora:root'); drupal_goto("islandora/object/$pid"); } /** * Renders the default view object page for the given object. * * Modules should implement ISLANDORA_VIEW_HOOK for the Fedora Content * models that their modules want to provide a view for. * * If no modules implement the hook then the default view object page * will be rendered. * * @param AbstractObject $object * The object to view. * * @return string * The html repersentation of this object. */ function islandora_view_object(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); module_load_include('inc', 'islandora', 'includes/utilities'); drupal_set_title($object->label); drupal_set_breadcrumb(islandora_get_breadcrumbs($object)); // Optional pager parameters. $page_number = (empty($_GET['page'])) ? '1' : $_GET['page']; $page_size = (empty($_GET['pagesize'])) ? '10' : $_GET['pagesize']; $output = array(); $hooks = islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $object->models); foreach ($hooks as $hook) { // @todo Remove page number and size from this hook, implementers of the // hook should use drupal page handling directly. $temp = module_invoke_all($hook, $object, $page_number, $page_size); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } } if (empty($output)) { // No results, use the default view. $output = islandora_default_islandora_view_object($object); } arsort($output); drupal_alter($hooks, $object, $output); return implode('', $output); } /** * Title callback for drupal title. * * Changes the drupal title to be the objects label. * models that their modules want to provide a view for. * * @param AbstractObject $object * The object to view. * * @return string * The objects label. */ function islandora_drupal_title(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); drupal_set_breadcrumb(islandora_get_breadcrumbs($object)); return $object->label; } /** * Renders the default view object page for the given object. * * @param AbstractObject $object * The object used to render the view object page. * * @return array * The default rendering of the object view page, indexed at 'Default output'. */ function islandora_default_islandora_view_object($object) { $output = theme('islandora_default', array('islandora_object' => $object)); return array('Default output' => $output); } /** * Just a wrapper around fetchings the IslandoraTuque object. * * Includes some very basic error logging. * * @param object $user * The user to connect as. * @param string $url * The URL to connect to. * * @return IslandoraTuque * A IslandoraTuque instance */ function islandora_get_tuque_connection($user = NULL, $url = NULL) { $tuque = &drupal_static(__FUNCTION__); if (!$tuque) { if (IslandoraTuque::exists()) { try { $tuque = new IslandoraTuque($user, $url); } catch (Exception $e) { drupal_set_message(t('Unable to connect to the repository %e', array('%e' => $e)), 'error'); } } else { return NULL; } } return $tuque; } /** * Loads the object from the given ID if possible. * * Often used to get a connection and return an object for the one specified in * the menu path as '%islandora_object'. * * @param string $object_id * The pid of an object in the menu path identified by '%islandora_object'. * * @return FedoraObject * If the given object id exists in the repository then this returns a * FedoraObject. * If no object was found it returns FALSE which triggers * drupal_page_not_found(). * If the object was inaccessible then NULL is returned, and the * access callback is expected to catch that case, triggering * drupal_access_denied(). */ function islandora_object_load($object_id) { $tuque = islandora_get_tuque_connection(); if ($tuque) { try { return $tuque->repository->getObject(urldecode($object_id)); } catch (Exception $e) { if ($e->getCode() == '404') { return FALSE; } else { return NULL; } } } else { IslandoraTuque::getError(); } // Assuming access denied in all other cases for now. return NULL; } /** * Load the the object using a token if passed as a GET parameter. * * A helper function to get a connection and return an object using a token * for authentication. * * @param string $object_id * The PID of an object in the menu path identified by * '%islandora_tokened_object'. * @param array $map * Used to extract the Fedora object's DSID at $map[4]. * * @return FedoraObject * A token authenticated object. @see islandora_object_load */ function islandora_tokened_object_load($object_id, $map) { if (array_key_exists('token', $_GET)) { $token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING); if ($token) { module_load_include('inc', 'islandora', 'includes/authtokens'); $token_user = islandora_validate_object_token($object_id, $map[4], $token); $token_user = $token_user ? user_load($token_user->uid) : NULL; islandora_get_tuque_connection($token_user); } } return islandora_object_load($object_id); } /** * Fetches a datastream object. * * This datastream load must take in arguments in a different * order than the usual islandora_datastream_load. This is because * the function islandora_tokened_object_load needs DSID. It uses * the path %map to avoid duplicate parameters. The menu system * passes 'load arguments' to both islandora_tokened_object_load * and this function and the first parameter is positional with the token. * An alternative: * islandora_tokened_object_load(PID, DSID, PID) * islandora_tokened_datastream_load(DSID, DSID, PID) * * @param mixed $datastream_id * %islandora_tokened_datastream @see islandora_datastream_load * @param array $map * Used to extract the Fedora object's PID at $map[2]. * * @return FedoraDatastream * A datastream from Fedora. * * @see islandora_datastream_load */ function islandora_tokened_datastream_load($datastream_id, $map) { return islandora_datastream_load($datastream_id, $map[2]); } /** * Fetches a datastream object. * * A helper function to get an datastream specified as '%islandora_datastream' * for the object specified in the menu path as '%islandora_object'. * * Its up to the access callbacks and menu callbacks to trigger * drupal_access_denied() when appropriate. * * @param string $datastream_id * The DSID of the datastream specified as '%islandora_datastream' to fetch * from the given object in the menu path identified by '%islandora_object'. * * @param mixed $object_id * The object to load the datastream from. This can be a Fedora PID or * an instantiated IslandoraAbstractObject as it implements __toString() * returning the PID. * * @return FedoraDatastream * If the given datastream ID exists then this returns a FedoraDatastream * object, otherwise it returns NULL which triggers drupal_page_not_found(). */ function islandora_datastream_load($datastream_id, $object_id) { $object = is_object($object_id) ? $object_id : islandora_object_load($object_id); if (!$object) { return NULL; } return $object[$datastream_id]; } /** * Fetches the given datastream version from its datastream. * * Content model, collection view and collection policy datastreams may now * optionally define a version number in their top-level XML element as an * attribute, as in: * content); } elseif (!empty($datastream_file)) { $doc = simplexml_load_file($datastream_file); } if (!empty($doc) && $version = (int) $doc->attributes()->version) { $return = $version; } return $return; } /** * Implements hook_islandora_required_objects(). */ function islandora_islandora_required_objects(IslandoraTuque $connection) { $module_path = drupal_get_path('module', 'islandora'); // Root Collection. $root_collection = $connection->repository->constructObject('islandora:root'); $root_collection->owner = 'fedoraAdmin'; $root_collection->label = 'Top-level Collection'; $root_collection->models = 'islandora:collectionCModel'; // Collection Policy Datastream. $datastream = $root_collection->constructDatastream('COLLECTION_POLICY', 'X'); $datastream->label = 'Collection policy'; $datastream->mimetype = 'text/xml'; $datastream->setContentFromFile("$module_path/xml/islandora_collection_policy.xml", FALSE); $root_collection->ingestDatastream($datastream); // TN Datastream. $datastream = $root_collection->constructDatastream('TN', 'M'); $datastream->label = 'Thumbnail'; $datastream->mimetype = 'image/png'; $datastream->setContentFromFile("$module_path/images/folder.png", FALSE); $root_collection->ingestDatastream($datastream); return array( 'islandora' => array( 'title' => 'Islandora', 'objects' => array( $root_collection, ), ), ); } /** * Implements islandora_undeleteable_datastreams(). */ function islandora_islandora_undeletable_datastreams(array $models) { return array('DC'); } /** * Ingest the given object. * * @param AbstractObject $object * An ingestable FedoraObject. * * @return FedoraObject * The ingested FedoraObject. */ function islandora_add_object(AbstractObject &$object) { return $object->repository->ingestObject($object); } /** * Creates a new object with the same properties as the old. * * @todo Make Tuque objects support cloneing. * * @param AbstractObject $object * An existing or new Fedora Object. * * @return AbstractObject * The new Fedora Object with properties identical to the object given. This * returned object is not automatically ingested. */ function islandora_copy_object(AbstractObject $object) { $clone = $object->repository->constructObject($object->id); $object_properties = array( 'state', 'createdDate', 'lastModifiedDate', 'label', 'owner', 'logMessage', ); // Copy Properties. foreach ($object_properties as $property) { if (isset($object->$property)) { $clone->$property = $object->$property; } } // Copy Datastreams. foreach ($object as $dsid => $datastream) { if (empty($clone[$dsid])) { $clone->ingestDatastream($datastream); } else { // Get the content into a file, and add the file. $temp_file = drupal_tempnam('temporary://', 'datastream'); $datastream->getContent($temp_file); $clone[$dsid]->setContentFromFile($temp_file); drupal_unlink($temp_file); } } return $clone; } /** * Delete's or purges the given object. * * @param AbstractObject $object * An object to delete. * * @return bool * TRUE if successful, FALSE otherwise. */ function islandora_delete_object(AbstractObject &$object) { try { $object->repository->purgeObject($object->id); $object = NULL; return TRUE; } catch (Exception $e) { // Exception message gets logged in Tuque Wrapper. return FALSE; } } /** * Delete's or purges the given datastream. * * @throws Exception * Which types are undefined, but more than likely because of the hooks * there will be several kinds. * * @param AbstractDatastream $datastream * The datastream to delete. * * @return bool * TRUE if successful, FALSE otherwise. */ function islandora_delete_datastream(AbstractDatastream &$datastream) { $object = $datastream->parent; return $object->purgeDatastream($datastream->id); } /** * Implements hook_cron(). */ function islandora_cron() { module_load_include('inc', 'islandora', 'includes/authtokens'); islandora_remove_expired_tokens(); } /** * Implements hook_entity_info(). * * Some boiler-plate for Tokens (the module, not our authentication work- * around). */ function islandora_entity_info() { $entities = array(); $entities['islandora_object'] = array( 'label' => t('Islandora Object'), 'controller class' => 'IslandoraObjectEntityController', 'fieldable' => FALSE, 'entity keys' => array( 'id' => 'id', 'label' => 'label', ), ); return $entities; } /** * Implements hook_entity_property_info(). * * Details the tokens which will be available on the given object. */ function islandora_entity_property_info() { $info = array(); $p = &$info['islandora_object']['properties']; $p['id'] = array( 'type' => 'text', 'label' => t('ID'), 'description' => t('The identifier of the object.'), ); $p['label'] = array( 'type' => 'text', 'label' => t('Object Label'), 'description' => t('The label of the object.'), ); $p['owner'] = array( 'type' => 'text', 'label' => t('Object Owner'), 'description' => t('The name of the owner of the object.'), ); $p['state'] = array( 'type' => 'text', 'label' => t('Object State'), 'description' => t('An initial representing the state of the object.'), ); $p['models'] = array( 'type' => 'list', 'label' => t('Content Models'), 'description' => t('The list of content models which the object has.'), ); return $info; } /** * Renders the print page for the given object. * * Modules can either implement preprocess functions to append content onto the * 'content' variable, or override the display by providing a theme suggestion. * * @param AbstractObject $object * The object. * * @return array * A renderable array. */ function islandora_print_object(AbstractObject $object) { drupal_set_title($object->label); return theme('islandora_object_print', array('object' => $object)); } /** * Menu callback downloads the given clip. */ function islandora_download_clip(AbstractObject $object) { if (isset($_GET['clip'])) { $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on'; $http_protocol = $is_https ? 'https' : 'http'; $url = $http_protocol . '://' . $_SERVER['HTTP_HOST'] . $_GET['clip']; $filename = $object->label; header("Content-Disposition: attachment; filename=\"{$filename}.jpg\""); header("Content-type: image/jpeg"); header("Content-Transfer-Encoding: binary"); $ch = curl_init(); curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_URL, $url); $response = curl_exec($ch); curl_close($ch); } exit(); } /** * Implements hook_file_mimetype_mapping_alter(). * * Grab custom islandora mime type list * and add any missing ext/mimes to the drupal mapping */ function islandora_file_mimetype_mapping_alter(&$mapping) { $mime_detect = new MimeDetect(); $types = $mime_detect->getMimeTypes(); $diff = array_diff_key($types, $mapping['extensions']); foreach ($diff as $ext => $mime) { $mapping['mimetypes'][] = $mime; end($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]; } /** * Implements hook_islandora_basic_collection_get_query_filters(). */ function islandora_islandora_basic_collection_get_query_filters() { $enforced = variable_get('islandora_namespace_restriction_enforced', FALSE); if ($enforced) { $namespace_array = islandora_get_allowed_namespaces(); $namespace_sparql = implode('|', $namespace_array); return format_string('regex(str(?object), "info:fedora/(!namespaces):")', array( '!namespaces' => $namespace_sparql, )); } }