. */ require_once __DIR__ . "/includes/globals.inc"; // Common datastreams define('DS_COMP_STREAM', 'DS-COMPOSITE-MODEL'); // Permissions define('FEDORA_VIEW', 'view fedora repository'); 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_MODIFY_STATE', 'modify fedora state'); define('FEDORA_MANAGE', 'manage fedora items'); // Hooks define('ISLANDORA_VIEW_HOOK', 'islandora_view_object'); define('ISLANDORA_EDIT_HOOK', 'islandora_edit_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'); define('ISLANDORA_INGEST_STEP_HOOK', 'islandora_ingest_steps'); define('ISLANDORA_PRE_PURGE_DATASTREAM_HOOK', 'islandora_pre_purge_datastream'); define('ISLANDORA_POST_PURGE_DATASTREAM_HOOK', 'islandora_post_purge_datastream'); define('ISLANDORA_EDIT_DATASTREAM_HOOK', 'islandora_edit_datastream'); /** * 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' => 'admin/islandora.admin.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), ); $items['islandora/object/%islandora_object'] = array( 'title' => 'Repository', 'page callback' => 'islandora_view_object', 'page arguments' => array(2), 'type' => MENU_NORMAL_ITEM, 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_VIEW, 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_edit_object', 'page arguments' => array(2), 'type' => MENU_LOCAL_TASK, 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_MODIFY_STATE, 2), ); $items['islandora/object/%islandora_object/manage/datastreams'] = array( 'title' => 'Datastreams', 'type' => MENU_DEFAULT_LOCAL_TASK, '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_MODIFY_STATE, 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), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', 'access callback' => 'islandora_object_datastream_access_callback', 'access arguments' => array(FEDORA_VIEW, 2, 4), 'load arguments' => array('%map'), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastream/view'] = array( 'title' => 'View datastream', '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_object_datastream_access_callback', 'access arguments' => array(FEDORA_VIEW, 2, 4), 'load arguments' => array('%map'), ); $items['islandora/object/%islandora_object/datastream/%islandora_datastreams/edit'] = array( 'title' => 'Edit datastream', 'page callback' => 'islandora_edit_datastream', 'page arguments' => array(2, 4), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', 'access callback' => 'islandora_object_datastream_access_callback', 'access arguments' => array(FEDORA_METADATA_EDIT, 2, 4), 'load arguments' => array('%map'), ); $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_object_datastream_access_callback', 'access arguments' => array(FEDORA_PURGE, 2, 4), 'load arguments' => array('%map'), ); $items['islandora/ingest'] = array( 'title' => 'Add an Object', 'page callback' => 'islandora_ingest_callback', 'file' => 'includes/ingest.menu.inc', 'type' => MENU_SUGGESTED_ITEM, 'access arguments' => array(FEDORA_INGEST), ); 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; return $paths; } /** * Implements hook_theme(). */ function islandora_theme() { return array( // default object template 'islandora_default' => array( 'file' => 'theme/islandora.theme.inc', 'template' => 'theme/islandora-object', 'variables' => array('islandora_object' => NULL), ), // default edit page 'islandora_default_edit' => array( 'file' => 'theme/islandora.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', ), ); } /** * Implements hook_permission(). */ function islandora_permission() { return array( FEDORA_VIEW => array( 'title' => t('View repository objects and datastreams'), 'description' => t('View objects in the repository and their associated datastreams. 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_MODIFY_STATE => array( 'title' => t('Change repository object states'), 'description' => t('Change the state of objects in the repository (e.g. from Active to Inactive).') ), FEDORA_MANAGE => array( 'title' => t('View object management tabs'), 'description' => t('View tabs that provide object management functions.') ) ); } /** * 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 with the given permission. * * Checks for object existance, accessiblitly, namespace permissions, and user permissions * * @see islandora_object_load() To find potential solutions to enable page not found errors. * * @param string $perm * The user permission to test for. * @param FedoraObject $object * The object to test, if NULL given the object doesn't exist or is inaccessible. * * @return boolean * 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'); return user_access($perm) && is_object($object) && islandora_namespace_accessible($object->id); } /** * Checks whether the user can access the given object and datastream with the given permission. * * Checks for object existance, accessiblitly, namespace permissions, and user permissions * * @see islandora_object_load() To find potential solutions to enable page not found errors. * * @param string $perm * The user permission to test for. * @param FedoraObject $object * The object to test, if NULL given the object doesn't exist or is inaccessible. * @param FedoraDatastream $datastream * The datastream to test, if NULL given the datastream doesn't exist or is inaccessible. * * @return boolean * TRUE if the user is allowed to access this object, FALSE otherwise. */ function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL) { module_load_include('inc', 'islandora', 'includes/utilities'); return user_access($perm) && is_object($object) && islandora_namespace_accessible($object->id) && is_object($datastream); } /** * 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 FedoraObject $object * The object to manage. * * @return string * The HTML repersentation of the manage object page. */ function islandora_edit_object(FedoraObject $object) { module_load_include('inc', 'islandora', 'includes/utilities'); $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)) { $output = islandora_default_islandora_edit_object($object); // Add in the default, if we did not get any results. } arsort($output); drupal_alter(ISLANDORA_EDIT_HOOK, $object, $output); return implode('', $output); } /** * Renders the default manage object page for the given object. * * @param FedoraObject $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(FedoraObject $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 FedoraObject $object * The object to view. * * @return string * The html repersentation of this object. */ function islandora_view_object(FedoraObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); module_load_include('inc', 'islandora', 'includes/utilities'); 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(); foreach (islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $object->models) as $hook) { $temp = module_invoke_all($hook, $object, $page_number, $page_size); // @todo Remove page number and size from this hook, implementers of the hook should use drupal page handling directly. if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } } if (empty($output)) { $output = islandora_default_islandora_view_object($object); // No results, use the default view. } arsort($output); drupal_alter(ISLANDORA_VIEW_HOOK, $object, $output); return implode('', $output); } /** * Renders the default view object page for the given object. * * @param FedoraObject $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); } /** * A helper function to get a connection and return an object for objects specified in the menu path as '%islandora_object'. * * This should only be used by the Drupal menu wildcard system! * * When this function returns FALSE the Drupal menu system will issues a "page not found" error, when this function returns NULL, * the access function is expected to check for the given object and return false generating a "accesss denied" error. * * This will currently display a message if the repository is inaccessable, ideally this would redirect to another page in such a case, * as the access function will not be aware of this fact and will trigger the display of the "access denied" page. * * @todo When the repository down this should return a 500 error or a site offline notice. Currently only displays a message. * * @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) { static $object = NULL, $load_failed = FALSE; // Assume inaccessible. if ($load_failed || isset($object)) { return $object; } $object = islandora_get_object_by_id($object_id); // Either NULL or FALSE. if (!isset($object)) { module_load_include('inc', 'islandora', 'includes/utilities'); if (islandora_describe_repository() === FALSE) { drupal_set_message(t('The repository is not availible please contact the administrator.'), 'error'); } $load_failed = TRUE; } return $object; } /** * A helper function to get an datastream specified as '%islandora_datastream' for the object specified in the menu path as '%islandora_object'. * * This should only be used by the Drupal menu wildcard system! As for non existing datastreams this will return page not found. * * The following settings are required for any menu paths which intent to use this auto loader. * * @code * 'load arguments' => array('%map'), * @endcode * * @see islandora_object_load() for solutions to access/not found problems. * * @todo For non accessible datastreams to the user this should return access denied. * @todo Is there anything we can do to enhance caching? * * @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'. * * @return FedoraDatastream * If the given datastream id exists in the object then this returns a FedoraDatastream, in other cases this aborts. */ function islandora_datastream_load($datastream_id, $map) { static $datastream = NULL, $load_failed = FALSE; // @hack for bug in drupal_not_found() when used before the menu callback. Infinite recursion bug. if ($load_failed || isset($datastream)) { return $datastream; } foreach ($map as $element) { $is_fedora_object = is_object($element) && strtolower(get_class($element)) == 'fedoraobject'; // @todo Probably a better way to check types by now. if ($is_fedora_object && isset($element[$datastream_id])) { // @todo check for access denied to this datastream so we can show the access denied page instead. $datastream = $element[$datastream_id]; return $datastream; } } $load_failed = TRUE; return $datastream; // @todo Test } /** * 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() { // module path $module_path = drupal_get_path('module', 'islandora'); return array( 'islandora' => array( 'title' => 'Islandora', 'objects' => array( array( 'pid' => 'islandora:root', 'label' => 'Top-level collection', 'cmodel' => 'islandora:collectionCModel', 'datastreams' => array( array( 'dsid' => 'COLLECTION_POLICY', 'label' => 'Collection policy', 'mimetype' => 'text/xml', 'control_group' => 'X', 'datastream_file' => "$module_path/xml/islandora_collection_policy.xml", ), array( 'dsid' => 'TN', 'label' => 'Thumbnail', 'mimetype' => 'image/png', 'control_group' => 'M', 'datastream_file' => "$module_path/images/folder.png", ), ), ), ), ), ); } /** * Implements islandora_undeleteable_datastreams(). */ function islandora_islandora_undeletable_datastreams(array $models) { return array('DC'); }