diff --git a/includes/breadcrumb.inc b/includes/breadcrumb.inc index 05ab1bac..6f975ae3 100644 --- a/includes/breadcrumb.inc +++ b/includes/breadcrumb.inc @@ -28,7 +28,7 @@ function islandora_get_breadcrumbs($object) { $breadcrumbs = islandora_get_breadcrumbs_recursive($object->id, $object->repository); array_pop($breadcrumbs); $context = 'islandora'; - drupal_alter('islandora_breadcrumbs', $breadcrumbs, $context); + drupal_alter('islandora_breadcrumbs', $breadcrumbs, $context, $object); return $breadcrumbs; } @@ -114,9 +114,7 @@ function islandora_get_breadcrumbs_recursive($pid, FedoraRepository $repository, // render the last two links and break (on the next pass). return array_merge( islandora_get_breadcrumbs_recursive($root, $repository, $context), - array( - '...', - ) + array('...') ); } } diff --git a/includes/datastream.inc b/includes/datastream.inc index 1d506e3d..ba2872c2 100644 --- a/includes/datastream.inc +++ b/includes/datastream.inc @@ -53,8 +53,19 @@ function islandora_view_datastream(AbstractDatastream $datastream, $download = F if ($download) { // Browsers will not append all extensions. $mime_detect = new MimeDetect(); - $extension = $mime_detect->getExtension($datastream->mimetype); - $filename = $datastream->label . '.' . $extension; + $extension = '.' . $mime_detect->getExtension($datastream->mimetype); + + // Prevent adding on a duplicate extension. + $label = $datastream->label; + $extension_length = strlen($extension); + $duplicate_extension_position = strlen($label) > $extension_length ? + strripos($label, $extension, -$extension_length) : + FALSE; + $filename = $label; + if ($duplicate_extension_position === FALSE) { + $filename .= $extension; + } + header("Content-Disposition: attachment; filename=\"$filename\""); } @@ -70,14 +81,30 @@ function islandora_view_datastream(AbstractDatastream $datastream, $download = F islandora_view_datastream_set_cache_headers($datastream); drupal_page_is_cacheable(FALSE); - // Try not to load the file into PHP memory! - // Close and flush ALL the output buffers! - while (@ob_end_flush()) { - }; // New content needed. if ($cache_check === 200) { - $datastream->getContent('php://output'); + // We need to see if the chunking is being requested. This will mainly + // happen with iOS video requests as they do not support any other way + // to receive content for playback. + $chunk_headers = FALSE; + if (isset($_SERVER['HTTP_RANGE'])) { + // Set headers specific to chunking. + $chunk_headers = islandora_view_datastream_set_chunk_headers($datastream); + } + // Try not to load the file into PHP memory! + // Close and flush ALL the output buffers! + while (@ob_end_flush()) { + }; + + if (isset($_SERVER['HTTP_RANGE'])) { + if ($chunk_headers) { + islandora_view_datastream_deliver_chunks($datastream, $chunk_headers); + } + } + else { + $datastream->getContent('php://output'); + } } exit(); } @@ -312,7 +339,7 @@ function islandora_edit_datastream(AbstractDatastream $datastream) { case 0: // No edit implementations. drupal_set_message(t('There are no edit methods specified for this datastream.')); - drupal_goto("islandora/object/{$object->id}/manage/datastreams"); + drupal_goto("islandora/object/{$datastream->parent->id}/manage/datastreams"); break; case 1: @@ -383,3 +410,125 @@ function islandora_datastream_get_view_link(AbstractDatastream $datastream) { 'datastream' => $datastream, )); } + +/** + * Set the headers for the chunking of our content. + * + * @param AbstractDatastream $datastream + * An AbstractDatastream representing a datastream on a Fedora object. + * + * @return bool + * TRUE if there are chunks to be returned, FALSE otherwise. + */ +function islandora_view_datastream_set_chunk_headers(AbstractDatastream $datastream) { + $file_uri = islandora_view_datastream_retrieve_file_uri($datastream); + // The meat of this has been taken from: + // http://mobiforge.com/design-development/content-delivery-mobile-devices. + $size = filesize($file_uri); + $length = $size; + $start = 0; + $end = $size - 1; + + header("Accept-Ranges: 0-$length"); + if (isset($_SERVER['HTTP_RANGE'])) { + $c_start = $start; + $c_end = $end; + // Extract the range string. + list(, $range) = explode('=', $_SERVER['HTTP_RANGE'], 2); + // Make sure the client hasn't sent us a multibyte range. + if (strpos($range, ',') !== FALSE) { + // Not a valid range, notify the client. + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + exit; + } + // If the range starts with an '-' we start from the beginning. If not, we + // forward the file pointer and make sure to get the end byte if specified. + if (strpos($range, '-') === 0) { + // The n-number of the last bytes is requested. + $c_start = $size - substr($range, 1); + } + else { + $range = explode('-', $range); + $c_start = $range[0]; + $c_end = (isset($range[1]) && is_numeric($range[1])) ? $range[1] : $size; + } + /* Check the range and make sure it's treated according to the specs. + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + */ + // End bytes can not be larger than $end. + $c_end = ($c_end > $end) ? $end : $c_end; + // Validate the requested range and return an error if it's not correct. + if ($c_start > $c_end || $c_start > $size - 1 || $c_end >= $size) { + header('HTTP/1.1 416 Requested Range Not Satisfiable'); + header("Content-Range: bytes $start-$end/$size"); + exit; + } + $start = $c_start; + $end = $c_end; + // Calculate new content length. + $length = $end - $start + 1; + header('HTTP/1.1 206 Partial Content'); + } + // Notify the client the byte range we'll be outputting. + header("Content-Range: bytes $start-$end/$size"); + header("Content-Length: $length"); + return array( + 'start' => $start, + 'end' => $end, + ); +} + +/** + * Deliver back the specified chunks of a file. + * + * @param AbstractDatastream $datastream + * An AbstractDatastream representing a datastream on a Fedora object. + * @param array $params + * An associate array containing the start and ending chunk bytes. + */ +function islandora_view_datastream_deliver_chunks(AbstractDatastream $datastream, $params) { + $file_uri = islandora_view_datastream_retrieve_file_uri($datastream); + // The meat of this has been taken from: + // http://mobiforge.com/design-development/content-delivery-mobile-devices. + $fp = @fopen($file_uri, 'rb'); + fseek($fp, $params['start']); + // Start buffered download. + $buffer = 1024 * 8; + while (!feof($fp) && ($p = ftell($fp)) <= $params['end']) { + if ($p + $buffer > $params['end']) { + // In case we're only outputting a chunk, make sure we don't read past the + // length. + $buffer = $params['end'] - $p + 1; + } + // Reset time limit for big files. + set_time_limit(0); + echo fread($fp, $buffer); + } + fclose($fp); +} + +/** + * Creates/returns the file URI for the content of a datastream for chunking. + * + * @param AbstractDatastream $datastream + * An AbstractDatastream representing a datastream on a Fedora object. + * + * @return string + * The URI of the file. + */ +function islandora_view_datastream_retrieve_file_uri(AbstractDatastream $datastream) { + $mime_detect = new MimeDetect(); + $extension = $mime_detect->getExtension($datastream->mimetype); + $file_uri = 'temporary://chunk_' . $datastream->parent->id . '_' . $datastream->id . '_' . $datastream->createdDate->getTimestamp() . '.' . $extension; + if (!file_exists($file_uri)) { + $file = new stdClass(); + $file->uri = $file_uri; + $file->filename = drupal_basename($file_uri); + $file->filemime = $datastream->mimeType; + $file->status = 0; + $datastream->getContent($file_uri); + file_save($file); + } + return $file_uri; +} diff --git a/includes/derivatives.inc b/includes/derivatives.inc index 5ba4bb56..d25789cc 100644 --- a/includes/derivatives.inc +++ b/includes/derivatives.inc @@ -41,20 +41,7 @@ function islandora_do_derivatives(AbstractObject $object, array $options) { $hooks = islandora_invoke_hook_list(ISLANDORA_DERVIATIVE_CREATION_HOOK, $object->models, array($object)); uasort($hooks, 'drupal_sort_weight'); $results = array(); - - if (array_key_exists('source_dsid', $options)) { - $hooks = array_filter($hooks, function($filter_hook) use($options) { - return array_key_exists('source_dsid', $filter_hook) && - $filter_hook['source_dsid'] == $options['source_dsid']; - }); - } - - if (array_key_exists('destination_dsid', $options)) { - $hooks = array_filter($hooks, function($filter_hook) use($options) { - return array_key_exists('destination_dsid', $filter_hook) && - $filter_hook['destination_dsid'] == $options['destination_dsid']; - }); - } + $hooks = islandora_filter_derivatives($hooks, $options, $object); foreach ($hooks as $hook) { if (isset($hook['file'])) { @@ -121,3 +108,94 @@ function islandora_derivative_logging(array $logging_results) { } } } + +/** + * Kicks off derivative functions based upon hooks and conditions. + * + * @param AbstractObject $object + * An AbstractObject representing a FedoraObject. + * @param array $options + * An array of parameters containing: + * - force: Bool denoting whether we are forcing the generation of + * derivatives. + * - source_dsid: (Optional) String of the datastream id we are generating + * from or NULL if it's the object itself. + * - destination_dsid: (Optional) String of the datastream id that is being + * created. To be used in the UI. + * + * @return array + * An array of operations to be called from within a batch. + */ +function islandora_do_batch_derivatives(AbstractObject $object, array $options) { + module_load_include('inc', 'islandora', 'includes/utilities'); + $options += array( + 'force' => FALSE, + ); + $hooks = islandora_invoke_hook_list(ISLANDORA_DERVIATIVE_CREATION_HOOK, $object->models, array($object)); + uasort($hooks, 'drupal_sort_weight'); + $operations = array(); + + $hooks = islandora_filter_derivatives($hooks, $options, $object); + foreach ($hooks as $hook) { + $file = FALSE; + if (isset($hook['file'])) { + $file = $hook['file']; + } + foreach ($hook['function'] as $function) { + $operations[] = array('islandora_derivative_perform_batch_operation', array( + $function, + $file, + $object->id, + $options['force']), + ); + } + } + return $operations; +} + +/** + * Filter the derivative functions to only call those which are valid. + * + * @param array $hooks + * An array of hooks to be filtered depending on options. + * @param array $options + * An array of options for the derivative generation. + * @param AbstractObject $object + * An AbstractObject representing an object within Fedora. + * + * @return array + * Returns the filtered array of hooks to be ran. + */ +function islandora_filter_derivatives($hooks, $options, AbstractObject $object) { + if (array_key_exists('source_dsid', $options)) { + $hooks = array_filter($hooks, function ($filter_hook) use ($options) { + return array_key_exists('source_dsid', $filter_hook) && + $filter_hook['source_dsid'] == $options['source_dsid']; + }); + } + if (array_key_exists('destination_dsid', $options)) { + $hooks = array_filter($hooks, function ($filter_hook) use ($options) { + return array_key_exists('destination_dsid', $filter_hook) && + $filter_hook['destination_dsid'] == $options['destination_dsid']; + }); + } + // Do a final filtering to make sure that the source DSID exists on the object + // where needed. Using a defined function as opposed to the way above as + // it seems to break PHPCS as of 1.4.8. + $filter_function = function ($filter_hook) use ($object) { + $to_return = FALSE; + if (array_key_exists('source_dsid', $filter_hook)) { + if ($filter_hook['source_dsid'] != NULL) { + if (isset($object[$filter_hook['source_dsid']])) { + $to_return = TRUE; + } + } + else { + $to_return = TRUE; + } + } + return $to_return; + }; + $hooks = array_filter($hooks, $filter_function); + return $hooks; +} diff --git a/includes/object_properties.form.inc b/includes/object_properties.form.inc index 676f0d0c..f9c8e23b 100644 --- a/includes/object_properties.form.inc +++ b/includes/object_properties.form.inc @@ -26,6 +26,15 @@ function islandora_object_properties_form(array $form, array &$form_state, Abstr if (!empty($temp)) { $related_objects_pids = array_merge_recursive($related_objects_pids, $temp); } + $regenerate_derivatives_access = FALSE; + if (islandora_object_access(ISLANDORA_REGENERATE_DERIVATIVES, $object)) { + module_load_include('inc', 'islandora', 'includes/derivatives'); + $hooks = islandora_invoke_hook_list(ISLANDORA_DERVIATIVE_CREATION_HOOK, $object->models, array($object)); + $hooks = islandora_filter_derivatives($hooks, array('force' => TRUE), $object); + if (count($hooks) > 1) { + $regenerate_derivatives_access = TRUE; + } + } return array( 'pid' => array( '#type' => 'hidden', @@ -84,6 +93,12 @@ function islandora_object_properties_form(array $form, array &$form_state, Abstr '#submit' => array('islandora_object_properties_form_delete'), '#limit_validation_errors' => array(array('pid')), ), + 'regenerate' => array( + '#type' => 'submit', + '#access' => $regenerate_derivatives_access, + '#value' => t("Regenerate all derivatives"), + '#submit' => array('islandora_object_properties_regenerate_derivatives'), + ), ); } @@ -188,3 +203,15 @@ function islandora_update_object_properties($pid, $update_states, $state, $updat } } } + +/** + * Callback function for object properties regenerate all derivatives. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_object_properties_regenerate_derivatives(array $form, array &$form_state) { + drupal_goto("islandora/object/{$form_state['object']}/regenerate"); +} diff --git a/includes/regenerate_derivatives.form.inc b/includes/regenerate_derivatives.form.inc new file mode 100644 index 00000000..a7ef147c --- /dev/null +++ b/includes/regenerate_derivatives.form.inc @@ -0,0 +1,178 @@ + $datastream->id)), + "islandora/object/{$datastream->parent->id}/manage/datastreams", + t('This will create a new version of the datastream. Please wait while this happens.'), + t('Regenerate'), + t('Cancel') + ); +} + +/** + * Submit handler for the regenerate datastream derivative form. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_regenerate_datastream_derivative_form_submit(array $form, array &$form_state) { + module_load_include('inc', 'islandora', 'includes/derivatives'); + $datastream = $form_state['datastream']; + $batch = islandora_regenerate_datastream_derivative_batch($datastream); + batch_set($batch); + $form_state['redirect'] = "islandora/object/{$datastream->parent->id}/manage/datastreams"; +} + +/** + * Regenerate all derivatives on an object. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + * @param AbstractObject $object + * The object that is having its derivatives regenerated. + * + * @return array + * The Drupal form definition. + */ +function islandora_regenerate_object_derivatives_form(array $form, array &$form_state, AbstractObject $object) { + $form_state['object'] = $object; + return confirm_form($form, + t('Are you sure you want to regenerate all the derivatives for %title?', array('%title' => $object->label)), + "islandora/object/{$object->id}/manage/properties", + t('This will create a new version for every datastream on the object. Please wait while this happens.'), + t('Regenerate'), + t('Cancel') + ); +} + +/** + * Submit handler for the regenerate object derivativse form. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_regenerate_object_derivatives_form_submit(array $form, array &$form_state) { + $object = $form_state['object']; + $batch = islandora_regenerate_object_derivatives_batch($object); + batch_set($batch); + $form_state['redirect'] = "islandora/object/{$object->id}/manage/properties"; +} + +/** + * Creates a batch to go out and re-create all of the derivatives for an object. + * + * @param AbstractObject $object + * A AbstractObject representing an object within Fedora. + * + * @return array + * An array specifying the Drupal batch. + */ +function islandora_regenerate_object_derivatives_batch(AbstractObject $object) { + module_load_include('inc', 'islandora', 'includes/derivatives'); + return array( + 'title' => t('Regenerating all derivatives for @label', array('@label' => $object->label)), + 'operations' => islandora_do_batch_derivatives($object, array('force' => TRUE)), + 'init_message' => t('Preparing to regenerate derivatives...'), + 'progress_message' => t('Time elapsed: @elapsed
Estimated time remaning @estimate.'), + 'error_message' => t('An error has occurred.'), + 'file' => drupal_get_path('module', 'islandora') . '/includes/regenerate_derivatives.form.inc', + 'finished' => 'islandora_regenerate_derivative_batch_finished', + ); +} + +/** + * Creates a batch to go out and re-create the derivative for a datastream. + * + * @param AbstractDatastream $datastream + * A AbstractDatastream representing a datastream on an object within Fedora. + * + * @return array + * An array specifying the Drupal batch. + */ +function islandora_regenerate_datastream_derivative_batch(AbstractDatastream $datastream) { + module_load_include('inc', 'islandora', 'includes/derivatives'); + return array( + 'title' => t('Regenerating derivatives for the @dsid datastream', array('@dsid' => $datastream->id)), + 'operations' => islandora_do_batch_derivatives($datastream->parent, array( + 'force' => TRUE, + 'destination_dsid' => $datastream->id, + )), + 'init_message' => t('Preparing to regenerate derivatives...'), + 'progress_message' => t('Time elapsed: @elapsed
Estimated time remaning @estimate.'), + 'error_message' => t('An error has occurred.'), + 'file' => drupal_get_path('module', 'islandora') . '/includes/regenerate_derivatives.form.inc', + 'finished' => 'islandora_regenerate_derivative_batch_finished', + ); +} + +/** + * Wrapper to call out to batch operations. + * + * @param string $function + * The name of the function we are calling for derivatives. + * @param bool|string $file + * FALSE if there is no file to load, the path to require otherwise + * @param string $pid + * The pid of the object we are performing. + * @param bool $force + * Whether we are forcing derivative regeneration or not. + * @param array $context + * The context of the current batch operation. + */ +function islandora_derivative_perform_batch_operation($function, $file, $pid, $force, &$context) { + if ($file) { + require_once $file; + } + if (function_exists($function)) { + $logging = call_user_func($function, islandora_object_load($pid), $force); + if (!empty($logging)) { + $context['results']['logging'][] = $logging; + } + } + else { + watchdog('islandora', 'Unable to call derivative function @function as it was not found!', array('@function' => $function), WATCHDOG_ERROR); + } +} + +/** + * Finished function for derivative batch regeneration. + * + * @param array $success + * An array of success passed from the batch. + * @param array $results + * An array of results passed from the batch. + * @param array $operations + * An array of operations passed from the batch. + */ +function islandora_regenerate_derivative_batch_finished($success, $results, $operations) { + module_load_include('inc', 'islandora', 'includes/derivatives'); + if (!empty($results['logging'])) { + islandora_derivative_logging($results['logging']); + } +} diff --git a/islandora.api.php b/islandora.api.php index 04d8bd49..51aeb343 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -691,8 +691,10 @@ function hook_islandora_update_related_objects_properties(AbstractObject $object * Breadcrumbs array to be altered by reference. Each element is markup. * @param string $context * Where the alter is originating from for distinguishing. + * @param AbstractObject $object + * (Optional) AbstractObject representing object providing breadcrumb path */ -function hook_islandora_breadcrumbs_alter(&$breadcrumbs, $context) { +function hook_islandora_breadcrumbs_alter(&$breadcrumbs, $context, $object = NULL) { } diff --git a/islandora.module b/islandora.module index 96789eba..8405d303 100644 --- a/islandora.module +++ b/islandora.module @@ -36,6 +36,7 @@ define('ISLANDORA_MANAGE_PROPERTIES', 'manage object properties'); define('ISLANDORA_VIEW_DATASTREAM_HISTORY', 'view old datastream versions'); define('ISLANDORA_MANAGE_DELETED_OBJECTS', 'manage deleted objects'); define('ISLANDORA_REVERT_DATASTREAM', 'revert to old datastream'); +define('ISLANDORA_REGENERATE_DERIVATIVES', 'regenerate derivatives for an object'); // Hooks. @@ -209,6 +210,15 @@ function islandora_menu() { 'access callback' => 'islandora_object_access_callback', 'access arguments' => array(ISLANDORA_PURGE, 2), ); + $items['islandora/object/%islandora_object/regenerate'] = array( + 'title' => 'Regenerate all derivatives on an object', + 'file' => 'includes/regenerate_derivatives.form.inc', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('islandora_regenerate_object_derivatives_form', 2), + 'type' => MENU_CALLBACK, + 'access callback' => 'islandora_object_access_callback', + 'access arguments' => array(ISLANDORA_REGENERATE_DERIVATIVES, 2), + ); $items['islandora/object/%islandora_object/manage/datastreams/add'] = array( 'title' => 'Add a datastream', 'file' => 'includes/add_datastream.form.inc', @@ -314,6 +324,16 @@ function islandora_menu() { 'access arguments' => array(ISLANDORA_VIEW_DATASTREAM_HISTORY, 4), 'load arguments' => array(2), ); + $items['islandora/object/%islandora_object/datastream/%islandora_datastream/regenerate'] = array( + 'title' => 'Regenrate datastream derivative', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('islandora_regenerate_datastream_derivative_form', 4), + 'file' => 'includes/regenerate_derivatives.form.inc', + 'type' => MENU_CALLBACK, + 'access callback' => 'islandora_datastream_access', + 'access arguments' => array(ISLANDORA_REGENERATE_DERIVATIVES, 4), + 'load arguments' => array(2), + ); $items['islandora/object/%islandora_object/download_clip'] = array( 'page callback' => 'islandora_download_clip', 'page arguments' => array(2), @@ -460,6 +480,10 @@ function islandora_theme() { 'file' => 'theme/theme.inc', 'variables' => array('datastream' => NULL), ), + 'islandora_datastream_regenerate_link' => array( + 'file' => 'theme/theme.inc', + 'variables' => array('datastream' => NULL), + ), 'islandora_dublin_core_display' => array( 'file' => 'theme/theme.inc', 'template' => 'theme/islandora-dublin-core-display', @@ -534,6 +558,10 @@ function islandora_permission() { 'title' => t('Manage deleted objects'), 'description' => t('Purge or revert deleted objects.'), ), + ISLANDORA_REGENERATE_DERIVATIVES => array( + 'title' => t('Regenerate derivatives'), + 'description' => t('Regenerate derivatives for an object or per datastream.'), + ), ); } @@ -1069,7 +1097,7 @@ function islandora_default_islandora_view_object($object) { * * @param AbstractObject $object * The fedora object to print. - * @param unknown $alter + * @param string $alter * The string representation of the themed viewable object. * * @return array @@ -1802,6 +1830,32 @@ function islandora_islandora_metadata_display_info() { ); } +/** + * Implements hook_islandora_datastream_access(). + */ +function islandora_islandora_datastream_access($op, AbstractDatastream $datastream, $user) { + module_load_include('inc', 'islandora', 'includes/utilities'); + $result = islandora_namespace_accessible($datastream->parent->id) && user_access($op, $user); + + if ($result && $op == ISLANDORA_REGENERATE_DERIVATIVES) { + module_load_include('inc', 'islandora', 'includes/derivatives'); + $applicable_hook = FALSE; + $object = $datastream->parent; + $hooks = islandora_invoke_hook_list(ISLANDORA_DERVIATIVE_CREATION_HOOK, $object->models, array($object)); + $hooks = islandora_filter_derivatives($hooks, array('force' => TRUE), $object); + foreach ($hooks as $hook) { + if ($hook['destination_dsid'] == $datastream->id && islandora_datastream_access(ISLANDORA_VIEW_OBJECTS, $object[$hook['source_dsid']], $user)) { + $applicable_hook = TRUE; + break; + } + } + if (!$applicable_hook) { + $result = FALSE; + } + } + return $result; +} + /** * Determines the server's operating system. * diff --git a/tests/derivatives.test b/tests/derivatives.test index 13014880..b7eeae9b 100644 --- a/tests/derivatives.test +++ b/tests/derivatives.test @@ -159,7 +159,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase { public function testDerivativeFilteringOnSourceDSID() { global $_islandora_derivative_test_derivative_functions; $_islandora_derivative_test_derivative_functions = array(); - $this->constructBaseObject(); + $object = $this->constructBaseObject(); + $this->constructSOMEWEIRDDATASTREAMDatastream($object); $object = islandora_object_load($this->pid); islandora_do_derivatives($object, array( 'source_dsid' => 'OBJ', @@ -207,7 +208,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase { public function testNoSourceDSIDNoForce() { global $_islandora_derivative_test_derivative_functions; $_islandora_derivative_test_derivative_functions = array(); - $this->constructBaseObject(); + $object = $this->constructBaseObject(); + $object = $this->constructSOMEWEIRDDATASTREAMDatastream($object); $object = islandora_object_load($this->pid); islandora_do_derivatives($object, array()); $this->assertDatastreams($object, array( @@ -216,6 +218,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase { 'OBJ', 'DERIV', 'NOSOURCE', + 'SOMEWEIRDDATASTREAM', + 'STANLEY', )); $this->assertEqual(3, count($_islandora_derivative_test_derivative_functions), 'Expected 3 derivative functions when there is no source_dsid, got ' . count($_islandora_derivative_test_derivative_functions) . '.'); } @@ -226,7 +230,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase { public function testNoSourceDSIDForce() { global $_islandora_derivative_test_derivative_functions; $_islandora_derivative_test_derivative_functions = array(); - $this->constructBaseObject(); + $object = $this->constructBaseObject(); + $this->constructSOMEWEIRDDATASTREAMDatastream($object); $object = islandora_object_load($this->pid); islandora_do_derivatives($object, array( 'force' => TRUE, @@ -236,6 +241,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase { 'RELS-EXT', 'OBJ', 'DERIV', + 'SOMEWEIRDDATASTREAM', + 'STANLEY', 'NOSOURCE', )); $this->assertEqual(3, count($_islandora_derivative_test_derivative_functions), 'Expected 3 derivative functions when there is no source_dsid, got ' . count($_islandora_derivative_test_derivative_functions) . '.'); @@ -293,4 +300,22 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase { $object->ingestDatastream($ds); return $object; } + + /** + * Helper function to construct the SWD datastream without firing hooks. + * + * @param AbstractObject $object + * An AbstractObject representing a FedoraObject. + * + * @return AbstractObject + * The modified AbstractObject. + */ + public function constructSOMEWEIRDDATASTREAMDatastream(AbstractObject $object) { + $dsid = 'SOMEWEIRDDATASTREAM'; + $ds = $object->constructDatastream($dsid); + $ds->label = 'Test'; + $ds->content = 'Omnomnom'; + $object->ingestDatastream($ds); + return $object; + } } diff --git a/tests/islandora_derivatives_test.module b/tests/islandora_derivatives_test.module index 80530296..2e27c5c7 100644 --- a/tests/islandora_derivatives_test.module +++ b/tests/islandora_derivatives_test.module @@ -23,7 +23,7 @@ function islandora_derivatives_test_some_cmodel_islandora_derivative() { 'destination_dsid' => 'STANLEY', 'weight' => '-1', 'function' => array( - 'islandora_derivatives_test_create_some_weird_datastream', + 'islandora_derivatives_test_create_stanley_datastream', ), ), array( @@ -81,17 +81,20 @@ function islandora_derivatives_test_create_deriv_datastream(AbstractObject $obje } /** - * Stub function that used only for datastream filtering counts. + * Creates the STANLEY datastream for use in testing. * * @param AbstractObject $object * An AbstractObject representing a Fedora object. * @param bool $force * Whether the derivatives are being forcefully generated or not. */ -function islandora_derivatives_test_create_some_weird_datastream(AbstractObject $object, $force = FALSE) { +function islandora_derivatives_test_create_stanley_datastream(AbstractObject $object, $force = FALSE) { global $_islandora_derivative_test_derivative_functions; // Add to the global that we got to this function. $_islandora_derivative_test_derivative_functions[] = 'islandora_derivatives_test_create_some_weird_datastream'; + if (!isset($object['STANLEY']) || (isset($object['STANLEY']) && $force === TRUE)) { + islandora_derivatives_test_add_datastream($object, 'STANLEY', 'yum'); + } } /** diff --git a/theme/theme.inc b/theme/theme.inc index 6a80fbb6..b783cfa8 100644 --- a/theme/theme.inc +++ b/theme/theme.inc @@ -25,7 +25,7 @@ function islandora_preprocess_islandora_default_edit(array &$variables) { $header[] = array('data' => t('Versions')); } - $header[] = array('data' => t('Operations'), 'colspan' => '3'); + $header[] = array('data' => t('Operations'), 'colspan' => '4'); $table_attributes = array('class' => array('manage-datastreams')); $rows = array(); @@ -53,7 +53,7 @@ function islandora_preprocess_islandora_default_edit(array &$variables) { 'class' => 'datastream-size', 'data' => islandora_datastream_get_human_readable_size($ds), ); - if (user_access(ISLANDORA_VIEW_DATASTREAM_HISTORY)) { + if (islandora_datastream_access(ISLANDORA_VIEW_DATASTREAM_HISTORY, $ds)) { $row[] = array( 'class' => 'datastream-versions', 'data' => theme('islandora_datastream_version_link', array( @@ -79,6 +79,12 @@ function islandora_preprocess_islandora_default_edit(array &$variables) { 'datastream' => $ds, )), ); + $row[] = array( + 'class' => 'datastream-regenerate', + 'data' => theme('islandora_datastream_regenerate_link', array( + 'datastream' => $ds, + )), + ); $rows[] = $row; } $caption = filter_xss($islandora_object->label) . ' - ' . $islandora_object->id; @@ -424,6 +430,23 @@ function theme_islandora_datastream_version_link(array $vars) { } } +/** + * Renders a link that will re-create derivatives for a datastream. + * + * @param array $vars + * An array containing: + * - datastream: An AbstractDatastream to generate the version link from. + * + * @return string + * Markup. + */ +function theme_islandora_datastream_regenerate_link(array $vars) { + $datastream = $vars['datastream']; + if (islandora_datastream_access(ISLANDORA_REGENERATE_DERIVATIVES, $datastream)) { + return l(t('regenerate'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/regenerate"); + } +} + /** * Implements hook_preprocess(). */