Browse Source

Merge branch '7.x' of git://github.com/Islandora/islandora into 7.x

pull/457/head
Nelson Hart 11 years ago
parent
commit
42c75afb5b
  1. 8
      css/islandora.admin.css
  2. 5
      includes/add_datastream.form.inc
  3. 6
      includes/breadcrumb.inc
  4. 159
      includes/datastream.inc
  5. 60
      includes/datastream.version.inc
  6. 106
      includes/derivatives.inc
  7. 6
      includes/ingest.form.inc
  8. 15
      includes/mime_detect.inc
  9. 27
      includes/mime_type.autocomplete.inc
  10. 37
      includes/object_properties.form.inc
  11. 178
      includes/regenerate_derivatives.form.inc
  12. 56
      includes/solution_packs.inc
  13. 15
      includes/tuque_wrapper.inc
  14. 14
      includes/utilities.inc
  15. 4
      islandora.api.php
  16. 58
      islandora.drush.inc
  17. 79
      islandora.module
  18. 31
      tests/derivatives.test
  19. 9
      tests/islandora_derivatives_test.module
  20. 90
      tests/islandora_web_test_case.inc
  21. 2
      tests/scripts/travis_setup.sh
  22. 18
      theme/islandora-object-img-print.tpl.php
  23. 27
      theme/theme.inc

8
css/islandora.admin.css

@ -13,5 +13,11 @@
.islandora-solution-pack-fieldset table th, .islandora-solution-pack-fieldset table th,
.islandora-solution-pack-fieldset table td .islandora-solution-pack-fieldset table td
{ {
width: 33%; width: 30%;
}
.islandora-solution-pack-fieldset table th:first-child,
.islandora-solution-pack-fieldset table td:first-child
{
width: 10%;
} }

5
includes/add_datastream.form.inc

@ -161,7 +161,10 @@ function islandora_add_datastream_form_validate(array $form, array &$form_state)
if (isset($form_state['datastream_requirements'][$dsid]) && $file) { if (isset($form_state['datastream_requirements'][$dsid]) && $file) {
$allowed_types = $form_state['datastream_requirements'][$dsid]['mime']; $allowed_types = $form_state['datastream_requirements'][$dsid]['mime'];
$mime_detect = new MimeDetect(); $mime_detect = new MimeDetect();
$allowed_extensions = array_map(array($mime_detect, 'getExtension'), $allowed_types); $allowed_extensions = array();
foreach ($allowed_types as $mime) {
$allowed_extensions = array_merge($allowed_extensions, $mime_detect->getValidExtensions($mime));
}
$errors = file_validate_extensions($file, implode(' ', $allowed_extensions)); $errors = file_validate_extensions($file, implode(' ', $allowed_extensions));
if (count($errors) > 0) { if (count($errors) > 0) {
form_set_error('file', $errors[0]); form_set_error('file', $errors[0]);

6
includes/breadcrumb.inc

@ -28,7 +28,7 @@ function islandora_get_breadcrumbs($object) {
$breadcrumbs = islandora_get_breadcrumbs_recursive($object->id, $object->repository); $breadcrumbs = islandora_get_breadcrumbs_recursive($object->id, $object->repository);
array_pop($breadcrumbs); array_pop($breadcrumbs);
$context = 'islandora'; $context = 'islandora';
drupal_alter('islandora_breadcrumbs', $breadcrumbs, $context); drupal_alter('islandora_breadcrumbs', $breadcrumbs, $context, $object);
return $breadcrumbs; 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). // render the last two links and break (on the next pass).
return array_merge( return array_merge(
islandora_get_breadcrumbs_recursive($root, $repository, $context), islandora_get_breadcrumbs_recursive($root, $repository, $context),
array( array('...')
'...',
)
); );
} }
} }

159
includes/datastream.inc

@ -53,8 +53,19 @@ function islandora_view_datastream(AbstractDatastream $datastream, $download = F
if ($download) { if ($download) {
// Browsers will not append all extensions. // Browsers will not append all extensions.
$mime_detect = new MimeDetect(); $mime_detect = new MimeDetect();
$extension = $mime_detect->getExtension($datastream->mimetype); $extension = '.' . $mime_detect->getExtension($datastream->mimetype);
$filename = $datastream->label . '.' . $extension;
// 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\""); header("Content-Disposition: attachment; filename=\"$filename\"");
} }
@ -70,15 +81,31 @@ function islandora_view_datastream(AbstractDatastream $datastream, $download = F
islandora_view_datastream_set_cache_headers($datastream); islandora_view_datastream_set_cache_headers($datastream);
drupal_page_is_cacheable(FALSE); drupal_page_is_cacheable(FALSE);
// New content needed.
if ($cache_check === 200) {
// 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! // Try not to load the file into PHP memory!
// Close and flush ALL the output buffers! // Close and flush ALL the output buffers!
while (@ob_end_flush()) { while (@ob_end_flush()) {
}; };
// New content needed. if (isset($_SERVER['HTTP_RANGE'])) {
if ($cache_check === 200) { if ($chunk_headers) {
islandora_view_datastream_deliver_chunks($datastream, $chunk_headers);
}
}
else {
$datastream->getContent('php://output'); $datastream->getContent('php://output');
} }
}
exit(); exit();
} }
@ -312,7 +339,7 @@ function islandora_edit_datastream(AbstractDatastream $datastream) {
case 0: case 0:
// No edit implementations. // No edit implementations.
drupal_set_message(t('There are no edit methods specified for this datastream.')); 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; break;
case 1: case 1:
@ -383,3 +410,125 @@ function islandora_datastream_get_view_link(AbstractDatastream $datastream) {
'datastream' => $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;
}

60
includes/datastream.version.inc

@ -1,4 +1,5 @@
<?php <?php
/** /**
* @file * @file
* The form displayed that shows the datastream version history. * The form displayed that shows the datastream version history.
@ -10,19 +11,36 @@
function islandora_datastream_version_table($datastream) { function islandora_datastream_version_table($datastream) {
module_load_include('inc', 'islandora', 'includes/datastream'); module_load_include('inc', 'islandora', 'includes/datastream');
module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/utilities');
$parent = $datastream->parent;
drupal_set_title(t("@dsid Previous Versions", array('@dsid' => $datastream->id))); drupal_set_title(t("@dsid Previous Versions", array('@dsid' => $datastream->id)));
$audit_values = islandora_get_audit_trail($parent->id, $datastream->id);
$header = array(); $header = array();
$header[] = array('data' => t('Created Date')); $header[] = array('data' => t('Created Date'));
$header[] = array('data' => t('Size')); $header[] = array('data' => t('Size'));
$header[] = array('data' => t('Label')); $header[] = array('data' => t('Label'));
$header[] = array('data' => t('Responsibility'));
$header[] = array('data' => t('Mime type')); $header[] = array('data' => t('Mime type'));
$header[] = array('data' => t('Operations'), 'colspan' => '2'); $header[] = array('data' => t('Operations'), 'colspan' => '2');
$rows = array(); $rows = array();
foreach ($datastream as $version => $datastream_version) { foreach ($datastream as $version => $datastream_version) {
$row = array(); $row = array();
$reponsibility = $parent->owner;
foreach ($audit_values as $audit_value) {
$internal = $datastream_version->createdDate;
if ($audit_value['date'] == $datastream_version->createdDate) {
$reponsibility = $audit_value['responsibility'];
}
}
$user = user_load_by_name($reponsibility);
if ($user) {
$user_id = $user->uid;
$user_val = l($reponsibility, "user/$user_id");
}
else {
$user_val = $reponsibility;
}
$row[] = array( $row[] = array(
'class' => 'datastream-date', 'class' => 'datastream-date',
'data' => theme('islandora_datastream_view_link', array( 'data' => theme('islandora_datastream_view_link', array(
@ -39,6 +57,10 @@ function islandora_datastream_version_table($datastream) {
'class' => 'datastream-label', 'class' => 'datastream-label',
'data' => $datastream_version->label, 'data' => $datastream_version->label,
); );
$row[] = array(
'class' => 'datastream-responsibility',
'data' => $user_val,
);
$row[] = array( $row[] = array(
'class' => 'datastream-mime', 'class' => 'datastream-mime',
'data' => $datastream_version->mimeType, 'data' => $datastream_version->mimeType,
@ -208,3 +230,39 @@ function islandora_revert_datastream_version_form_submit(array $form, array &$fo
$form_state['redirect'] = "islandora/object/{$islandora_object->id}/datastream/{$datastream_to_revert->id}/version"; $form_state['redirect'] = "islandora/object/{$islandora_object->id}/datastream/{$datastream_to_revert->id}/version";
} }
/**
* Gets Audit datastream values from foxml.
*
* @param String $pid
* PID of parent object
*
* @return array
* Array of audit values
*/
function islandora_get_audit_trail($pid, $dsid) {
$url = variable_get('islandora_base_url', 'http://localhost:8080/fedora');
$connection = islandora_get_tuque_connection(NULL, $url);
$xml = $connection->api->m->getObjectXml($pid);
$simple_xml = simplexml_load_string($xml);
$fox_ns = "info:fedora/fedora-system:def/foxml#";
$audit_ns = 'info:fedora/fedora-system:def/audit#';
$foxml_nodes = $simple_xml->children($fox_ns);
foreach ($foxml_nodes as $node) {
if ($node->attributes()->ID == "AUDIT") {
$content = $node->datastreamVersion->xmlContent;
$audit_nodes = $content->children($audit_ns);
}
}
$audit_values = array();
if (isset($audit_nodes)) {
foreach ($audit_nodes->auditTrail->record as $record) {
if ($dsid == $record->componentID) {
$values['responsibility'] = $record->responsibility;
$values['date'] = $record->date;
$audit_values[] = $values;
}
}
}
return $audit_values;
}

106
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)); $hooks = islandora_invoke_hook_list(ISLANDORA_DERVIATIVE_CREATION_HOOK, $object->models, array($object));
uasort($hooks, 'drupal_sort_weight'); uasort($hooks, 'drupal_sort_weight');
$results = array(); $results = array();
$hooks = islandora_filter_derivatives($hooks, $options, $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'];
});
}
foreach ($hooks as $hook) { foreach ($hooks as $hook) {
if (isset($hook['file'])) { 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;
}

6
includes/ingest.form.inc

@ -769,10 +769,16 @@ function islandora_ingest_form_submit(array $form, array &$form_state) {
islandora_ingest_form_execute_consecutive_callback_steps($form, $form_state, $step); islandora_ingest_form_execute_consecutive_callback_steps($form, $form_state, $step);
} }
// Ingest the objects. // Ingest the objects.
$set_redirect = TRUE;
foreach ($form_state['islandora']['objects'] as &$object) { foreach ($form_state['islandora']['objects'] as &$object) {
try { try {
islandora_add_object($object); islandora_add_object($object);
// We want to redirect to the first object as it's considered to be the
// primary object.
if ($set_redirect) {
$form_state['redirect'] = "islandora/object/{$object->id}"; $form_state['redirect'] = "islandora/object/{$object->id}";
$set_redirect = FALSE;
}
drupal_set_message( drupal_set_message(
t('"@label" (ID: @pid) has been ingested.', array('@label' => $object->label, '@pid' => $object->id)), t('"@label" (ID: @pid) has been ingested.', array('@label' => $object->label, '@pid' => $object->id)),
'status'); 'status');

15
includes/mime_detect.inc

@ -383,4 +383,19 @@ class MimeDetect {
return $this->protectedMimeTypes; return $this->protectedMimeTypes;
} }
/**
* Get all valid extensions for this MIME type.
*
* @param string $mimetype
* The MIME type we are searching for.
*
* @return array
* An array of valid extensions for this MIME type.
*/
public function getValidExtensions($mimetype) {
$filter = function ($mime) use ($mimetype) {
return $mime == $mimetype;
};
return array_keys(array_filter($this->protectedMimeTypes, $filter));
}
} }

27
includes/mime_type.autocomplete.inc

@ -0,0 +1,27 @@
<?php
/**
* @file
* Autocomplete functionality for MIME types in Islandora.
*/
/**
* Autocomplete the MIME type name.
*
* @param string $string
* A search string.
*
* @return string
* The rendered JSON results.
*/
function islandora_mime_type_autocomplete($string) {
module_load_include('inc', 'islandora', 'includes/mime_detect');
$mime_detect = new MimeDetect();
$mime_types = $mime_detect->getMimeTypes();
$output = array();
foreach ($mime_types as $mime_type) {
if (preg_match("/{$string}/i", $mime_type) !== 0) {
$output[$mime_type] = $mime_type;
}
}
return drupal_json_output($output);
}

37
includes/object_properties.form.inc

@ -26,6 +26,15 @@ function islandora_object_properties_form(array $form, array &$form_state, Abstr
if (!empty($temp)) { if (!empty($temp)) {
$related_objects_pids = array_merge_recursive($related_objects_pids, $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( return array(
'pid' => array( 'pid' => array(
'#type' => 'hidden', '#type' => 'hidden',
@ -84,6 +93,12 @@ function islandora_object_properties_form(array $form, array &$form_state, Abstr
'#submit' => array('islandora_object_properties_form_delete'), '#submit' => array('islandora_object_properties_form_delete'),
'#limit_validation_errors' => array(array('pid')), '#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'),
),
); );
} }
@ -166,15 +181,15 @@ function islandora_object_properties_form_delete(array $form, array &$form_state
/** /**
* Updates object state. * Updates object state.
* *
* @param String $pid * @param string $pid
* PID of object to be updated * PID of object to be updated
* @param Boolean $update_states * @param bool $update_states
* If TRUE, update object state * If TRUE, update object state
* @param String $state * @param string $state
* Desired object state * Desired object state
* @param Boolean $update_owners * @param bool $update_owners
* If TRUE, update Owner * If TRUE, update Owner
* @param String $owner * @param string $owner
* New Owner * New Owner
*/ */
function islandora_update_object_properties($pid, $update_states, $state, $update_owners, $owner) { function islandora_update_object_properties($pid, $update_states, $state, $update_owners, $owner) {
@ -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");
}

178
includes/regenerate_derivatives.form.inc

@ -0,0 +1,178 @@
<?php
/**
* @file
* The confirmation forms used to regenerate derivatives.
*/
/**
* Regenerate a single datastream derivative confirm form.
*
* @param array $form
* The Drupal form.
* @param array $form_state
* The Drupal form state.
* @param AbstractDatastream $datastream
* The datastream to have derivatives regenerated for.
*
* @return array
* The Drupal form definition.
*/
function islandora_regenerate_datastream_derivative_form(array $form, array &$form_state, AbstractDatastream $datastream) {
$form_state['datastream'] = $datastream;
return confirm_form($form,
t('Are you sure you want to regenerate the derivative for the %dsid datastream?', array('%dsid' => $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 <br/>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 <br/>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']);
}
}

56
includes/solution_packs.inc

@ -140,7 +140,14 @@ function islandora_solution_pack_form(array $form, array &$form_state, $solution
); );
$status_severities = array_keys($status_info); $status_severities = array_keys($status_info);
$solution_pack_status_severity = array_search('up_to_date', $status_severities); $solution_pack_status_severity = array_search('up_to_date', $status_severities);
$table_rows = array();
// Prepair for tableselect.
$header = array(
'label' => t('Label'),
'pid' => t('PID'),
'status' => t('Status'));
$object_info = array();
foreach ($objects as $object) { foreach ($objects as $object) {
$object_status = islandora_check_object_status($object); $object_status = islandora_check_object_status($object);
$object_status_info = $status_info[$object_status['status']]; $object_status_info = $status_info[$object_status['status']];
@ -151,11 +158,15 @@ function islandora_solution_pack_form(array $form, array &$form_state, $solution
$exists = $object_status['status'] != 'missing'; $exists = $object_status['status'] != 'missing';
$label = $exists ? l($object->label, "islandora/object/{$object->id}") : $object->label; $label = $exists ? l($object->label, "islandora/object/{$object->id}") : $object->label;
$status_msg = "{$object_status_info['image']}&nbsp{$object_status['status_friendly']}"; $status_msg = "{$object_status_info['image']}&nbsp{$object_status['status_friendly']}";
$table_rows[] = array($label, $object->id, $status_msg); $object_info[] = array(
'label' => $label,
'pid' => $object->id,
'status' => $status_msg);
} }
$solution_pack_status = $status_severities[$solution_pack_status_severity]; $solution_pack_status = $status_severities[$solution_pack_status_severity];
$solution_pack_status_info = $status_info[$solution_pack_status]; $solution_pack_status_info = $status_info[$solution_pack_status];
return array(
$form = array(
'solution_pack' => array( 'solution_pack' => array(
'#type' => 'fieldset', '#type' => 'fieldset',
'#collapsible' => FALSE, '#collapsible' => FALSE,
@ -187,10 +198,13 @@ function islandora_solution_pack_form(array $form, array &$form_state, $solution
'#suffix' => '</div>', '#suffix' => '</div>',
), ),
'table' => array( 'table' => array(
'#type' => 'item', '#type' => 'tableselect',
'#markup' => theme('table', array( '#header' => $header,
'header' => array(t('Label'), t('PID'), t('Status')), '#options' => $object_info,
'rows' => $table_rows)), ),
'tablevalue' => array(
'#type' => 'hidden',
'#value' => json_encode($object_info),
), ),
'submit' => array( 'submit' => array(
'#type' => 'submit', '#type' => 'submit',
@ -200,6 +214,7 @@ function islandora_solution_pack_form(array $form, array &$form_state, $solution
), ),
), ),
); );
return $form;
} }
/** /**
@ -211,9 +226,21 @@ function islandora_solution_pack_form(array $form, array &$form_state, $solution
* The state of the form submited. * The state of the form submited.
*/ */
function islandora_solution_pack_form_submit(array $form, array &$form_state) { function islandora_solution_pack_form_submit(array $form, array &$form_state) {
$not_checked = array();
$object_info = json_decode($form_state['values']['tablevalue']);
if (isset($form_state['values']['table'])) {
foreach ($form_state['values']['table'] as $key => $value) {
if ($value === 0) {
$not_checked[] = $object_info[$key]->pid;
}
}
}
$solution_pack_module = $form_state['values']['solution_pack_module']; $solution_pack_module = $form_state['values']['solution_pack_module'];
$batch = islandora_solution_pack_get_batch($solution_pack_module); // Use not_checked instead of checked. Remove not checked item from betch. so
// that get batch function can get all object ingest batch if not checked list
// is empty.
$batch = islandora_solution_pack_get_batch($solution_pack_module, $not_checked);
batch_set($batch); batch_set($batch);
// Hook to let solution pack objects be modified. // Hook to let solution pack objects be modified.
// Not using module_invoke so solution packs can be expanded by other modules. // Not using module_invoke so solution packs can be expanded by other modules.
@ -227,11 +254,13 @@ function islandora_solution_pack_form_submit(array $form, array &$form_state) {
* @param string $module * @param string $module
* The name of the modules of which to grab the required objects for to setup * The name of the modules of which to grab the required objects for to setup
* the batch. * the batch.
* @param array $not_checked
* The object that will bot be install.
* *
* @return array * @return array
* An array defining a batch which can be passed on to batch_set(). * An array defining a batch which can be passed on to batch_set().
*/ */
function islandora_solution_pack_get_batch($module) { function islandora_solution_pack_get_batch($module, $not_checked = array()) {
$batch = array( $batch = array(
'title' => t('Installing / Updating solution pack objects'), 'title' => t('Installing / Updating solution pack objects'),
'file' => drupal_get_path('module', 'islandora') . '/includes/solution_packs.inc', 'file' => drupal_get_path('module', 'islandora') . '/includes/solution_packs.inc',
@ -239,6 +268,14 @@ function islandora_solution_pack_get_batch($module) {
); );
$info = islandora_solution_packs_get_required_objects($module); $info = islandora_solution_packs_get_required_objects($module);
foreach ($info['objects'] as $key => $object) {
foreach ($not_checked as $not) {
if ($object->id == $not) {
unset($info['objects'][$key]);
}
}
}
foreach ($info['objects'] as $object) { foreach ($info['objects'] as $object) {
$batch['operations'][] = array('islandora_solution_pack_batch_operation_reingest_object', array($object)); $batch['operations'][] = array('islandora_solution_pack_batch_operation_reingest_object', array($object));
} }
@ -803,7 +840,6 @@ function islandora_get_viewer_callback($viewer_id = NULL) {
} }
return FALSE; return FALSE;
} }
/** /**
* @} End of "defgroup viewer-functions". * @} End of "defgroup viewer-functions".
*/ */

15
includes/tuque_wrapper.inc

@ -8,7 +8,11 @@
* @todo Overload functions and apply pre/post hooks. * @todo Overload functions and apply pre/post hooks.
*/ */
$islandora_module_path = drupal_get_path('module', 'islandora'); // This function may not exist when a batch operation is running from a
// multistep form.
if (function_exists('drupal_get_path')) {
$islandora_module_path = drupal_get_path('module', 'islandora');
}
// @todo this until we expost these in a module or library // @todo this until we expost these in a module or library
@include_once 'sites/all/libraries/tuque/Datastream.php'; @include_once 'sites/all/libraries/tuque/Datastream.php';
@ -294,7 +298,14 @@ class IslandoraFedoraApiM extends FedoraApiM {
default: default:
$ret = parent::purgeDatastream($pid, $dsid, $params); $ret = parent::purgeDatastream($pid, $dsid, $params);
islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_PURGED_HOOK, $object->models, $dsid, $object, $dsid); // We need to remove this object from the cache and reload it as
// Tuque may not have an updated copy. That is the datastream could
// still be present within the object even though it's purged out of
// Fedora.
$tuque = islandora_get_tuque_connection();
$tuque->cache->delete($pid);
$non_cached_object = islandora_object_load($pid);
islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_PURGED_HOOK, $non_cached_object->models, $dsid, $non_cached_object, $dsid);
return $ret; return $ret;
} }
} }

14
includes/utilities.inc

@ -981,3 +981,17 @@ function islandora_scale_thumbnail($file, $width, $height) {
} }
return FALSE; return FALSE;
} }
/**
* Determines if the server operating system is Windows.
*
* @return bool
* TRUE if Windows, FALSE otherwise.
*/
function islandora_deployed_on_windows() {
// Determine if PHP is currently running on Windows.
if (strpos(strtolower(php_uname('s')), 'windows') !== FALSE) {
return TRUE;
}
return FALSE;
}

4
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. * Breadcrumbs array to be altered by reference. Each element is markup.
* @param string $context * @param string $context
* Where the alter is originating from for distinguishing. * 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) {
} }

58
islandora.drush.inc

@ -70,7 +70,23 @@ function islandora_drush_command() {
), ),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN, 'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN,
); );
$commands['islandora-solution-pack-install-content_models'] = array(
'description' => dt('Install Solution Pack content models.'),
'options' => array(
'module' => array(
'description' => dt('The module for which to install the content models.'),
'required' => TRUE,
),
),
'aliases' => array('ispicm'),
'drupal dependencies' => array(
'islandora',
),
'examples' => array(
'drush -u 1 ispicm --module=islandora' => dt('Install missing solution pack objects for the "islandora" module.'),
),
'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_LOGIN,
);
return $commands; return $commands;
} }
@ -83,9 +99,7 @@ function drush_islandora_solution_pack_install_required_objects() {
$module = drush_get_option('module'); $module = drush_get_option('module');
if (module_exists($module)) { if (module_exists($module)) {
islandora_install_solution_pack( islandora_install_solution_pack(
$module, $module, 'install', drush_get_option('force', FALSE)
'install',
drush_get_option('force', FALSE)
); );
} }
else { else {
@ -104,8 +118,7 @@ function drush_islandora_solution_pack_uninstall_required_objects() {
$module = drush_get_option('module'); $module = drush_get_option('module');
if (module_exists($module)) { if (module_exists($module)) {
islandora_uninstall_solution_pack( islandora_uninstall_solution_pack(
$module, $module, drush_get_option('force', FALSE)
drush_get_option('force', FALSE)
); );
} }
else { else {
@ -152,3 +165,36 @@ function drush_islandora_solution_pack_required_objects_status() {
drush_print_table($rows, $header, $widths); drush_print_table($rows, $header, $widths);
} }
} }
/**
* Command callback to install required objects.
*/
function drush_islandora_solution_pack_install_content_models() {
module_load_include('inc', 'islandora', 'includes/solution_packs');
$module = drush_get_option('module');
if (module_exists($module)) {
$info = islandora_solution_packs_get_required_objects($module);
$objects_to_add = array();
foreach ($info['objects'] as $key => $candidate) {
$object = islandora_object_load($candidate);
if (in_array('fedora-system:ContentModel-3.0', $object->models)) {
$objects_to_add[] = $candidate;
}
}
foreach ($objects_to_add as $object_to_add) {
$old_object = islandora_object_load($object_to_add->id);
if ($old_object) {
$deleted = islandora_delete_object($old_object);
if (!$deleted) {
drush_log(dt('@object did not delete.', array('@object' => $old_object->id), 'error'));
continue;
}
}
$new_object = islandora_add_object($object_to_add);
$verb = $deleted ? dt("Replaced") : dt("Added");
if ($new_object) {
drush_log("$verb " . $object_to_add->id . " - " . $object_to_add->label);
}
}
}
}

79
islandora.module

@ -36,6 +36,7 @@ define('ISLANDORA_MANAGE_PROPERTIES', 'manage object properties');
define('ISLANDORA_VIEW_DATASTREAM_HISTORY', 'view old datastream versions'); define('ISLANDORA_VIEW_DATASTREAM_HISTORY', 'view old datastream versions');
define('ISLANDORA_MANAGE_DELETED_OBJECTS', 'manage deleted objects'); define('ISLANDORA_MANAGE_DELETED_OBJECTS', 'manage deleted objects');
define('ISLANDORA_REVERT_DATASTREAM', 'revert to old datastream'); define('ISLANDORA_REVERT_DATASTREAM', 'revert to old datastream');
define('ISLANDORA_REGENERATE_DERIVATIVES', 'regenerate derivatives for an object');
// Hooks. // Hooks.
@ -61,6 +62,7 @@ define('ISLANDORA_DERVIATIVE_CREATION_HOOK', 'islandora_derivative');
// Autocomplete paths. // Autocomplete paths.
define('ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE', 'islandora/autocomplete/content-models'); define('ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE', 'islandora/autocomplete/content-models');
define('ISLANDORA_MIME_TYPES_AUTOCOMPLETE', 'islandora/autocomplete/mime-types');
/** /**
* @deprecated Constants. * @deprecated Constants.
@ -209,6 +211,15 @@ function islandora_menu() {
'access callback' => 'islandora_object_access_callback', 'access callback' => 'islandora_object_access_callback',
'access arguments' => array(ISLANDORA_PURGE, 2), '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( $items['islandora/object/%islandora_object/manage/datastreams/add'] = array(
'title' => 'Add a datastream', 'title' => 'Add a datastream',
'file' => 'includes/add_datastream.form.inc', 'file' => 'includes/add_datastream.form.inc',
@ -314,6 +325,16 @@ function islandora_menu() {
'access arguments' => array(ISLANDORA_VIEW_DATASTREAM_HISTORY, 4), 'access arguments' => array(ISLANDORA_VIEW_DATASTREAM_HISTORY, 4),
'load arguments' => array(2), '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( $items['islandora/object/%islandora_object/download_clip'] = array(
'page callback' => 'islandora_download_clip', 'page callback' => 'islandora_download_clip',
'page arguments' => array(2), 'page arguments' => array(2),
@ -338,6 +359,15 @@ function islandora_menu() {
'access arguments' => array('administer site configuration'), 'access arguments' => array('administer site configuration'),
'type' => MENU_CALLBACK, 'type' => MENU_CALLBACK,
); );
$items[ISLANDORA_MIME_TYPES_AUTOCOMPLETE] = array(
'title' => 'Autocomplete callback',
'description' => 'Autocomplete MIME Types.',
'file' => 'includes/mime_type.autocomplete.inc',
'page callback' => 'islandora_mime_type_autocomplete',
'page arguments' => array(3),
'access arguments' => array('administer site configuration'),
'type' => MENU_CALLBACK,
);
$items['admin/islandora/restore/prep'] = array( $items['admin/islandora/restore/prep'] = array(
'description' => 'Restore or permanantly remove objects with Deleted status', 'description' => 'Restore or permanantly remove objects with Deleted status',
'title' => 'Manage Deleted Objects', 'title' => 'Manage Deleted Objects',
@ -460,6 +490,10 @@ function islandora_theme() {
'file' => 'theme/theme.inc', 'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL), 'variables' => array('datastream' => NULL),
), ),
'islandora_datastream_regenerate_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_dublin_core_display' => array( 'islandora_dublin_core_display' => array(
'file' => 'theme/theme.inc', 'file' => 'theme/theme.inc',
'template' => 'theme/islandora-dublin-core-display', 'template' => 'theme/islandora-dublin-core-display',
@ -485,6 +519,11 @@ function islandora_theme() {
'pattern' => 'islandora_dublin_core_description__', 'pattern' => 'islandora_dublin_core_description__',
'variables' => array('islandora_object' => NULL), 'variables' => array('islandora_object' => NULL),
), ),
// Table for install/reinstall content model and collections.
'islandora_solution_pack_table' => array(
'file' => 'includes/solution_packs.inc',
'render element' => 'form',
),
); );
} }
@ -529,6 +568,10 @@ function islandora_permission() {
'title' => t('Manage deleted objects'), 'title' => t('Manage deleted objects'),
'description' => t('Purge or revert 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.'),
),
); );
} }
@ -994,11 +1037,9 @@ function islandora_view_object(AbstractObject $object) {
/** /**
* This will prepare an object to be printed. * This will prepare an object to be printed.
* *
* By default, all fedora objects can print DC record data, * By default all fedora objects can print DC record data. Solution packs that
* however, Solution packs that wish to modify the form * wish to modify the data to be printed can implement
* to be printed must implement hook_islandora_view_print_object_alter, * hook_islandora_view_print_object or hook_islandora_metadata_display_info.
* create a theme.tpl.php file, and return its markup by calling
* theme(themename.tpl.php).
* *
* @param AbstractObject $object * @param AbstractObject $object
* The object to print. * The object to print.
@ -1064,7 +1105,7 @@ function islandora_default_islandora_view_object($object) {
* *
* @param AbstractObject $object * @param AbstractObject $object
* The fedora object to print. * The fedora object to print.
* @param unknown $alter * @param string $alter
* The string representation of the themed viewable object. * The string representation of the themed viewable object.
* *
* @return array * @return array
@ -1796,3 +1837,29 @@ 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;
}

31
tests/derivatives.test

@ -159,7 +159,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase {
public function testDerivativeFilteringOnSourceDSID() { public function testDerivativeFilteringOnSourceDSID() {
global $_islandora_derivative_test_derivative_functions; global $_islandora_derivative_test_derivative_functions;
$_islandora_derivative_test_derivative_functions = array(); $_islandora_derivative_test_derivative_functions = array();
$this->constructBaseObject(); $object = $this->constructBaseObject();
$this->constructSOMEWEIRDDATASTREAMDatastream($object);
$object = islandora_object_load($this->pid); $object = islandora_object_load($this->pid);
islandora_do_derivatives($object, array( islandora_do_derivatives($object, array(
'source_dsid' => 'OBJ', 'source_dsid' => 'OBJ',
@ -207,7 +208,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase {
public function testNoSourceDSIDNoForce() { public function testNoSourceDSIDNoForce() {
global $_islandora_derivative_test_derivative_functions; global $_islandora_derivative_test_derivative_functions;
$_islandora_derivative_test_derivative_functions = array(); $_islandora_derivative_test_derivative_functions = array();
$this->constructBaseObject(); $object = $this->constructBaseObject();
$object = $this->constructSOMEWEIRDDATASTREAMDatastream($object);
$object = islandora_object_load($this->pid); $object = islandora_object_load($this->pid);
islandora_do_derivatives($object, array()); islandora_do_derivatives($object, array());
$this->assertDatastreams($object, array( $this->assertDatastreams($object, array(
@ -216,6 +218,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase {
'OBJ', 'OBJ',
'DERIV', 'DERIV',
'NOSOURCE', '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) . '.'); $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() { public function testNoSourceDSIDForce() {
global $_islandora_derivative_test_derivative_functions; global $_islandora_derivative_test_derivative_functions;
$_islandora_derivative_test_derivative_functions = array(); $_islandora_derivative_test_derivative_functions = array();
$this->constructBaseObject(); $object = $this->constructBaseObject();
$this->constructSOMEWEIRDDATASTREAMDatastream($object);
$object = islandora_object_load($this->pid); $object = islandora_object_load($this->pid);
islandora_do_derivatives($object, array( islandora_do_derivatives($object, array(
'force' => TRUE, 'force' => TRUE,
@ -236,6 +241,8 @@ class IslandoraDerivativesTestCase extends IslandoraWebTestCase {
'RELS-EXT', 'RELS-EXT',
'OBJ', 'OBJ',
'DERIV', 'DERIV',
'SOMEWEIRDDATASTREAM',
'STANLEY',
'NOSOURCE', '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) . '.'); $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); $object->ingestDatastream($ds);
return $object; 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;
}
} }

9
tests/islandora_derivatives_test.module

@ -23,7 +23,7 @@ function islandora_derivatives_test_some_cmodel_islandora_derivative() {
'destination_dsid' => 'STANLEY', 'destination_dsid' => 'STANLEY',
'weight' => '-1', 'weight' => '-1',
'function' => array( 'function' => array(
'islandora_derivatives_test_create_some_weird_datastream', 'islandora_derivatives_test_create_stanley_datastream',
), ),
), ),
array( 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 * @param AbstractObject $object
* An AbstractObject representing a Fedora object. * An AbstractObject representing a Fedora object.
* @param bool $force * @param bool $force
* Whether the derivatives are being forcefully generated or not. * 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; global $_islandora_derivative_test_derivative_functions;
// Add to the global that we got to this function. // Add to the global that we got to this function.
$_islandora_derivative_test_derivative_functions[] = 'islandora_derivatives_test_create_some_weird_datastream'; $_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');
}
} }
/** /**

90
tests/islandora_web_test_case.inc

@ -7,6 +7,13 @@
class IslandoraWebTestCase extends DrupalWebTestCase { class IslandoraWebTestCase extends DrupalWebTestCase {
/**
* An array of users that may be created over the course of a test.
*
* @var array
*/
protected $users = array();
/** /**
* Sets up the Drupal filter to access this test Drupal instances database. * Sets up the Drupal filter to access this test Drupal instances database.
* *
@ -131,6 +138,7 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
} }
else { else {
parent::drupalLogin($account); parent::drupalLogin($account);
$this->users[] = $account->name;
} }
} }
@ -155,6 +163,9 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
* @see DrupalWebTestCase::tearDown() * @see DrupalWebTestCase::tearDown()
*/ */
public function tearDown() { public function tearDown() {
foreach ($this->users as $user) {
$this->deleteUserCreatedObjects($user);
}
if ($this->configuration['use_drupal_filter']) { if ($this->configuration['use_drupal_filter']) {
$this->restoreDrupalFilter(); $this->restoreDrupalFilter();
} }
@ -170,20 +181,24 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
* The PID of the object * The PID of the object
* @param array $datastreams * @param array $datastreams
* An array of strings containing datastream names * An array of strings containing datastream names
*
* @return bool
* TRUE on success, FALSE on fail.
*/ */
public function assertDatastreams($object, array $datastreams) { public function assertDatastreams($object, array $datastreams) {
if (!is_object($object)) { if (!is_object($object)) {
$this->fail("Failed. Object passed in is invalid.", 'Islandora'); $this->fail("Failed. Object passed in is invalid.", 'Islandora');
} }
else { else {
foreach ($datastreams as $datastream) { $missing_datastreams = array_diff_key(array_flip($datastreams), $this->admin->repository->api->a->listDatastreams($object->id));
if (isset($object[$datastream])) {
$this->pass("Loaded datastream {$datastream} from PID {$object->id}.", 'Islandora'); if (!empty($missing_datastreams)) {
} $this->fail("Failed to find datastream(s) " . implode(', ', array_flip($missing_datastreams)) . " in object {$object->id}.");
else { return FALSE;
$this->fail("Failed to load datastream {$datastream} from PID {$object->id}.", 'Islandora');
}
} }
$this->pass("Found required datastream(s) in object {$object->id}");
return TRUE;
} }
} }
@ -254,23 +269,30 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
* The PID of the collection to be deleted * The PID of the collection to be deleted
* @param string $button * @param string $button
* The label of the first 'Delete' button * The label of the first 'Delete' button
* @param bool $safety
* If TRUE, this will only delete objects owned by users in $this->users.
*/ */
public function deleteObject($pid, $button = NULL) { public function deleteObject($pid, $button = NULL, $safety = TRUE) {
$path = 'islandora/object/' . $pid . '/manage/properties'; $object = islandora_object_load($pid);
$edit = array(); if (!$safety || in_array($object->owner, $this->users)) {
$path = "islandora/object/$pid/manage/properties";
if (isset($button)) { if (isset($button)) {
$this->drupalPost($path, $edit, $button); $this->drupalPost($path, array(), $button);
} }
else { else {
$object = islandora_object_load($pid); $object = islandora_object_load($pid);
$this->drupalPost($path, $edit, "Permanently remove '{$object->label}' from repository"); $this->drupalPost($path, array(), "Permanently remove '{$object->label}' from repository");
} }
$this->drupalPost($this->url, $edit, t('Delete')); $this->drupalPost($this->url, array(), t('Delete'));
$object = islandora_object_load($pid);
$this->drupalGet("islandora/object/$pid"); $this->drupalGet("islandora/object/$pid");
$this->assertResponse(404, "Object $pid successfully deleted."); $this->assertResponse(404, "Object $pid successfully deleted.");
} }
else {
$this->fail("Cannot delete object {$pid}; it is owned by non-test user {$object->owner}, and this function was called with the safety on.");
return FALSE;
}
}
/** /**
* Constructs and ingests a Fedora object and datastream(s) via tuque. * Constructs and ingests a Fedora object and datastream(s) via tuque.
@ -283,7 +305,9 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
* 'label' - The object label; randomized if not set. * 'label' - The object label; randomized if not set.
* 'pid' - 'namespace:pid', or just 'namespace' to generate the suffix. * 'pid' - 'namespace:pid', or just 'namespace' to generate the suffix.
* 'models' - An array that can contain multiple content model PIDs. * 'models' - An array that can contain multiple content model PIDs.
* 'owner' - The object's owner. * 'owner' - The object's owner. Defaults to the currently logged-in user,
* if available. It is recommended to set this to a value that can be found
* in $this->users; otherwise, this object will have to be manually deleted.
* 'parent' - The PID of the parent collection. * 'parent' - The PID of the parent collection.
* @param array $datastreams * @param array $datastreams
* An array containing zero or more datastream arrays that use the keys: * An array containing zero or more datastream arrays that use the keys:
@ -316,6 +340,9 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
if (isset($properties['owner'])) { if (isset($properties['owner'])) {
$object->owner = $properties['owner']; $object->owner = $properties['owner'];
} }
elseif ($this->loggedInUser !== FALSE) {
$object->owner = $this->loggedInUser->name;
}
if (isset($properties['models']) && is_array($properties['models'])) { if (isset($properties['models']) && is_array($properties['models'])) {
foreach ($properties['models'] as $model) { foreach ($properties['models'] as $model) {
@ -367,4 +394,37 @@ class IslandoraWebTestCase extends DrupalWebTestCase {
return $object; return $object;
} }
/**
* Deletes all objects created by the given user.
*
* @param object $username
* The user whose objects we'd like to remove.
*
* @return bool
* TRUE on success, FALSE on failure.
*/
public function deleteUserCreatedObjects($username) {
if ($username === $this->configuration['admin_user']) {
$this->fail("This function will under no circumstance attempt deletion of all objects owned by the configured Fedora admin user ({$this->configuration['admin_user']}), as this could irreparably damage the repository.", 'Islandora');
return FALSE;
}
$query = <<<QUERY
SELECT ?object FROM <#ri> WHERE
{
?object <fedora-model:ownerId> "$username"
}
QUERY;
$objects = $this->admin->repository->ri->sparqlQuery($query);
foreach ($objects as $object) {
$loaded_object = islandora_object_load($object['object']['value']);
islandora_delete_object($loaded_object);
if ($this->assertFalse(islandora_object_load($object['object']['value']), "Object {$object['object']['value']} successfully removed from repository.", 'Islandora')) {
return FALSE;
}
return TRUE;
}
}
} }

2
tests/scripts/travis_setup.sh

@ -19,7 +19,7 @@ pear channel-discover pear.drush.org
pear channel-discover pear.drush.org pear channel-discover pear.drush.org
pear channel-discover pear.phpqatools.org pear channel-discover pear.phpqatools.org
pear channel-discover pear.netpirates.net pear channel-discover pear.netpirates.net
pear install pear/PHP_CodeSniffer pear install pear/PHP_CodeSniffer-1.4.8
pear install pear.phpunit.de/phpcpd pear install pear.phpunit.de/phpcpd
pear install drush/drush-5.9.0 pear install drush/drush-5.9.0
phpenv rehash phpenv rehash

18
theme/islandora-object-img-print.tpl.php

@ -1,18 +0,0 @@
<?php
/**
* @file
* The default view to theme an image of an object.
*
* This view is passed into 'islandora-object-print' theme file
* and is rendred as an image. Allows for seperate theming of image
* and metadata.
*
*/
?>
<?php if (isset($islandora_content)): ?>
<div>
<?php print $islandora_content; ?>
</div>
<?php endif; ?>

27
theme/theme.inc

@ -25,7 +25,7 @@ function islandora_preprocess_islandora_default_edit(array &$variables) {
$header[] = array('data' => t('Versions')); $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')); $table_attributes = array('class' => array('manage-datastreams'));
$rows = array(); $rows = array();
@ -53,7 +53,7 @@ function islandora_preprocess_islandora_default_edit(array &$variables) {
'class' => 'datastream-size', 'class' => 'datastream-size',
'data' => islandora_datastream_get_human_readable_size($ds), '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( $row[] = array(
'class' => 'datastream-versions', 'class' => 'datastream-versions',
'data' => theme('islandora_datastream_version_link', array( 'data' => theme('islandora_datastream_version_link', array(
@ -79,6 +79,12 @@ function islandora_preprocess_islandora_default_edit(array &$variables) {
'datastream' => $ds, 'datastream' => $ds,
)), )),
); );
$row[] = array(
'class' => 'datastream-regenerate',
'data' => theme('islandora_datastream_regenerate_link', array(
'datastream' => $ds,
)),
);
$rows[] = $row; $rows[] = $row;
} }
$caption = filter_xss($islandora_object->label) . ' - ' . $islandora_object->id; $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(). * Implements hook_preprocess().
*/ */

Loading…
Cancel
Save