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().
*/