diff --git a/.travis.yml b/.travis.yml index adedf7b1..17a22707 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,10 @@ php: - 5.4 branches: only: - - 7.x + - /^7.x/ env: - FEDORA_VERSION="3.5" + - FEDORA_VERSION="3.6.2" before_install: - export ISLANDORA_DIR=$TRAVIS_BUILD_DIR - $TRAVIS_BUILD_DIR/tests/scripts/travis_setup.sh diff --git a/css/islandora.print.css b/css/islandora.print.css new file mode 100644 index 00000000..45fca341 --- /dev/null +++ b/css/islandora.print.css @@ -0,0 +1,72 @@ +/** + * @file + * Print styling + * + * We provide some sane print styling for Drupal, hiding most visuals. + */ +a:link, +a:visited { /* underline all links */ + text-decoration: underline !important; +} + +#site-name a:link, +#site-name a:visited { /* Don't underline header */ + text-decoration: none !important; +} + +#content a[href^="javascript:"]:after, +#content a[href^="#"]:after { /* Only display useful links. */ +/* content: ""; */ +} + +#content abbr[title]:after { /* Add visible title after abbreviations. */ +/* content: " (" attr(title) ")"; */ +} + +#content { + left: 0 !important; + width: 100% !important; +} +uncomment when ready to test printing +#header { + display: none !important; +} + +#content { /* Un-float the content */ + float: none !important; + width: 100% !important; + margin: 0 !important; + padding: 0 !important; +} + +body, +#page, +#main, +#content { /* Turn off any background colors or images */ + color: #000; + background-color: transparent !important; + background-image: none !important; +} + +body.sidebar-first { + left: 0 !important; + width: 100% !important; +} +#skip-link, +#toolbar, +#navigation, +/* .region-sidebar-first, */ +/* .region-sidebar-second, */ +#header, +#footer, +.breadcrumb, +.tabs, +.action-links, +.links, +.book-navigation, +.forum-topic-navigation, +.pager, +.feed-icons { /* Hide sidebars and nav elements */ + visibility: hidden !important; + display: none !important; +} diff --git a/images/print-icon.png b/images/print-icon.png new file mode 100644 index 00000000..5f5a3b3c Binary files /dev/null and b/images/print-icon.png differ diff --git a/includes/add_datastream.form.inc b/includes/add_datastream.form.inc index 62490c9a..3a1d964d 100644 --- a/includes/add_datastream.form.inc +++ b/includes/add_datastream.form.inc @@ -32,7 +32,7 @@ function islandora_add_datastream_form(array $form, array &$form_state, Abstract '#attributes' => array( 'enctype' => 'multipart/form-data', ), - 'dsid' => array( + 'dsid_fieldset' => array( '#type' => 'fieldset', '#title' => 'Add a datastream', '#collapsible' => FALSE, @@ -40,44 +40,44 @@ function islandora_add_datastream_form(array $form, array &$form_state, Abstract 'dsid' => array( '#title' => 'Datastream ID', '#description' => t("An ID for this stream that is unique to this object. Must start with a letter and contain only alphanumeric characters, dashes and underscores. The following datastreams are defined by this content model but don't currently exist: @unused_dsids.", array('@unused_dsids' => $unused_datastreams)), + '#type' => 'textfield', + '#size' => 64, + '#maxlength' => 64, + '#required' => TRUE, + '#element_validate' => array( + 'islandora_add_datastream_form_field_is_not_an_existing_datastream_id', + 'islandora_add_datastream_form_field_starts_with_a_letter', + 'islandora_add_datastream_form_field_is_valid_dsid', + ), + '#autocomplete_path' => "islandora/object/{$object->id}/manage/datastreams/add/autocomplete", ), - '#type' => 'textfield', - '#size' => 64, - '#maxlength' => 64, - '#required' => TRUE, - '#element_validate' => array( - 'islandora_add_datastream_form_field_is_not_an_existing_datastream_id', - 'islandora_add_datastream_form_field_starts_with_a_letter', - 'islandora_add_datastream_form_field_is_valid_dsid', + 'label' => array( + '#title' => 'Datastream Label', + '#required' => TRUE, + '#size' => 64, + '#maxlength' => 64, + '#description' => t('A human-readable label'), + '#type' => 'textfield', + '#element_validate' => array('islandora_add_datastream_form_field_does_not_contain_a_forward_slash'), ), - '#autocomplete_path' => "islandora/object/{$object->id}/manage/datastreams/add/autocomplete", - ), - 'label' => array( - '#title' => 'Datastream Label', - '#required' => TRUE, - '#size' => 64, - '#maxlength' => 64, - '#description' => t('A human-readable label'), - '#type' => 'textfield', - '#element_validate' => array('islandora_add_datastream_form_field_does_not_contain_a_forward_slash'), - ), - 'file' => array( - '#type' => 'managed_file', - '#required' => TRUE, - '#title' => t('Upload Document'), - '#size' => 48, - '#description' => t('Select a file to upload.
Files must be less than @size MB.', array('@size' => $upload_size)), - '#default_value' => isset($form_state['values']['files']) ? $form_state['values']['files'] : NULL, - '#upload_location' => 'temporary://', - '#upload_validators' => array( - 'file_validate_extensions' => array(NULL), - // Assume its specified in MB. - 'file_validate_size' => array($upload_size * 1024 * 1024), + 'file' => array( + '#type' => 'managed_file', + '#required' => TRUE, + '#title' => t('Upload Document'), + '#size' => 48, + '#description' => t('Select a file to upload.
Files must be less than @size MB.', array('@size' => $upload_size)), + '#default_value' => isset($form_state['values']['files']) ? $form_state['values']['files'] : NULL, + '#upload_location' => 'temporary://', + '#upload_validators' => array( + 'file_validate_extensions' => array(NULL), + // Assume its specified in MB. + 'file_validate_size' => array($upload_size * 1024 * 1024), + ), + ), + 'submit' => array( + '#type' => 'submit', + '#value' => t('Add Datastream'), ), - ), - 'submit' => array( - '#type' => 'submit', - '#value' => t('Add Datastream'), ), ); } @@ -148,7 +148,7 @@ function islandora_add_datastream_form_field_does_not_contain_a_forward_slash(ar } /** - * Checks if the given datastream requires the upload to be a certian MIME type. + * Checks if the given datastream requires the upload to be a certain MIME type. * * @param array $form * The Drupal form. diff --git a/includes/datastream.inc b/includes/datastream.inc index dc01bdfe..da55dcd5 100644 --- a/includes/datastream.inc +++ b/includes/datastream.inc @@ -26,8 +26,19 @@ function islandora_download_datastream(AbstractDatastream $datastream) { * @param bool $download * If TRUE the file is download to the user computer for viewing otherwise it * will attempt to display in the browser natively. + * @param int $version + * The version of the datastream to display */ -function islandora_view_datastream(AbstractDatastream $datastream, $download = FALSE) { +function islandora_view_datastream(AbstractDatastream $datastream, $download = FALSE, $version = NULL) { + if ($version !== NULL) { + if (isset($datastream[$version])) { + $datastream = $datastream[$version]; + } + else { + return drupal_not_found(); + } + } + header_remove('Cache-Control'); header_remove('Expires'); header('Content-type: ' . $datastream->mimetype); @@ -69,12 +80,31 @@ function islandora_datastream_get_human_readable_size(AbstractDatastream $datast * * @param AbstractDatastream $datastream * The datastream to generated the url to. + * @param string $type + * One of: + * - download + * - view + * @param int $version + * (Optional) The version of the datastream to get a URL for. * * @return string * either the 'view' or 'download' url for the given datastream. */ -function islandora_datastream_get_url(AbstractDatastream $datastream, $type = 'download') { - return $datastream->controlGroup == 'R' ? $datastream->url : "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/$type"; +function islandora_datastream_get_url(AbstractDatastream $datastream, $type = 'download', $version = NULL) { + if ($version === NULL) { + $link = "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/$type"; + } + else { + $link = "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/version/$version/$type"; + $datastream = $datastream[$version]; + } + + if ($datastream->controlGroup == 'R') { + return $datastream->url; + } + else { + return $link; + } } /** @@ -82,6 +112,9 @@ function islandora_datastream_get_url(AbstractDatastream $datastream, $type = 'd * * @param AbstractDatastream $datastream * The datastream to generated the url to. + * + * @return string + * Markup containing the link to the confirm form to delete the datastream. */ function islandora_datastream_get_delete_link(AbstractDatastream $datastream) { $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_delete_link" theme implementation.'); @@ -97,6 +130,9 @@ function islandora_datastream_get_delete_link(AbstractDatastream $datastream) { * * @param AbstractDatastream $datastream * The datastream to generated the url to. + * + * @return string + * Markup containing the link to edit the datastream. */ function islandora_datastream_edit_get_link(AbstractDatastream $datastream) { $message = islandora_deprecated('7.x-1.2', 'Use the "islandora_datastream_edit_link" theme implementation.'); @@ -139,6 +175,9 @@ function islandora_edit_datastream(AbstractDatastream $datastream) { * * @param array $edit_registry * A list of 'islandora_edit_datastream_registry' values. + * + * @return array + * A Drupal renderable array containing the "edit" markup. */ function islandora_edit_datastream_registry_render(array $edit_registry) { $markup = ''; diff --git a/includes/datastream.version.inc b/includes/datastream.version.inc new file mode 100644 index 00000000..1e7c0830 --- /dev/null +++ b/includes/datastream.version.inc @@ -0,0 +1,127 @@ + $datastream->id))); + + $header = array(); + $header[] = array('data' => t('Created Date')); + $header[] = array('data' => t('Size')); + $header[] = array('data' => t('Label')); + $header[] = array('data' => t('Mime type')); + $header[] = array('data' => t('Operations')); + $rows = array(); + + foreach ($datastream as $version => $datastream_version) { + $row = array(); + $row[] = array( + 'class' => 'datastream-date', + 'data' => theme('islandora_datastream_view_link', array( + 'datastream' => $datastream, + 'label' => $datastream_version->createdDate->format(DATE_RFC850), + 'version' => $version, + )), + ); + $row[] = array( + 'class' => 'datastream-size', + 'data' => islandora_datastream_get_human_readable_size($datastream_version), + ); + $row[] = array( + 'class' => 'datastream-label', + 'data' => $datastream_version->label, + ); + $row[] = array( + 'class' => 'datastream-mime', + 'data' => $datastream_version->mimeType, + ); + $row[] = array( + 'class' => 'datastream-delete', + 'data' => theme('islandora_datastream_delete_link', array( + 'datastream' => $datastream, + 'version' => $version, + )), + ); + $rows[] = $row; + } + + return theme('table', array('header' => $header, 'rows' => $rows)); +} + +/** + * The admin delete datastream form. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + * @param AbstractDatastream $datastream + * The datastream to be deleted. + * @param string $version + * The version number of the datastream we are trying to delete. + * + * @return array + * The drupal form definition. + */ +function islandora_delete_datastream_version_form(array $form, array &$form_state, AbstractDatastream $datastream, $version) { + if (!isset($datastream[$version]) || count($datastream) < 2) { + return drupal_not_found(); + } + + $form_state['datastream'] = $datastream; + $form_state['version'] = $version; + return confirm_form($form, + t('Are you sure you want to delete version @version of the @dsid datastream?', array('@dsid' => $datastream->id, '@version' => $version)), + "islandora/object/{$datastream->parent->id}", + t('This action cannot be undone.'), + t('Delete'), + t('Cancel') + ); +} + +/** + * Submit handler for the delete datastream form. + * + * Purges/Delete's the given AbstractDatastream if possible. + * + * The ISLANDORA_PRE_PURGE_DATASTREAM_HOOK will query other modules as to + * whether the given FedoraDatastream + * should be: blocked from purging; state set to 'Deleted'; or purged. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_delete_datastream_version_form_submit(array $form, array &$form_state) { + $datastream = $form_state['datastream']; + $version = $form_state['version']; + + $datastream_id = $datastream->id; + $object = $datastream->parent; + + try { + unset($datastream[$version]); + } + catch (Exception $e) { + drupal_set_message(t('Error deleting version %v of %s datastream from object %o %e', array( + '%v' => $version, + '%s' => $datastream_id, + '%o' => $object->label, + '%e' => $e->getMessage())), 'error'); + } + + drupal_set_message(t('%d datastream version successfully deleted from Islandora object %o', array( + '%d' => $datastream_id, + '%o' => $object->label))); + + $form_state['redirect'] = "islandora/object/{$object->id}/datastream/{$datastream->id}/version"; +} diff --git a/includes/dublin_core.inc b/includes/dublin_core.inc index 14d25392..ec058181 100644 --- a/includes/dublin_core.inc +++ b/includes/dublin_core.inc @@ -133,6 +133,7 @@ class DublinCore { $dc_array[$field]['label'] = $element_label; $dc_array[$field]['value'] = $value; $dc_array[$field]['class'] = drupal_strtolower(preg_replace('/[^A-Za-z0-9]/', '-', $field)); + $dc_array[$field]['dcterms'] = preg_replace('/^dc/', 'dcterms', $field); } } } diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 00783934..7edd0f60 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -186,10 +186,10 @@ function islandora_ingest_form_get_step(array &$form_state, $step_id = NULL) { * * @param array $form_state * The Drupal form state. - * @param string $step + * @param array $step * The step relative to the result, if not provided the current step is used. * - * @return string + * @return array|null * The next step if found, NULL otherwise. */ function islandora_ingest_form_get_next_step(array &$form_state, array $step = NULL) { @@ -205,10 +205,10 @@ function islandora_ingest_form_get_next_step(array &$form_state, array $step = N * * @param array $form_state * The Drupal form state. - * @param string $step + * @param array $step * The step relative to the result, if not provided the current step is used. * - * @return string + * @return array|null * The next step if found, NULL otherwise. */ function islandora_ingest_form_get_previous_step(array &$form_state, array $step = NULL) { @@ -329,6 +329,9 @@ function islandora_ingest_form_decrement_step(array &$form_state) { * The Drupal form. * @param array $form_state * The Drupal form state. + * @param string $step_id + * The ID of the step relative to the result, if not provided the current + * step_id is used. * * @return array * The form definition of the current step. @@ -363,6 +366,8 @@ function islandora_ingest_form_execute_step(array $form, array &$form_state, $st * The Drupal form. * @param array $form_state * The Drupal form state. + * @param array $step + * The step we are executing. * * @return array * The form definition of the given step. @@ -391,6 +396,8 @@ function islandora_ingest_form_execute_form_step(array $form, array &$form_state * The Drupal form. * @param array $form_state * The Drupal form state. + * @param array $step + * The step that execution begins from. */ function islandora_ingest_form_execute_consecutive_callback_steps(array $form, array &$form_state, array $step) { do { @@ -409,6 +416,8 @@ function islandora_ingest_form_execute_consecutive_callback_steps(array $form, a * The Drupal form. * @param array $form_state * The Drupal form state. + * @param array $step + * The step currently being executed. */ function islandora_ingest_form_execute_callback_step(array $form, array &$form_state, array $step) { $args = array(&$form_state); @@ -425,6 +434,8 @@ function islandora_ingest_form_execute_callback_step(array $form, array &$form_s * The Drupal form. * @param array $form_state * The Drupal form state. + * @param array $step + * The step that execution begins from. */ function islandora_ingest_form_undo_consecutive_callback_steps(array $form, array &$form_state, array $step) { do { @@ -443,6 +454,8 @@ function islandora_ingest_form_undo_consecutive_callback_steps(array $form, arra * The Drupal form. * @param array $form_state * The Drupal form state. + * @param array $step + * The step which the undo callback is being called on. */ function islandora_ingest_form_undo_callback_step(array $form, array &$form_state, array $step) { $args = array(&$form_state); @@ -457,11 +470,13 @@ function islandora_ingest_form_undo_callback_step(array $form, array &$form_stat * The Drupal form. * @param array $form_state * The Drupal form state. + * @param array $step + * An array defining a ingest step. * * @return array * The stepified Drupal form definition for the given step. */ -function islandora_ingest_form_stepify(array $form, array &$form_state, $step) { +function islandora_ingest_form_stepify(array $form, array &$form_state, array $step) { $first_form_step = islandora_ingest_form_on_first_form_step($form_state); $last_form_step = islandora_ingest_form_on_last_form_step($form_state); $form['form_step_id'] = array( @@ -692,6 +707,8 @@ function islandora_ingest_form_ingest_button(array &$form_state) { * * Attempts to ingest every object built by the previous steps. * + * @param array $form + * The Drupal form. * @param array $form_state * The Drupal form state. */ @@ -703,7 +720,7 @@ function islandora_ingest_form_submit(array $form, array &$form_state) { islandora_ingest_form_execute_consecutive_callback_steps($form, $form_state, $step); } // Ingest the objects. - foreach ($form_state['islandora']['objects'] as $object) { + foreach ($form_state['islandora']['objects'] as &$object) { try { islandora_add_object($object); $form_state['redirect'] = "islandora/object/{$object->id}"; @@ -715,6 +732,9 @@ function islandora_ingest_form_submit(array $form, array &$form_state) { drupal_set_message(t('A problem occured while ingesting "@label" (ID: @pid), please notifiy the administrator.', array('@label' => $object->label, '@pid' => $object->id)), 'error'); } } + // XXX: Foreaching with references can be weird... The reference exists in + // the scope outside. + unset($object); } /** diff --git a/includes/object.entity_controller.inc b/includes/object.entity_controller.inc index d3fd6986..9464d7b5 100644 --- a/includes/object.entity_controller.inc +++ b/includes/object.entity_controller.inc @@ -24,6 +24,9 @@ class IslandoraObjectEntityController implements DrupalEntityControllerInterface * The ID's of the entities. * @param array $conditions * The conditions to apply. + * + * @return array + * An array of loaded objects. */ public function load($ids = array(), $conditions = array()) { if (!empty($conditions)) { diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index 26bd77b5..a80c41a5 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -5,11 +5,55 @@ * Admin and callback functions for solution pack management. */ +/** + * Get the information about required object. + * + * @param string $module + * An optional string, identifying a module for which to get the required + * object information. + * + * @return array + * An associative array of info describing the required objects. If $module + * is not provided (or is NULL), then we provide the info for all modules. If + * $module is provided and we have info for the given module, only the info + * for that module is provided. If $module is provided and we have no info + * for the given module, we throw an exception. + */ +function islandora_solution_packs_get_required_objects($module = NULL) { + // Should make this statically cache, after figuring out how exactly it + // should be called... We occasionally load a module and attempt to install + // it's object right away (in the same request)... This would require + // resetting of the cache. Let's just not cache for now... + $required_objects = array(); + + if (!$required_objects) { + $connection = islandora_get_tuque_connection(); + $required_objects = module_invoke_all('islandora_required_objects', $connection); + } + + if ($module !== NULL) { + if (isset($required_objects[$module])) { + return $required_objects[$module]; + } + else { + watchdog('islandora', 'Attempted to get required objects for %module... %module does not appear to have any required objects. Clear caches?', array( + '%module' => $module, + )); + throw new Exception(t('Module "@module" has no required objects!', array( + '@module' => $module, + ))); + } + } + else { + return $required_objects; + } +} + /** * Solution pack admin page callback. * - * @return string - * The html repersentation of all solution pack forms for required objects. + * @return array + * Renderable array of all solution pack forms for required objects. */ function islandora_solution_packs_admin() { module_load_include('inc', 'islandora', 'includes/utilities'); @@ -18,17 +62,15 @@ function islandora_solution_packs_admin() { return ''; } - $connection = islandora_get_tuque_connection(); drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css'); - $output = ''; - $enabled_solution_packs = module_invoke_all('islandora_required_objects', $connection); + $output = array(); + $enabled_solution_packs = islandora_solution_packs_get_required_objects(); foreach ($enabled_solution_packs as $solution_pack_module => $solution_pack_info) { // @todo We should probably get the title of the solution pack from the // systems table for consistency in the interface. $solution_pack_name = $solution_pack_info['title']; $objects = array_filter($solution_pack_info['objects']); - $form = drupal_get_form('islandora_solution_pack_form_' . $solution_pack_module, $solution_pack_module, $solution_pack_name, $objects); - $output .= drupal_render($form); + $output[$solution_pack_module] = drupal_get_form('islandora_solution_pack_form_' . $solution_pack_module, $solution_pack_module, $solution_pack_name, $objects); } return $output; } @@ -131,7 +173,7 @@ function islandora_solution_pack_form(array $form, array &$form_state, $solution '#markup' => t('Object status: !image !status', array( '!image' => $solution_pack_status_info['image'], '!status' => $solution_pack_status_info['solution_pack'], - )), + )), '#prefix' => '
', '#suffix' => '
', ), @@ -161,20 +203,38 @@ function islandora_solution_pack_form(array $form, array &$form_state, $solution */ function islandora_solution_pack_form_submit(array $form, array &$form_state) { $solution_pack_module = $form_state['values']['solution_pack_module']; - $objects = $form_state['values']['objects']; + + $batch = islandora_solution_pack_get_batch($solution_pack_module); + batch_set($batch); + // Hook to let solution pack objects be modified. + // Not using module_invoke so solution packs can be expanded by other modules. + // @todo shouldn't we send the object list along as well? + module_invoke_all('islandora_postprocess_solution_pack', $solution_pack_module); +} + +/** + * Get the batch definition to reinstall all the objects for a given module. + * + * @param string $module + * The name of the modules of which to grab the required objects for to setup + * the batch. + * + * @return array + * An array defining a batch which can be passed on to batch_set(). + */ +function islandora_solution_pack_get_batch($module) { $batch = array( 'title' => t('Installing / Updating solution pack objects'), 'file' => drupal_get_path('module', 'islandora') . '/includes/solution_packs.inc', 'operations' => array(), ); - foreach ($objects as $object) { + + $info = islandora_solution_packs_get_required_objects($module); + foreach ($info['objects'] as $object) { $batch['operations'][] = array('islandora_solution_pack_batch_operation_reingest_object', array($object)); } - batch_set($batch); - // Hook to let solution pack objects be modified. - // Not using module_invoke so solution packs can be expanded by other modules. - // @todo shouldn't we send the object list along as well? - module_invoke_all('islandora_postprocess_solution_pack', $solution_pack_module); + + return $batch; } /** @@ -245,14 +305,16 @@ function islandora_solution_pack_batch_operation_reingest_object(AbstractObject * install/unistall hooks. * @param string $op * The operation to perform, either install or uninstall. + * @param bool $force + * Force the (un)installation of object. * * @todo Implement hook_modules_installed/hook_modules_uninstalled instead of * calling this function directly. * @todo Remove the second parameter and have two seperate functions. */ -function islandora_install_solution_pack($module, $op = 'install') { +function islandora_install_solution_pack($module, $op = 'install', $force = FALSE) { if ($op == 'uninstall') { - islandora_uninstall_solution_pack($module); + islandora_uninstall_solution_pack($module, $force); return; } @@ -267,9 +329,9 @@ function islandora_install_solution_pack($module, $op = 'install') { '!admin_link' => $admin_link, ); - module_load_include('module', 'islandora', 'islandora'); + drupal_load('module', 'islandora'); module_load_include('inc', 'islandora', 'includes/utilities'); - module_load_include('module', $module, $module); + drupal_load('module', $module); $info_file = drupal_get_path('module', $module) . "/{$module}.info"; $info_array = drupal_parse_info_file($info_file); $module_name = $info_array['name']; @@ -279,8 +341,8 @@ function islandora_install_solution_pack($module, $op = 'install') { return; } $connection = islandora_get_tuque_connection(); - $required_objects = module_invoke($module, 'islandora_required_objects', $connection); - $objects = $required_objects[$module]['objects']; + $required_objects = islandora_solution_packs_get_required_objects($module); + $objects = $required_objects['objects']; $status_messages = array( 'up_to_date' => $t('The object already exists and is up-to-date.', $t_params), 'missing_datastream' => $t('The object already exists but is missing a datastream. Please reinstall the object on the !admin_link page.', $t_params), @@ -288,26 +350,41 @@ function islandora_install_solution_pack($module, $op = 'install') { 'modified_datastream' => $t('The object already exists but datastreams are modified. Please reinstall the object on the !admin_link page.', $t_params), ); foreach ($objects as $object) { - $query = $connection->api->a->findObjects('query', 'pid=' . $object->id); - $already_exists = !empty($query['results']); + $already_exists = islandora_object_load($object->id); + $label = $object->label; $object_link = l($label, "islandora/object/{$object->id}"); + $deleted = FALSE; if ($already_exists) { - $object_status = islandora_check_object_status($object); - $here_params = array( - '!summary' => $t("@module: Did not install !object_link.", array( - '!object_link' => $object_link, - ) + $t_params), - '!description' => $status_messages[$object_status['status']], - ); - drupal_set_message(filter_xss(format_string('!summary !description', $here_params)), 'warning'); + if (!$force) { + $object_status = islandora_check_object_status($object); + $here_params = array( + '!summary' => $t("@module: Did not install !object_link.", array( + '!object_link' => $object_link, + ) + $t_params), + '!description' => $status_messages[$object_status['status']], + ); + drupal_set_message(filter_xss(format_string('!summary !description', $here_params)), 'warning'); + continue; + } + else { + $deleted = islandora_delete_object($already_exists); + } } - else { + + if ($already_exists && $deleted || !$already_exists) { $object = islandora_add_object($object); if ($object) { - drupal_set_message(filter_xss($t('@module: Successfully installed. !object_link.', array( - '!object_link' => $object_link, - ) + $t_params)), 'status'); + if ($deleted) { + drupal_set_message(filter_xss($t('@module: Successfully reinstalled. !object_link.', array( + '!object_link' => $object_link, + ) + $t_params)), 'status'); + } + else { + drupal_set_message(filter_xss($t('@module: Successfully installed. !object_link.', array( + '!object_link' => $object_link, + ) + $t_params)), 'status'); + } } else { drupal_set_message($t('@module: Failed to install. @label.', array( @@ -315,6 +392,11 @@ function islandora_install_solution_pack($module, $op = 'install') { ) + $t_params), 'warning'); } } + else { + drupal_set_message($t('@module: "@label" already exists and failed to be deleted.', array( + '@label' => $label, + ) + $t_params), 'warning'); + } } } @@ -323,15 +405,17 @@ function islandora_install_solution_pack($module, $op = 'install') { * * @param string $module * The solution pack to uninstall. + * @param bool $force + * Force the objects to be removed. * * @todo Implement hook_modules_uninstalled instead of calling this function * directly for each solution pack. */ -function islandora_uninstall_solution_pack($module) { +function islandora_uninstall_solution_pack($module, $force = FALSE) { $t = get_t(); - module_load_include('module', 'islandora', 'islandora'); + drupal_load('module', 'islandora'); module_load_include('inc', 'islandora', 'includes/utilities'); - module_load_include('module', $module, $module); + drupal_load('module', $module); $config_link = l($t('Islandora configuration'), 'admin/islandora/configure'); $info_file = drupal_get_path('module', $module) . "/{$module}.info"; $info_array = drupal_parse_info_file($info_file); @@ -345,22 +429,35 @@ function islandora_uninstall_solution_pack($module) { return; } $connection = islandora_get_tuque_connection(); - $required_objects = module_invoke($module, 'islandora_required_objects', $connection); - $objects = $required_objects[$module]['objects']; + $required_objects = islandora_solution_packs_get_required_objects($module); + $objects = $required_objects['objects']; $filter = function($o) use($connection) { $param = "pid={$o->id}"; $query = $connection->api->a->findObjects('query', $param); return !empty($query['results']); }; $existing_objects = array_filter($objects, $filter); - foreach ($existing_objects as $object) { - $object_link = l($object->label, "islandora/object/{$object->id}"); - $msg = $t('@module: Did not remove !object_link. It may be used by other sites.', array( - '!object_link' => $object_link, - '@module' => $module_name, - )); - drupal_set_message(filter_xss($msg), 'warning'); + if (!$force) { + foreach ($existing_objects as $object) { + $object_link = l($object->label, "islandora/object/{$object->id}"); + $msg = $t('@module: Did not remove !object_link. It may be used by other sites.', array( + '!object_link' => $object_link, + '@module' => $module_name, + )); + + drupal_set_message(filter_xss($msg), 'warning'); + } + } + else { + foreach ($existing_objects as $object) { + $params = array( + '@id' => $object->id, + '@module' => $module_name, + ); + islandora_delete_object($object); + drupal_set_message($t('@module: Deleted @id.', $params)); + } } } @@ -430,13 +527,21 @@ function islandora_check_object_status(AbstractObject $object_definition) { // be equal as Fedora does some XML mangling. In order for C14N to work // we need to replace the info:fedora namespace, as C14N hates it. // C14N also doesn't normalize whitespace at the end of lines and Fedora - // may add some whitespace on some lines. + // will sometimes replace new-lines with white-space. So first we strip + // leading/tailing white-space and replace all new-lines within the xml + // document to account for Fedora's weird formatting. + $xsl = new DOMDocument(); + $xsl->load(drupal_get_path('module', 'islandora') . '/xml/strip_newlines_and_whitespace.xsl'); + $xslt = new XSLTProcessor(); + $xslt->importStyleSheet($xsl); $object_definition_dom = new DOMDocument(); $object_definition_dom->preserveWhiteSpace = FALSE; $object_definition_dom->loadXML(str_replace('info:', 'http://', $ds->content)); + $object_definition_dom = $xslt->transformToDoc($object_definition_dom); $object_actual_dom = new DOMDocument(); $object_actual_dom->preserveWhiteSpace = FALSE; $object_actual_dom->loadXML(str_replace('info:', 'http://', $existing_object[$ds->id]->content)); + $object_actual_dom = $xslt->transformToDoc($object_actual_dom); // Fedora changes the xml structure so we need to cannonize it. if ($object_actual_dom->C14N() != $object_definition_dom->C14N()) { @@ -615,7 +720,7 @@ function theme_islandora_viewers_table($variables) { 'header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'islandora-viewers-table'), - )); + )); $output .= drupal_render_children($form); return $output; } diff --git a/includes/tuque_wrapper.inc b/includes/tuque_wrapper.inc index 8563070f..96f9919c 100644 --- a/includes/tuque_wrapper.inc +++ b/includes/tuque_wrapper.inc @@ -82,13 +82,26 @@ class IslandoraFedoraRepository extends FedoraRepository { * @see FedoraRepository::ingestObject() */ public function ingestObject(NewFedoraObject &$object) { - $context = array( - 'action' => 'ingest', - 'block' => FALSE, - ); - islandora_alter_object($object, $context); try { - if ($context['block']) { + foreach ($object as $dsid => $datastream) { + $datastream_context = array( + 'action' => 'ingest', + 'block' => FALSE, + ); + islandora_alter_datastream($object, $datastream, $datastream_context); + if ($datastream_context['block']) { + throw new Exception(t('Object ingest blocked due to ingest of @dsid being blocked.', array( + '@dsid' => $dsid, + ))); + } + } + + $object_context = array( + 'action' => 'ingest', + 'block' => FALSE, + ); + islandora_alter_object($object, $object_context); + if ($object_context['block']) { throw new Exception('Ingest Object was blocked.'); } $ret = parent::ingestObject($object); @@ -194,6 +207,9 @@ class IslandoraFedoraApiM extends FedoraApiM { 'params' => $params, ); islandora_alter_datastream($object, $datastream, $context); + if (isset($params['lastModifiedDate'])) { + $params['lastModifiedDate'] = (string) $object[$dsid]->createdDate; + } try { if ($context['block']) { throw new Exception('Modify Datastream was blocked.'); @@ -269,7 +285,6 @@ class IslandoraFedoraApiM extends FedoraApiM { switch ($action) { case 'block': throw new Exception('Purge Datastream was blocked.'); - break; case 'delete': $object[$dsid]->state = 'D'; @@ -313,7 +328,6 @@ class IslandoraFedoraApiM extends FedoraApiM { switch ($action) { case 'block': throw new Exception('Purge object was blocked.'); - break; case 'delete': $object->state = 'D'; diff --git a/includes/utilities.inc b/includes/utilities.inc index 66c03d26..c8d1ae5e 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -14,6 +14,8 @@ * * @param int $bytes * Size in bytes to convert + * @param int $precision + * The amount of decimal precision to show. * * @return string * Human readable size. @@ -865,3 +867,48 @@ function islandora_deprecated($release, $solution = NULL) { } return $message; } + +/** + * Transform recursively-merged array of strings to renderable arrays. + * + * Renderable arrays are passed-through as-is. + * + * Previously, functions/hooks like islandora_view_object would return an + * associative array with string values containing markup. These values were + * then imploded into one large piece of markup. Here, we transform this older + * structure which was generated into a renderable array, because renderable + * arrays are awesome! + * + * @param array $markup_array + * An associative array of which the values are either a string or an array + * of strings, which we transform to renderable markup elements (by + * reference). + */ +function islandora_as_renderable_array(&$markup_array) { + foreach ($markup_array as &$value) { + if (!is_array($value)) { + // Not a renderable array, just a string. Let's convert it to a + // renderable '#markup' element. + $value = array( + '#markup' => $value, + ); + } + elseif (!isset($value['#type']) && !isset($value['#markup'])) { + // A simple array--possibly the result of a recursive merge? Let's + // look at each, to possibly convert them to a renderable '#markup' + // elements. + foreach ($value as &$inner) { + if (!is_array($inner)) { + // If it is an array at this level, we can assume that it is a + // renderable array. If it is not an array, convert to a renderable + // '#markup' element. + $inner = array( + '#markup' => $inner, + ); + } + } + unset($inner); + } + } + unset($value); +} diff --git a/islandora.api.php b/islandora.api.php index 129787f4..4d54a00f 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -21,8 +21,30 @@ * An array whose values are markup. */ function hook_islandora_view_object($object, $user, $page_number, $page_size) { -} + $output = array(); + if (in_array('islandora:sp_basic_image', $object->models)) { + $resource_url = url("islandora/object/{$object->id}/datastream/OBJ/view"); + $params = array( + 'title' => $object->label, + 'path' => $resource_url, + ); + + // Theme the image seperatly. + $variables['islandora_img'] = theme('image', $params); + $output = theme('islandora_default_print', array( + 'islandora_content' => $variables['islandora_img'])); + } + return $output; +} +/** + * Generate a print friendly page for the given object. + * + * @param object $object + * The object form to print. + */ +function hook_islandora_view_print_object($object) { +} /** * Generate an object's display for the given content model. * diff --git a/islandora.drush.inc b/islandora.drush.inc new file mode 100644 index 00000000..b2e75c47 --- /dev/null +++ b/islandora.drush.inc @@ -0,0 +1,142 @@ + dt('Install Solution Pack objects.'), + 'options' => array( + 'module' => array( + 'description' => dt('The module for which to install the required objects.'), + 'required' => TRUE, + ), + 'force' => array( + 'description' => dt('Force reinstallation of the objects.'), + ), + ), + 'aliases' => array('ispiro'), + 'drupal dependencies' => array( + 'islandora', + ), + 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN, + ); + $commands['islandora-solution-pack-uninstall-required-objects'] = array( + 'description' => dt('Uninstall Solution Pack objects.'), + 'options' => array( + 'module' => array( + 'description' => dt('The module for which to uninstall the required objects.'), + 'required' => TRUE, + ), + 'force' => array( + 'description' => dt('Force reinstallation of the objects.'), + ), + ), + 'aliases' => array('ispuro'), + 'drupal dependencies' => array( + 'islandora', + ), + 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN, + ); + $commands['islandora-solution-pack-required-objects-status'] = array( + 'description' => dt('Get Solution Pack object status.'), + 'options' => array( + 'module' => array( + 'description' => dt('The module for which to get the status of the required objects.'), + ), + ), + 'aliases' => array('ispros'), + 'drupal dependencies' => array( + 'islandora', + ), + 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN, + ); + + return $commands; +} + +/** + * Command callback to install required objects. + */ +function drush_islandora_solution_pack_install_required_objects() { + module_load_include('inc', 'islandora', 'includes/solution_packs'); + + $module = drush_get_option('module'); + if (module_exists($module)) { + islandora_install_solution_pack( + $module, + 'install', + drush_get_option('force', FALSE) + ); + } + else { + drush_log(dt('"@module" is not installed/enabled?...', array( + '@module' => $module, + ))); + } +} + +/** + * Command callback to uninstall required objects. + */ +function drush_islandora_solution_pack_uninstall_required_objects() { + module_load_include('inc', 'islandora', 'includes/solution_packs'); + + $module = drush_get_option('module'); + if (module_exists($module)) { + islandora_uninstall_solution_pack( + $module, + drush_get_option('force', FALSE) + ); + } + else { + drush_log(dt('"@module" is not installed/enabled?...', array( + '@module' => $module, + ))); + } +} + +/** + * Command callback for object status. + */ +function drush_islandora_solution_pack_required_objects_status() { + module_load_include('inc', 'islandora', 'includes/solution_packs'); + + $module = drush_get_option('module', FALSE); + $required_objects = array(); + if ($module && module_exists($module)) { + $required_objects[$module] = islandora_solution_packs_get_required_objects($module); + } + elseif ($module === FALSE) { + $required_objects = islandora_solution_packs_get_required_objects(); + } + else { + drush_log(dt('"@module" is not installed/enabled?...', array( + '@module' => $module, + ))); + return; + } + + $header = array('PID', 'Machine Status', 'Readable Status'); + $widths = array(30, 20, 20); + foreach ($required_objects as $module => $info) { + $rows = array(); + drush_print($info['title']); + foreach ($info['objects'] as $object) { + $status = islandora_check_object_status($object); + $rows[] = array( + $object->id, + $status['status'], + $status['status_friendly'], + ); + } + drush_print_table($rows, $header, $widths); + } +} diff --git a/islandora.info b/islandora.info index a9579128..45d473cf 100644 --- a/islandora.info +++ b/islandora.info @@ -17,4 +17,5 @@ files[] = tests/hooks.test files[] = tests/ingest.test files[] = tests/hooked_access.test files[] = tests/islandora_manage_permissions.test +files[] = tests/datastream_versions.test php = 5.3 diff --git a/islandora.module b/islandora.module index c579580c..7d2c0acb 100644 --- a/islandora.module +++ b/islandora.module @@ -33,9 +33,11 @@ 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_PRINT_HOOK', 'islandora_view_print_object'); define('ISLANDORA_EDIT_HOOK', 'islandora_edit_object'); define('ISLANDORA_OVERVIEW_HOOK', 'islandora_overview_object'); define('ISLANDORA_PRE_INGEST_HOOK', 'islandora_ingest_pre_ingest'); @@ -102,6 +104,13 @@ function islandora_menu() { 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), ); + $items['islandora/object/%islandora_object/print'] = array( + 'page callback' => 'islandora_printer_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, @@ -188,7 +197,7 @@ function islandora_menu() { $items['islandora/object/%islandora_object/datastream/%islandora_datastream'] = array( 'title' => 'View datastream', 'page callback' => 'islandora_view_datastream', - 'page arguments' => array(4, FALSE), + 'page arguments' => array(4, FALSE, NULL), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', 'access callback' => 'islandora_datastream_access', @@ -233,13 +242,34 @@ function islandora_menu() { 'access arguments' => array(FEDORA_PURGE, 4), 'load arguments' => array(2), ); - $items['islandora/object/%islandora_object/print'] = array( - 'title' => 'Print Object', - 'page callback' => 'islandora_print_object', - 'page 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_object_access', - 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), + '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/download_clip'] = array( @@ -268,8 +298,9 @@ function islandora_menu() { function islandora_admin_paths() { $paths = array(); $paths['islandora/object/*/manage*'] = TRUE; - $paths['islandora/object/*/delete'] = TRUE; + $paths['islandora/object/*/delete*'] = TRUE; $paths['islandora/object/*/datastream/*/edit'] = TRUE; + $paths['islandora/object/*/datastream/*/versions'] = TRUE; return $paths; } @@ -298,7 +329,11 @@ function islandora_theme() { // Print object view. 'islandora_object_print' => array( 'file' => 'theme/theme.inc', - 'variables' => array('object' => NULL, 'content' => array()), + 'template' => 'theme/islandora-object-print', + 'variables' => array( + 'object' => NULL, + 'content' => NULL, + 'islandora_content' => NULL), ), // Render a bunch of objects as either a grid or a list. 'islandora_objects' => array( @@ -329,16 +364,24 @@ function islandora_theme() { ), 'islandora_datastream_delete_link' => array( 'file' => 'theme/theme.inc', - 'variables' => array('datastream' => NULL), + 'variables' => array('datastream' => NULL, 'version' => NULL), ), 'islandora_datastream_view_link' => array( 'file' => 'theme/theme.inc', - 'variables' => array('datastream' => NULL), + '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), + ), ); } @@ -371,6 +414,10 @@ function islandora_permission() { '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.'), + ), ); } @@ -624,6 +671,7 @@ function islandora_manage_overview_object(AbstractObject $object) { $output = array(); foreach (islandora_build_hook_list(ISLANDORA_OVERVIEW_HOOK, $object->models) as $hook) { $temp = module_invoke_all($hook, $object); + islandora_as_renderable_array($temp); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } @@ -634,7 +682,8 @@ function islandora_manage_overview_object(AbstractObject $object) { } arsort($output); drupal_alter(ISLANDORA_OVERVIEW_HOOK, $object, $output); - return implode('', $output); + islandora_as_renderable_array($output); + return $output; } /** @@ -649,7 +698,11 @@ function islandora_manage_overview_object(AbstractObject $object) { */ function islandora_default_islandora_manage_overview_object(AbstractObject $object) { $output = theme('islandora_default_overview', array('islandora_object' => $object)); - return array('Default overview output' => $output); + return array( + 'Default overview output' => array( + '#markup' => $output, + ), + ); } /** @@ -675,6 +728,7 @@ function islandora_edit_object(AbstractObject $object) { $output = array(); foreach (islandora_build_hook_list(ISLANDORA_EDIT_HOOK, $object->models) as $hook) { $temp = module_invoke_all($hook, $object); + islandora_as_renderable_array($temp); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } @@ -685,7 +739,8 @@ function islandora_edit_object(AbstractObject $object) { } arsort($output); drupal_alter(ISLANDORA_EDIT_HOOK, $object, $output); - return implode('', $output); + islandora_as_renderable_array($output); + return $output; } /** @@ -700,7 +755,11 @@ function islandora_edit_object(AbstractObject $object) { */ function islandora_default_islandora_edit_object(AbstractObject $object) { $output = theme('islandora_default_edit', array('islandora_object' => $object)); - return array('Default Edit output' => $output); + return array( + 'Default Edit output' => array( + '#markup' => $output, + ), + ); } /** @@ -732,8 +791,24 @@ function islandora_view_default_object() { function islandora_view_object(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); module_load_include('inc', 'islandora', 'includes/utilities'); + + // Add the print button via JavaScript. + $path = drupal_get_path('module', 'islandora'); + drupal_add_js(array( + 'islandora' => array( + 'print_img' => $path . '/images/print-icon.png'), + ), array( + 'type' => 'setting')); + + drupal_add_js(array( + 'islandora' => array( + 'print_link' => '/islandora/object/' . $object->id . '/print')), + array('type' => 'setting')); + drupal_add_js($path . '/js/add_print.js'); + 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']; @@ -743,6 +818,7 @@ function islandora_view_object(AbstractObject $object) { // @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); + islandora_as_renderable_array($temp); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } @@ -751,11 +827,47 @@ function islandora_view_object(AbstractObject $object) { // No results, use the default view. $output = islandora_default_islandora_view_object($object); } + arsort($output); drupal_alter($hooks, $object, $output); - return implode('', $output); + islandora_as_renderable_array($output); + return $output; } +/** + * This will prepare an object to be printed. + * + * By default, all fedora objects can print DC record data, + * however, Solution packs that wish to modify the form + * to be printed must implement hook_islandora_view_print_object_alter, + * create a theme.tpl.php file, and return its markup by calling + * theme(themename.tpl.php). + * + * @param AbstractObject $object + * The object to print. + * + * @return string + * An HTML representation of this object. + */ +function islandora_printer_object(AbstractObject $object) { + $output = array(); + $temp_arr = array(); + // Dispatch print hook. + foreach (islandora_build_hook_list(ISLANDORA_PRINT_HOOK, $object->models) as $hook) { + $temp = module_invoke_all($hook, $object); + islandora_as_renderable_array($temp); + if (!empty($temp)) { + $temp_arr = array_merge_recursive($temp_arr, $temp); + } + } + $output = islandora_default_islandora_printer_object($object, drupal_render($temp_arr)); + arsort($output); + islandora_as_renderable_array($output); + + // Prompt to print. + drupal_add_js('jQuery(document).ready(function () { window.print(); });', 'inline'); + return $output; +} /** * Title callback for drupal title. @@ -786,7 +898,53 @@ function islandora_drupal_title(AbstractObject $object) { */ function islandora_default_islandora_view_object($object) { $output = theme('islandora_default', array('islandora_object' => $object)); - return array('Default output' => $output); + return array( + 'Default output' => array( + '#markup' => $output, + ), + ); +} + +/** + * Append the image alter to the printable form. + * + * @param AbstractObject $object + * The fedora object to print. + * @param unknown $alter + * The string representation of the themed viewable object. + * + * @return array + * A renderable array + */ +function islandora_default_islandora_printer_object($object, $alter) { + module_load_include('inc', 'islandora', 'includes/utilities'); + module_load_include('inc', 'islandora', 'includes/datastream'); + + $path = drupal_get_path('module', 'islandora'); + drupal_add_css($path . '/css/islandora.print.css'); + + $islandora_object = islandora_object_load($object->id); + $repository = $islandora_object->repository; + + try { + $dc = $islandora_object['DC']->content; + $dc_object = DublinCore::importFromXMLString($dc); + } + catch (Exception $e) { + drupal_set_message(t('Error retrieving object %s %t', array('%s' => $islandora_object->id, '%t' => $e->getMessage())), 'error', FALSE); + } + + $variables = isset($dc_object) ? $dc_object->asArray() : array(); + $output = theme('islandora_object_print', array( + 'object' => $object, + 'dc_array' => $variables, + 'islandora_content' => $alter)); + + return array( + 'Default output' => array( + '#markup' => $output, + ), + ); } /** @@ -1183,24 +1341,6 @@ function islandora_entity_property_info() { 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. */ @@ -1299,7 +1439,7 @@ function islandora_islandora_object_access($op, $object, $user) { /** * Hookable access callback for datastreams. * - * Requires the equivalent permissions on the object. + * Positive permissions on object access suggests on the datastream. */ function islandora_datastream_access($op, $datastream, $user = NULL) { $cache = &drupal_static(__FUNCTION__); @@ -1328,10 +1468,9 @@ function islandora_datastream_access($op, $datastream, $user = NULL) { $user, )); - // Neither the object nor the datastream check returned FALSE, and one in - // the object or datastream checks returned TRUE. + // 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)) ); diff --git a/js/add_print.js b/js/add_print.js new file mode 100644 index 00000000..7af5c3ca --- /dev/null +++ b/js/add_print.js @@ -0,0 +1,18 @@ +/** + * @file +* JavaScript file responsable for the print button behaviour. +* +* The print button is added automatically to every view, as metadata +* can be printed from every object. +* +*/ +(function ($) { + $(document).ready(function() { + $('.tabs .primary').append(''); + $('#print_btn').css("cursor","pointer"); + $('#print_btn').click(function() { + window.location=Drupal.settings.islandora.print_link; + }); + }); +})(jQuery); + diff --git a/tests/datastream_versions.test b/tests/datastream_versions.test new file mode 100644 index 00000000..6b22bd95 --- /dev/null +++ b/tests/datastream_versions.test @@ -0,0 +1,198 @@ + 'Islandora Datastream Versions', + 'description' => 'Tests the functionality related to datastream versions in Islandora.', + 'group' => 'Islandora', + ); + } + + /** + * Create an object with many datastram versions. + * + * @see IslandoraWebTestCase::setUp() + */ + public function setUp() { + parent::setUp(); + + $this->pid = $this->randomName() . ":" . $this->randomName(); + $tuque = islandora_get_tuque_connection(); + $object = $tuque->repository->constructObject($this->pid); + $object = $tuque->repository->ingestObject($object); + $this->dsid = $this->randomName(); + $ds = $object->constructDatastream($this->dsid); + $ds->label = 'Test'; + $ds->content = 'test'; + $object->ingestDatastream($ds); + + // Create three versions. + $ds->mimetype = 'application/pdf'; + $ds->label = 'jaaaaa maaaan'; + $ds->content = 'Tests... are the bests.'; + } + + /** + * Free any objects/resources created for this test. + * + * @see IslandoraWebTestCase::tearDown() + */ + public function tearDown() { + $tuque = islandora_get_tuque_connection(); + $tuque->repository->purgeObject($this->pid); + + parent::tearDown(); + } + + /** + * Check if the user can see datastream versions in the datastream table. + */ + public function testSeeDatastreamVersions() { + $user = $this->drupalCreateUser(array( + 'view fedora repository objects', + 'ingest fedora objects', + 'view old datastream versions', + 'add fedora datastreams', + )); + $this->drupalLogin($user); + $this->drupalGet("islandora/object/{$this->pid}/manage/datastreams"); + $this->assertLink($this->dsid); + $this->assertLink("4"); + $encoded_pid = urlencode($this->pid); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version"); + } + + /** + * Check that users without permission cannot see datastream versions. + */ + public function testNotSeeDatastreamVersions() { + $user = $this->drupalCreateUser(array( + 'view fedora repository objects', + 'ingest fedora objects', + 'add fedora datastreams', + )); + $this->drupalLogin($user); + $this->drupalGet("islandora/object/{$this->pid}/manage/datastreams"); + $this->assertLink($this->dsid); + $this->assertNoLink("4"); + $encoded_pid = urlencode($this->pid); + $this->assertNoLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version"); + } + + /** + * Check that users without permission cannot see datastream version pages. + */ + public function testDatastreamVersionPermissions() { + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version"); + $this->assertResponse(403); + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/0/view"); + $this->assertResponse(403); + } + + /** + * Check that the proper infomration is displayed on the ds version page. + */ + public function testDatastreamVersionPage() { + $user = $this->drupalCreateUser(array( + 'view old datastream versions', + )); + $this->drupalLogin($user); + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version"); + $this->assertNoLink("Delete"); + $this->assertText("text/xml"); + $this->assertText("application/pdf"); + $this->assertText("jaaaaa maaaan"); + $this->assertText("Test"); + + $encoded_pid = urlencode($this->pid); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/0/view"); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/1/view"); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/2/view"); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/3/view"); + } + + /** + * Make sure the correct content is displayed for each datastream version. + */ + public function testDatastreamVersionContent() { + $user = $this->drupalCreateUser(array( + 'view old datastream versions', + )); + $this->drupalLogin($user); + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/3/view"); + $content = $this->drupalGetContent(); + if ($content != 'test') { + $this->fail("Incorrect datastream content"); + } + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/2/view"); + $content = $this->drupalGetContent(); + if ($content != 'test') { + $this->fail("Incorrect datastream content"); + } + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/1/view"); + $content = $this->drupalGetContent(); + if ($content != 'test') { + $this->fail("Incorrect datastream content"); + } + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/0/view"); + $content = $this->drupalGetContent(); + if ($content != 'Tests... are the bests.') { + $this->fail("Incorrect datastream content"); + } + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/5/view"); + $this->assertResponse(404); + } + + /** + * Make sure you can delete datastream versions. + */ + public function testDatastreamVersionDelete() { + $user = $this->drupalCreateUser(array( + 'view old datastream versions', + 'delete fedora objects and datastreams', + )); + $this->drupalLogin($user); + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version"); + $this->assertLink("delete"); + $this->assertText('text/xml'); + + $encoded_pid = urlencode($this->pid); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/0/delete"); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/1/delete"); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/2/delete"); + $this->assertLinkByHref("islandora/object/$encoded_pid/datastream/{$this->dsid}/version/3/delete"); + + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/3/delete"); + $this->drupalPost(NULL, array(), t('Delete')); + $this->assertNoText('text/xml'); + } + + /** + * Make sure you can't delete versions that don't exist/have only 1 version. + */ + public function testDatastreamVersionDeleteEdgeCase() { + $user = $this->drupalCreateUser(array( + 'view old datastream versions', + 'delete fedora objects and datastreams', + )); + $this->drupalLogin($user); + + $this->drupalGet("islandora/object/{$this->pid}/datastream/{$this->dsid}/version/6/delete"); + $this->assertResponse(404); + + $this->drupalGet("islandora/object/{$this->pid}/datastream/DC/version/0/delete"); + $this->assertResponse(404); + } +} diff --git a/tests/hooks.test b/tests/hooks.test index 3133d656..d08c537b 100644 --- a/tests/hooks.test +++ b/tests/hooks.test @@ -75,6 +75,8 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { /** * Test ALL THE HOOKS!. + * + * Covers the majority of cases... */ public function testHooks() { // Test ingesting with FedoraRepository::ingestObject(). @@ -85,6 +87,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Called "hook_islandora_object_alter" when ingesting via FedoraRepository::ingestObject.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Called ISLANDORA_OBJECT_INGESTED_HOOK when ingesting via FedoraRepository::ingestObject.'); $this->repository->purgeObject($object->id); + // Test blocking the ingest. $object = $this->repository->constructObject('test:testIngestedObjectHook'); $object->label = 'block'; @@ -100,6 +103,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Called "hook_islandora_object_alter" when blocking ingesting via FedoraRepository::ingestObject.'); $this->assertFalse($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_INGESTED_HOOK], 'Did not called ISLANDORA_OBJECT_INGESTED_HOOK when blocking ingesting via FedoraRepository::ingestObject.'); } + // Test modifying via set magic functions. $object = $this->repository->constructObject('test:testModifiedObjectHook'); $this->repository->ingestObject($object); @@ -108,6 +112,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $object->label = "New Label!"; $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_MODIFIED_HOOK], 'Called "hook_islandora_object_alter" when modifying via set magic functions.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK], 'Called ISLANDORA_OBJECT_MODIFIED_HOOK when modifying via set magic functions.'); + // Test blocking the modification. try { $_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK] = FALSE; @@ -122,6 +127,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assertFALSE($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK], 'Called ISLANDORA_OBJECT_MODIFIED_HOOK when blocking modifying via set magic functions.'); } $this->repository->purgeObject($object->id); + // Test purging with FedoraRepository::purgeObject(). $object = $this->repository->constructObject('test:testPurgedObjectHook'); $this->repository->ingestObject($object); @@ -130,6 +136,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->repository->purgeObject($object->id); $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called "hook_islandora_object_alter" when purging via FedoraRepository::purgeObject.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called ISLANDORA_OBJECT_PURGED_HOOK when purging via FedoraRepository::purgeObject.'); + // Test deleting. $object = $this->repository->constructObject('test:testPurgedObjectHook'); $this->repository->ingestObject($object); @@ -139,6 +146,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called "hook_islandora_object_alter" when deleting via FedoraObject::delete.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called ISLANDORA_OBJECT_PURGED_HOOK when purging via FedoraObject::delete.'); $this->repository->purgeObject($object->id); + // Test alter blocking. $object = $this->repository->constructObject('test:testPurgedObjectHook'); $this->repository->ingestObject($object); @@ -154,6 +162,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called "hook_islandora_object_alter" when blocking purge via FedoraRepository::purgeObject.'); $this->assertFalse($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called ISLANDORA_OBJECT_PURGED_HOOK when blocking purge via FedoraRepository::purgeObject.'); } + // Test alter delete. $_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_PURGED_HOOK] = FALSE; $_SESSION['islandora_hooks']['alter'][ISLANDORA_OBJECT_PURGED_HOOK] = FALSE; @@ -164,6 +173,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_PURGED_HOOK], 'Called ISLANDORA_OBJECT_PURGED_HOOK when preventing purge and deleting.'); $object->label = 'Something other than delete'; $this->repository->purgeObject($object->id); + // Test ingesting with FedoraRepository::ingestObject(). $object = $this->repository->constructObject('test:testIngestedDatastreamHook'); $this->repository->ingestObject($object); @@ -174,6 +184,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_INGESTED_HOOK], 'Called "hook_islandora_datastream_alter" when ingesting via FedoraObject::ingestDatastream.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_INGESTED_HOOK], 'Called ISLANDORA_DATASTREAM_INGESTED_HOOK when ingesting via FedoraObject::ingestDatastream.'); $this->repository->purgeObject($object->id); + // Test modifying a datastream. $object = $this->repository->constructObject('test:testModifiedDatastreamHook'); $this->repository->ingestObject($object); @@ -184,6 +195,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $ds->label = "New Label!"; $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called "hook_islandora_datastream_alter" when modifying via set magic functions.'); $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called ISLANDORA_DATASTREAM_MODIFIED_HOOK when modifying via set magic functions.'); + // Test blocking modifying. try { $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK] = FALSE; @@ -197,6 +209,7 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->assertFALSE($_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK], 'Called ISLANDORA_DATASTREAM_MODIFIED_HOOK when blocking modifying via set magic functions.'); } $this->repository->purgeObject($object->id); + // Test purging with FedoraRepository::purgeObject(). $object = $this->repository->constructObject('test:testPurgedDatastreamHook'); $this->repository->ingestObject($object); @@ -210,4 +223,21 @@ class IslandoraHooksTestCase extends IslandoraWebTestCase { $this->repository->purgeObject($object->id); } + /** + * Test ALL THE HOOKS!. + * + * Ensure hooks are triggered properly in "New" objects. + */ + public function testNewIngestHooks() { + // Test ingesting with FedoraRepository::ingestObject(). + $object = $this->repository->constructObject('test:testIngestedDatastreamHook'); + $ds = $object->constructDatastream('TEST'); + $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_INGESTED_HOOK] = FALSE; + $_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_INGESTED_HOOK] = FALSE; + $object->ingestDatastream($ds); + $this->repository->ingestObject($object); + $this->assert($_SESSION['islandora_hooks']['alter'][ISLANDORA_DATASTREAM_INGESTED_HOOK], 'Called "hook_islandora_datastream_alter" when ingesting via FedoraObject::ingestDatastream.'); + $this->assert($_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_INGESTED_HOOK], 'Called ISLANDORA_DATASTREAM_INGESTED_HOOK when ingesting via FedoraObject::ingestDatastream.'); + $this->repository->purgeObject($object->id); + } } diff --git a/tests/islandora_hooked_access_test.module b/tests/islandora_hooked_access_test.module index de417738..e69fc1cc 100644 --- a/tests/islandora_hooked_access_test.module +++ b/tests/islandora_hooked_access_test.module @@ -23,6 +23,9 @@ function islandora_hooked_access_test_islandora_object_access($op, $object, $use * Implements hook_islandora_datastream_access(). */ function islandora_hooked_access_test_islandora_datastream_access($op, $datastream, $user) { + if ($op == FEDORA_PURGE) { + return FALSE; + } if (isset($_SESSION['islandora_hooked_access_test']) && $_SESSION['islandora_hooked_access_test'] === func_get_args()) { return TRUE; } diff --git a/tests/islandora_ingest_test.module b/tests/islandora_ingest_test.module index d414c717..8a6771d9 100644 --- a/tests/islandora_ingest_test.module +++ b/tests/islandora_ingest_test.module @@ -87,7 +87,11 @@ function islandora_ingest_test_test_testcmodel2_islandora_ingest_steps(array &$f * The Drupal form definition. */ function islandora_ingest_test_set_label_form(array $form, array &$form_state) { - $models = array('test:nomorestepscmodel', 'test:testcmodel', 'test:testcmodel2'); + $models = array( + 'test:nomorestepscmodel', + 'test:testcmodel', + 'test:testcmodel2', + ); $model = isset($form_state['values']['model']) ? $form_state['values']['model'] : reset($models); $shared_storage = &islandora_ingest_form_get_shared_storage($form_state); $shared_storage['models'] = array($model); @@ -139,8 +143,7 @@ function islandora_ingest_test_set_label_form_submit(array $form, array &$form_s * Test the First content model. */ function islandora_ingest_test_testcmodel_form(array $form, array &$form_state) { - return array( - ); + return array(); } /** @@ -154,8 +157,7 @@ function islandora_ingest_test_testcmodel_form_submit(array $form, array &$form_ * Test the second content model. */ function islandora_ingest_test_testcmodel2_form(array $form, array &$form_state) { - return array( - ); + return array(); } /** diff --git a/tests/islandora_web_test_case.inc b/tests/islandora_web_test_case.inc index de414c17..baf7a8ee 100644 --- a/tests/islandora_web_test_case.inc +++ b/tests/islandora_web_test_case.inc @@ -157,27 +157,27 @@ class IslandoraWebTestCase extends DrupalWebTestCase { } /** - * Asserts that the given datastreams exist on the object. + * Asserts that the given datastreams exist correctly on the object. * * @param AbstractObject $object * The PID of the object * @param array $datastreams - * An array of strings containing datastream names + * An array of strings containing datastream names */ public function assertDatastreams($object, array $datastreams) { if (!is_object($object)) { - $this->fail("Failed. Object passed in is invalid."); - return; + $this->fail("Failed. Object passed in is invalid.", 'Islandora'); } foreach ($datastreams as $datastream) { if (isset($object[$datastream])) { - $this->pass("Loaded datastream {$datastream} from PID {$object->id}"); + $this->pass("Loaded datastream {$datastream} from PID {$object->id}.", 'Islandora'); } else { - $this->fail("Failed to load datastream {$datastream} from PID {$object->id}"); + $this->fail("Failed to load datastream {$datastream} from PID {$object->id}.", 'Islandora'); } } + } /** @@ -199,7 +199,7 @@ class IslandoraWebTestCase extends DrupalWebTestCase { } } } - $this->fail("Failed to parse path : $path."); + $this->fail("Failed to parse path: $path."); return FALSE; } @@ -208,31 +208,49 @@ class IslandoraWebTestCase extends DrupalWebTestCase { * * @param string $pid * The PID of the collection to be deleted + * @param string $button + * The label of the first 'Delete' button */ - public function deleteObject($pid) { - $current_user = $this->loggedInUser; - $user = $this->drupalCreateUser(array( - 'manage object properties', - 'delete fedora objects and datastreams', - 'view fedora repository objects', - )); - - $this->drupalLogin($user); - + public function deleteObject($pid, $button = 'Delete') { $path = 'islandora/object/' . $pid . '/manage/properties'; $edit = array(); - $this->drupalPost($path, $edit, t('Delete')); + $this->drupalPost($path, $edit, $button); $this->drupalPost($this->url, $edit, t('Delete')); $object = islandora_object_load($pid); $this->drupalGet("islandora/object/$pid"); $this->assertResponse(404, "Object $pid successfully deleted."); + } + + /** + * Reverses a hex string and converts it to a little-endian-formatted integer. + * + * This is useful for running checks on values that appear in the binary + * of a datastream. Returns FALSE if the hex value contains non-hex characters + * or if the string would not return a 16- or 32-bit formatted big-endian + * signed integer. + * + * @param string $hex + * The hex value being converted. + * + * @return bool|int + * FALSE or the integer value that is converted. + */ + public function convertHexToInt($hex) { - if ($current_user) { - $this->drupalLogin($current_user); + // A couple of quick string checks. + if (!ctype_xdigit($hex)) { + $this->fail('String passed to convertHexToInt() contains non-hexidecimal characters.', 'PHP'); + return FALSE; } - else { - $this->drupalLogout(); + if (!strlen($hex) === 4 || !strlen($hex) === 8) { + $this->fail('String passed to convertHexToInt() cannot create a 16- or 32-bit little-endian signed integer', 'PHP'); + return FALSE; } + + // The actual conversion. + $reverse_hex = implode('', array_reverse(str_split($hex, 2))); + $int = hexdec($reverse_hex); + return $int; } } diff --git a/tests/scripts/travis_setup.sh b/tests/scripts/travis_setup.sh index 45dc3ab9..19c7db78 100755 --- a/tests/scripts/travis_setup.sh +++ b/tests/scripts/travis_setup.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash mysql -u root -e 'create database drupal;' mysql -u root -e "create database fedora;" @@ -11,8 +11,8 @@ cd islandora_tomcat export CATALINA_HOME='.' ./bin/startup.sh cd $HOME -pear upgrade –force Console_Getopt -pear upgrade –force pear +pear upgrade --force Console_Getopt +pear upgrade --force pear pear upgrade-all pear channel-discover pear.drush.org pear channel-discover pear.drush.org diff --git a/theme/islandora-object-img-print.tpl.php b/theme/islandora-object-img-print.tpl.php new file mode 100644 index 00000000..3ff21455 --- /dev/null +++ b/theme/islandora-object-img-print.tpl.php @@ -0,0 +1,18 @@ + + +
+ +
+ diff --git a/theme/islandora-object-print.tpl.php b/theme/islandora-object-print.tpl.php new file mode 100644 index 00000000..b9569061 --- /dev/null +++ b/theme/islandora-object-print.tpl.php @@ -0,0 +1,30 @@ + +
+
+ +
+
+ +
+ +
+
+
diff --git a/theme/islandora-object.tpl.php b/theme/islandora-object.tpl.php index 13b40ba0..6fa306c3 100644 --- a/theme/islandora-object.tpl.php +++ b/theme/islandora-object.tpl.php @@ -60,6 +60,7 @@ ?>

+
diff --git a/theme/theme.inc b/theme/theme.inc index f07f95d4..d988ee77 100644 --- a/theme/theme.inc +++ b/theme/theme.inc @@ -15,59 +15,71 @@ function islandora_preprocess_islandora_default_edit(array &$variables) { $variables['islandora_editmetadata_url'] = $base_url . '/islandora/edit_form/' . $islandora_object->id; module_load_include('inc', 'islandora', 'includes/datastream'); module_load_include('inc', 'islandora', 'includes/utilities'); - $header = array( - array('data' => t('ID')), - array('data' => t('Label')), - array('data' => t('Type')), - array('data' => t('Mime type')), - array('data' => t('Size')), - array('data' => t('Operations'), 'colspan' => '3'), - ); + $header = array(); + $header[] = array('data' => t('ID')); + $header[] = array('data' => t('Label')); + $header[] = array('data' => t('Type')); + $header[] = array('data' => t('Mime type')); + $header[] = array('data' => t('Size')); + if (user_access(ISLANDORA_VIEW_DATASTREAM_HISTORY)) { + $header[] = array('data' => t('Versions')); + } + + $header[] = array('data' => t('Operations'), 'colspan' => '3'); + $table_attributes = array('class' => array('manage-datastreams')); $rows = array(); foreach ($islandora_object as $ds) { - $rows[] = array( - array( - 'class' => 'datastream-id', - 'data' => theme('islandora_datastream_view_link', array( - 'datastream' => $ds, - )), - ), - array( - 'class' => 'datastream-label', - 'data' => $ds->label, - ), - array( - 'class' => 'datastream-control', - 'data' => islandora_control_group_to_human_readable($ds->controlGroup), - ), - array( - 'class' => 'datastream-mime', - 'data' => $ds->mimeType, - ), - array( - 'class' => 'datastream-size', - 'data' => islandora_datastream_get_human_readable_size($ds), - ), - array( - 'class' => 'datastream-download', - 'data' => theme('islandora_datastream_download_link', array( - 'datastream' => $ds, - )), - ), - array( - 'class' => 'datstream-edit', - 'data' => theme('islandora_datastream_edit_link', array( - 'datastream' => $ds, - )), - ), - array( - 'class' => 'datastream-delete', - 'data' => theme('islandora_datastream_delete_link', array( + $row = array(); + $row[] = array( + 'class' => 'datastream-id', + 'data' => theme('islandora_datastream_view_link', array( + 'datastream' => $ds, + )), + ); + $row[] = array( + 'class' => 'datastream-label', + 'data' => $ds->label, + ); + $row[] = array( + 'class' => 'datastream-control', + 'data' => islandora_control_group_to_human_readable($ds->controlGroup), + ); + $row[] = array( + 'class' => 'datastream-mime', + 'data' => $ds->mimeType, + ); + $row[] = array( + 'class' => 'datastream-size', + 'data' => islandora_datastream_get_human_readable_size($ds), + ); + if (user_access(ISLANDORA_VIEW_DATASTREAM_HISTORY)) { + $row[] = array( + 'class' => 'datastream-versions', + 'data' => theme('islandora_datastream_version_link', array( 'datastream' => $ds, )), - ), + ); + } + $row[] = array( + 'class' => 'datastream-download', + 'data' => theme('islandora_datastream_download_link', array( + 'datastream' => $ds, + )), ); + $row[] = array( + 'class' => 'datstream-edit', + 'data' => theme('islandora_datastream_edit_link', array( + 'datastream' => $ds, + )), + ); + $row[] = array( + 'class' => 'datastream-delete', + 'data' => theme('islandora_datastream_delete_link', array( + 'datastream' => $ds, + )), + ); + $rows[] = $row; } $caption = $islandora_object->label . ' - ' . $islandora_object->id; $table = array( @@ -239,6 +251,9 @@ function islandora_preprocess_islandora_objects(array &$variables) { * @param array $vars * An array containing: * - datastream: An AbstractDatastream for which to generate a download link. + * + * @return string + * Markup containing the download url if the user has access, empty otherwise. */ function theme_islandora_datastream_download_link(array $vars) { $datastream = $vars['datastream']; @@ -256,15 +271,36 @@ function theme_islandora_datastream_download_link(array $vars) { * @param array $vars * An array containing: * - datastream: An AbstractDatastream for which to generate a view link. + * - label: (Optional) The label for the link. + * - version: (Optional) The version of the datstream to link to. + * + * @return string + * Markup containing the link to the datastream or the label if inaccessible. */ function theme_islandora_datastream_view_link(array $vars) { $datastream = $vars['datastream']; module_load_include('inc', 'islandora', 'includes/utilities'); - $label = check_plain($datastream->id); - return islandora_datastream_access(FEDORA_VIEW_OBJECTS, $datastream) ? - l($label, islandora_datastream_get_url($datastream, 'view')) : - $label; + if ($vars['label'] === NULL) { + $label = check_plain($datastream->id); + } + else { + $label = check_plain($vars['label']); + } + + if ($vars['version'] === NULL) { + $perm = FEDORA_VIEW_OBJECTS; + } + else { + $perm = ISLANDORA_VIEW_DATASTREAM_HISTORY; + } + + if (islandora_datastream_access($perm, $datastream)) { + return l($label, islandora_datastream_get_url($datastream, 'view', $vars['version'])); + } + else { + return $label; + } } /** @@ -273,6 +309,10 @@ function theme_islandora_datastream_view_link(array $vars) { * @param array $vars * An array containing: * - datastream: An AbstractDatastream for which to generate a delete link. + * - version: (optional) the version of the datastream to delete. + * + * @return string + * Markup containing the url to delete a datastream, or empty if inaccessible. */ function theme_islandora_datastream_delete_link(array $vars) { $datastream = $vars['datastream']; @@ -281,9 +321,22 @@ function theme_islandora_datastream_delete_link(array $vars) { $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") : + if ($vars['version'] !== NULL) { + if (count($datastream) == 1) { + $can_delete = FALSE; + } + $link = "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/version/{$vars['version']}/delete"; + } + else { + $link = "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete"; + } + + if ($can_delete) { + return l(t('delete'), $link); + } + else { ''; + } } /** @@ -292,6 +345,9 @@ function theme_islandora_datastream_delete_link(array $vars) { * @param array $vars * An array containing: * - datastream: An AbstractDatastream for which to generate a edit link. + * + * @return string + * Markup containing the url to edit a datastream, or empty if inaccessible. */ function theme_islandora_datastream_edit_link(array $vars) { $datastream = $vars['datastream']; @@ -304,3 +360,32 @@ function theme_islandora_datastream_edit_link(array $vars) { l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") : ''; } + +/** + * Renders a link to take you to the datastream versions page. + * + * @param array $vars + * An array containing: + * - datastream: An AbstractDatastream to generate the version link from. + * + * @return string + * Markup. + */ +function theme_islandora_datastream_version_link(array $vars) { + $datastream = $vars['datastream']; + module_load_include('inc', 'islandora', 'includes/utilities'); + + $see_history = islandora_datastream_access(ISLANDORA_VIEW_DATASTREAM_HISTORY, $datastream); + + if ($see_history) { + if ($datastream->versionable) { + return l(count($datastream), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/version"); + } + else { + return t('Not Versioned'); + } + } + else { + return ''; + } +} diff --git a/xml/strip_newlines_and_whitespace.xsl b/xml/strip_newlines_and_whitespace.xsl new file mode 100644 index 00000000..4d4e1057 --- /dev/null +++ b/xml/strip_newlines_and_whitespace.xsl @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file