diff --git a/README.md b/README.md index 0515a848..798e6b33 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,11 @@ https://jira.duraspace.org/browse/ISLANDORA REQUIREMENTS ------------ - +The Tuque library must be installed to use Islandora. It can be found here: +http://github.com/Islandora/tuque +It is expected to be in one of two paths: + - sites/all/libraries/tuque (libraries directory may need to be created) + - islandora_folder/libraries/tuque INSTALLATION ------------ diff --git a/includes/add_datastream.form.inc b/includes/add_datastream.form.inc index d19d5757..62490c9a 100644 --- a/includes/add_datastream.form.inc +++ b/includes/add_datastream.form.inc @@ -12,13 +12,13 @@ * The Drupal form. * @param array $form_state * The Drupal form state. - * @param FedoraObject $object + * @param AbstractObject $object * The object to be deleted. * * @return array * The drupal form definition. */ -function islandora_add_datastream_form(array $form, array &$form_state, FedoraObject $object) { +function islandora_add_datastream_form(array $form, array &$form_state, AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/content_model'); module_load_include('inc', 'islandora', 'includes/utilities'); form_load_include($form_state, 'inc', 'islandora', 'includes/add_datastream.form'); @@ -206,13 +206,13 @@ function islandora_add_datastream_form_submit(array $form, array &$form_state) { * * It lists the missing required (may be optional) datastreams. * - * @param FedoraObject $object + * @param AbstractObject $object * The object used to check for missing required datastreams used to populate * the options in this callback. * @param string $query * vThe user query to match against the missing required datastreams. */ -function islandora_add_datastream_form_autocomplete_callback(FedoraObject $object, $query = '') { +function islandora_add_datastream_form_autocomplete_callback(AbstractObject $object, $query = '') { module_load_include('inc', 'islandora', 'includes/content_model'); module_load_include('inc', 'islandora', 'includes/utilities'); $dsids = array_keys(islandora_get_missing_datastreams_requirements($object)); diff --git a/includes/breadcrumb.inc b/includes/breadcrumb.inc index 9db4824c..872eb70a 100644 --- a/includes/breadcrumb.inc +++ b/includes/breadcrumb.inc @@ -14,7 +14,7 @@ * ancestry which is identified by any of the following RELS-EXT terms * (isMemberOf,isMemberOfCollection,isPartOf). * - * @param FedoraObject $object + * @param AbstractObject $object * An object whose ancestry will be mapped to bread-crumbs. * * @see drupal_set_breadcrumb() @@ -57,10 +57,21 @@ function islandora_get_breadcrumbs_recursive($pid, FedoraRepository $repository, $root = variable_get('islandora_repository_pid', 'islandora:root'); if ($pid == $root) { - $item = menu_get_item('islandora'); + $title = 'Islandora Repository'; + $mlid = db_select('menu_links', 'ml') + ->condition('ml.link_path', 'islandora') + ->fields('ml', array('mlid')) + ->execute() + ->fetchField(); + + if ($mlid) { + $link = menu_link_load($mlid); + $title = (isset($link['title']) ? $link['title'] : $title); + } + return array( l(t('Home'), ''), - l($item['title'], 'islandora'), + l($title, 'islandora'), ); } else { diff --git a/includes/content_model.autocomplete.inc b/includes/content_model.autocomplete.inc new file mode 100644 index 00000000..67923e9e --- /dev/null +++ b/includes/content_model.autocomplete.inc @@ -0,0 +1,57 @@ + $label) { + if (preg_match("/{$string}/i", $label) !== 0) { + $output[$model] = $label; + } + } + return drupal_json_output($output); +} + +/** + * Gets a map of form names suitable for use as select #options. + */ +function islandora_get_content_model_names() { + module_load_include('inc', 'islandora', 'includes/utilities'); + $results = islandora_get_content_models(); + $ret = array(); + foreach ($results as $result) { + $ret[$result['pid']] = "{$result['label']} ({$result['pid']})"; + } + return $ret; +} + +/** + * Minor array transformation. + * + * @param array $content + * The array of results as returned from Tuque's RI query interface. + * + * @return array + * An array of results in a more usable format. + */ +function islandora_parse_query($content) { + $content_models = array(); + foreach ($content as $model) { + $content_models[] = $model['object']['value']; + } + $content_models = array_unique($content_models); + $content_models = array_values($content_models); + return $content_models; +} diff --git a/includes/datastream.inc b/includes/datastream.inc index b817b70d..23eb44f9 100644 --- a/includes/datastream.inc +++ b/includes/datastream.inc @@ -8,10 +8,10 @@ /** * Callback to download the given datastream to the users computer. * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to download. */ -function islandora_download_datastream(FedoraDatastream $datastream) { +function islandora_download_datastream(AbstractDatastream $datastream) { islandora_view_datastream($datastream, TRUE); } @@ -21,13 +21,13 @@ function islandora_download_datastream(FedoraDatastream $datastream) { * @note * This function calls exit(). * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to view/download. * @param bool $download * If TRUE the file is download to the user computer for viewing otherwise it * will attempt to display in the browser natively. */ -function islandora_view_datastream(FedoraDatastream $datastream, $download = FALSE) { +function islandora_view_datastream(AbstractDatastream $datastream, $download = FALSE) { header_remove('Cache-Control'); header_remove('Expires'); header('Content-type: ' . $datastream->mimetype); @@ -51,14 +51,14 @@ function islandora_view_datastream(FedoraDatastream $datastream, $download = FAL /** * Get the human readable size of the given datastream. * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to check. * * @return string * A human readable size of the given datastream, or '-' if the size could not * be determined. */ -function islandora_datastream_get_human_readable_size(FedoraDatastream $datastream) { +function islandora_datastream_get_human_readable_size(AbstractDatastream $datastream) { module_load_include('inc', 'islandora', 'includes/utilities'); $size_is_calculatable = $datastream->controlGroup == 'M' || $datastream->controlGroup == 'X'; return $size_is_calculatable ? islandora_convert_bytes_to_human_readable($datastream->size) : '-'; @@ -67,23 +67,23 @@ function islandora_datastream_get_human_readable_size(FedoraDatastream $datastre /** * Get either the 'view' or 'download' url for the given datastream if possible. * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to generated the url to. * * @return string * either the 'view' or 'download' url for the given datastream. */ -function islandora_datastream_get_url(FedoraDatastream $datastream, $type = 'download') { +function islandora_datastream_get_url(AbstractDatastream $datastream, $type = 'download') { return $datastream->controlGroup == 'R' ? $datastream->url : "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/$type"; } /** * Gets the delete link. * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to generated the url to. */ -function islandora_datastream_get_delete_link(FedoraDatastream $datastream) { +function islandora_datastream_get_delete_link(AbstractDatastream $datastream) { $datastreams = module_invoke_all('islandora_undeletable_datastreams', $datastream->parent->models); $can_delete = !in_array($datastream->id, $datastreams); return $can_delete ? l(t('delete'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete") : ''; @@ -92,10 +92,10 @@ function islandora_datastream_get_delete_link(FedoraDatastream $datastream) { /** * Gets the edit link. * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to generated the url to. */ -function islandora_datastream_edit_get_link(FedoraDatastream $datastream) { +function islandora_datastream_edit_get_link(AbstractDatastream $datastream) { $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream); $can_edit = count($edit_registry) > 0 && user_access(FEDORA_METADATA_EDIT); return $can_edit ? l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") : ''; @@ -104,10 +104,10 @@ function islandora_datastream_edit_get_link(FedoraDatastream $datastream) { /** * Display the edit datastream page. * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to edit. */ -function islandora_edit_datastream(FedoraDatastream $datastream) { +function islandora_edit_datastream(AbstractDatastream $datastream) { $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream); $edit_count = count($edit_registry); switch ($edit_count) { diff --git a/includes/delete_datastream.form.inc b/includes/delete_datastream.form.inc index faf92a18..b94e0141 100644 --- a/includes/delete_datastream.form.inc +++ b/includes/delete_datastream.form.inc @@ -12,13 +12,13 @@ * The Drupal form. * @param array $form_state * The Drupal form state. - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to be deleted. * * @return array * The drupal form definition. */ -function islandora_delete_datastream_form(array $form, array &$form_state, FedoraDatastream $datastream) { +function islandora_delete_datastream_form(array $form, array &$form_state, AbstractDatastream $datastream) { $form_state['datastream'] = $datastream; return confirm_form($form, t('Are you sure you want to delete the %dsid datastream?', array('%dsid' => $datastream->id)), @@ -32,7 +32,7 @@ function islandora_delete_datastream_form(array $form, array &$form_state, Fedor /** * Submit handler for the delete datastream form. * - * Purges/Delete's the given FedoraDatastream if possible. + * Purges/Delete's the given AbstractDatastream if possible. * * The ISLANDORA_PRE_PURGE_DATASTREAM_HOOK will query other modules as to * whether the given FedoraDatastream diff --git a/includes/delete_object.form.inc b/includes/delete_object.form.inc index 46210e3c..4b893074 100644 --- a/includes/delete_object.form.inc +++ b/includes/delete_object.form.inc @@ -12,13 +12,13 @@ * The Drupal form. * @param array $form_state * The Drupal form state. - * @param FedoraObject $object + * @param AbstractObject $object * The object to be deleted. * * @return array * The drupal form definition. */ -function islandora_delete_object_form(array $form, array &$form_state, FedoraObject $object) { +function islandora_delete_object_form(array $form, array &$form_state, AbstractObject $object) { $form_state['object'] = $object; return confirm_form($form, t('Are you sure you want to delete %title?', array('%title' => $object->label)), diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 5c9e3e55..00783934 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -5,6 +5,25 @@ * Defines the multi-page ingest form and any relevant hooks and functions. */ +/** + * Checks if the given configuration can be used to display the ingest form. + * + * @param array $configuration + * The list of key/value pairs of configuration. + * + * @return bool + * TRUE if the give configuration defines one or more form steps, FALSE + * otherwise. + */ +function islandora_ingest_can_display_ingest_form(array $configuration) { + $form_state = array(); + islandora_ingest_form_init_form_state_storage($form_state, $configuration); + $form_steps = islandora_ingest_form_get_form_steps($form_state); + // Forget the stubbed steps for the remainder of this request. + drupal_static_reset('islandora_ingest_form_get_steps'); + return count($form_steps) > 0; +} + /** * Ingest form build function. * @@ -44,26 +63,6 @@ function islandora_ingest_form(array $form, array &$form_state, array $configura } } -/** - * Validates the given ingest configuration. - * - * At the moment it only requires that models are present. - * - * @todo Add hook for manipulating/validating the configuration. - * - * @see islandora_ingest_form() - * - * @throws InvalidArgumentException - * - * @param array $configuration - * The key value pairs that are used to build the multi-paged ingest process. - */ -function islandora_ingest_form_validate_configuration(array $configuration) { - if (empty($configuration['models'])) { - throw new InvalidArgumentException('Ingest configuration not vaild, no models were given'); - } -} - /** * Initializes the form_state storage for use in the ingest multi-page forms. * @@ -75,12 +74,23 @@ function islandora_ingest_form_validate_configuration(array $configuration) { */ function islandora_ingest_form_init_form_state_storage(array &$form_state, array $configuration) { if (empty($form_state['islandora'])) { - // Validate the configuration before we use it. - islandora_ingest_form_validate_configuration($configuration); - $object = islandora_ingest_form_prepare_new_object($configuration); + $objects = isset($configuration['objects']) ? $configuration['objects'] : array(); + if (empty($objects)) { + $objects[] = islandora_ingest_form_prepare_new_object($configuration); + } + $configuration['models'] = isset($configuration['models']) ? $configuration['models'] : array(); + // Make sure the models actually exist. + foreach ($configuration['models'] as $key => $model) { + if (!islandora_object_load($model)) { + unset($configuration['models'][$key]); + } + } + // No need to persist the 'objects' within the configuration. + unset($configuration['objects']); + // Required for step hooks. $form_state['islandora'] = array( 'step_id' => NULL, - 'objects' => array($object), + 'objects' => $objects, 'shared_storage' => $configuration, 'step_storage' => array(), ); @@ -132,6 +142,8 @@ function islandora_ingest_form_get_last_step_id(array &$form_state) { function islandora_ingest_form_prepare_new_object(array $configuration) { module_load_include('inc', 'islandora', 'includes/utilities'); if (empty($configuration['object'])) { + $message = islandora_deprecated('7.x-1.2', t('Please use "objects" as the default ingest form configuration property.')); + trigger_error(filter_xss($message), E_USER_DEPRECATED); // ID is more specific than namespace so it will take precedence. $id = isset($configuration['namespace']) ? $configuration['namespace'] : 'islandora'; $id = isset($configuration['id']) ? $configuration['id'] : $id; @@ -307,35 +319,6 @@ function islandora_ingest_form_decrement_step(array &$form_state) { } } -/** - * Build a list of steps given only configuration. - * - * XXX: This is used to give an indication of whether there are any steps for a - * given configuration. - * - * @param array $configuration - * The list of key/value pairs of configuration. - */ -function islandora_ingest_get_approximate_steps(array $configuration) { - try { - // @todo, we need to expand the configuration before we can validate it? - // I think this need some thinking. - islandora_ingest_form_validate_configuration($configuration); - } - catch (InvalidArgumentException $e) { - // Don't log or display exception. - return array(); - } - $stubbed_form_state = array( - 'islandora' => array( - 'shared_storage' => $configuration, - ), - ); - $steps = islandora_ingest_form_get_steps($stubbed_form_state); - drupal_static_reset('islandora_ingest_form_get_steps'); - return $steps; -} - /** * Executes the current step. * @@ -387,7 +370,15 @@ function islandora_ingest_form_execute_step(array $form, array &$form_state, $st function islandora_ingest_form_execute_form_step(array $form, array &$form_state, array $step) { $args = array($form, &$form_state); $args = isset($step['args']) ? array_merge($args, $step['args']) : $args; + $shared_storage = islandora_ingest_form_get_shared_storage($form_state); + // Build the form step. $form = call_user_func_array($step['form_id'], $args); + // Since the list of steps depends on the shared storage we will rebuild the + // list of steps if the shared storage has changed. This must be done before + // stepifying, so the prev/next buttons get updated. + if ($shared_storage != islandora_ingest_form_get_shared_storage($form_state)) { + drupal_static_reset('islandora_ingest_form_get_steps'); + } return islandora_ingest_form_stepify($form, $form_state, $step); } @@ -473,6 +464,10 @@ function islandora_ingest_form_undo_callback_step(array $form, array &$form_stat function islandora_ingest_form_stepify(array $form, array &$form_state, $step) { $first_form_step = islandora_ingest_form_on_first_form_step($form_state); $last_form_step = islandora_ingest_form_on_last_form_step($form_state); + $form['form_step_id'] = array( + '#type' => 'hidden', + '#value' => islandora_ingest_form_get_current_step_id($form_state), + ); $form['prev'] = $first_form_step ? NULL : islandora_ingest_form_previous_button($form_state); $form['next'] = $last_form_step ? islandora_ingest_form_ingest_button($form_state) : islandora_ingest_form_next_button($form_state); // Allow for a hook_form_FORM_ID_alter(). @@ -557,7 +552,7 @@ function islandora_ingest_form_previous_button(array &$form_state) { $prev_form_step = islandora_ingest_form_get_previous_form_step($form_state); $form_id = $prev_form_step['form_id']; $submit_callback = $form_id . '_undo_submit'; - $submit = function_exists($submit_callback) ? array($submit_callback, 'islandora_ingest_form_previous_submit') : array('islandora_ingest_form_previous_submit'); + $submit = function_exists($submit_callback) ? array('islandora_ingest_form_previous_submit', $submit_callback) : array('islandora_ingest_form_previous_submit'); return array( '#type' => 'submit', '#value' => t('Previous'), @@ -648,7 +643,7 @@ function islandora_ingest_form_next_submit(array $form, array &$form_state) { */ function islandora_ingest_form_stash_info(array &$form_state) { $storage = &islandora_ingest_form_get_step_storage($form_state); - if ($storage) { + if ($storage && isset($form_state['values'])) { $storage['values'] = $form_state['values']; unset($form_state['values']); } @@ -754,7 +749,7 @@ function &islandora_ingest_form_get_objects(array &$form_state) { */ function islandora_ingest_form_get_object(array &$form_state) { $objects = &islandora_ingest_form_get_objects($form_state); - return current($objects); + return reset($objects); } /** @@ -854,3 +849,39 @@ function islandora_ingest_form_get_steps(array &$form_state) { uasort($steps, 'drupal_sort_weight'); return $steps; } + +/** + * Filter the ingest steps to only steps of type 'form'. + * + * @param array $form_state + * The Drupal form state. + * + * @return array + * The list of sorted ingest form steps as defined by all implementers + * of ISLANDORA_INGEST_STEP_HOOK. + */ +function islandora_ingest_form_get_form_steps(array &$form_state) { + $steps = islandora_ingest_form_get_steps($form_state); + $form_step_filter = function($o) { + return $o['type'] == 'form'; + }; + return array_filter($steps, $form_step_filter); +} + +/** + * Filter the ingest steps to only steps of type 'form'. + * + * @param array $form_state + * The Drupal form state. + * + * @return array + * The list of sorted ingest callback steps as defined by all implementers + * of ISLANDORA_INGEST_STEP_HOOK. + */ +function islandora_ingest_form_get_callback_steps(array &$form_state) { + $steps = islandora_ingest_form_get_steps($form_state); + $callback_step_filter = function($o) { + return $o['type'] == 'callback'; + }; + return array_filter($steps, $callback_step_filter); +} diff --git a/includes/mime_detect.inc b/includes/mime_detect.inc index 0914f62b..13b66cc8 100644 --- a/includes/mime_detect.inc +++ b/includes/mime_detect.inc @@ -148,7 +148,7 @@ class MimeDetect { "jp2" => "image/jp2", "png" => "image/png", "tiff" => "image/tiff", - "tif" => "image/tif", + "tif" => "image/tiff", "djvu" => "image/vnd.djvu", "djv" => "image/vnd.djvu", "wbmp" => "image/vnd.wap.wbmp", @@ -194,6 +194,11 @@ class MimeDetect { 'bin' => 'application/octet-stream', ); protected $protectedFileExtensions; + protected $extensionExceptions = array( + // XXX: Deprecated... Only here due to old 'tif' => 'image/tif' mapping... + // The correct MIMEtype is 'image/tiff'. + 'image/tif' => 'tif', + ); protected $systemTypes; protected $systemExts; protected $etcMimeTypes = '/etc/mime.types'; @@ -205,6 +210,7 @@ class MimeDetect { // Populate the reverse shortlist: $this->protectedFileExtensions = array_flip($this->protectedMimeTypes); + $this->protectedFileExtensions += $this->extensionExceptions; // Pick up a local mime.types file if it is available. if (is_readable('mime.types')) { @@ -366,4 +372,14 @@ class MimeDetect { return $out; } + /** + * Gets MIME type array. + * + * @return array + * Returns associative array with exts and mimetypes. + */ + public function getMimeTypes() { + return $this->protectedMimeTypes; + } + } diff --git a/includes/object_properties.form.inc b/includes/object_properties.form.inc index c9de5e8f..543fa6dd 100644 --- a/includes/object_properties.form.inc +++ b/includes/object_properties.form.inc @@ -12,13 +12,13 @@ * The Drupal form. * @param array $form_state * The Drupal form state. - * @param FedoraObject $object + * @param AbstractObject $object * The object whose properties this form will modify. * * @return array * The drupal form definition. */ -function islandora_object_properties_form(array $form, array &$form_state, FedoraObject $object) { +function islandora_object_properties_form(array $form, array &$form_state, AbstractObject $object) { drupal_set_title($object->label); $form_state['object'] = $object; return array( diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index aa09c8a4..26bd77b5 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -180,12 +180,12 @@ function islandora_solution_pack_form_submit(array $form, array &$form_state) { /** * Batch operation to ingest/reingest required object(s). * - * @param NewFedoraObject $object + * @param AbstractObject $object * The object to ingest/reingest. * @param array $context * The context of this batch operation. */ -function islandora_solution_pack_batch_operation_reingest_object(NewFedoraObject $object, array &$context) { +function islandora_solution_pack_batch_operation_reingest_object(AbstractObject $object, array &$context) { $existing_object = islandora_object_load($object->id); $deleted = FALSE; if ($existing_object) { @@ -367,7 +367,7 @@ function islandora_uninstall_solution_pack($module) { /** * Function to check the status of an object against an object model array. * - * @param NewFedoraObject $object_definition + * @param AbstractObject $object_definition * A new fedora object that defines what the object should contain. * * @return string @@ -378,7 +378,7 @@ function islandora_uninstall_solution_pack($module) { * @see islandora_solution_pack_form() * @see islandora_install_solution_pack() */ -function islandora_check_object_status(NewFedoraObject $object_definition) { +function islandora_check_object_status(AbstractObject $object_definition) { $existing_object = islandora_object_load($object_definition->id); if (!$existing_object) { return array('status' => 'missing', 'status_friendly' => t('Missing')); @@ -627,7 +627,7 @@ function theme_islandora_viewers_table($variables) { * Array or string with data the module needs in order to render a full viewer * @param string $variable_id * The id of the Drupal variable the viewer settings are saved in - * @param FedoraObject $fedora_object + * @param AbstractObject $fedora_object * The tuque object representing the fedora object being displayed * * @return string diff --git a/includes/tuque_wrapper.inc b/includes/tuque_wrapper.inc index 14a770e2..8563070f 100644 --- a/includes/tuque_wrapper.inc +++ b/includes/tuque_wrapper.inc @@ -34,7 +34,7 @@ $islandora_module_path = drupal_get_path('module', 'islandora'); /** * Allow modules to alter an object before a mutable event occurs. */ -function islandora_alter_object(AbstractFedoraObject $object, array &$context) { +function islandora_alter_object(AbstractObject $object, array &$context) { module_load_include('inc', 'islandora', 'includes/utilities'); drupal_alter(islandora_build_hook_list('islandora_object', $object->models), $object, $context); } @@ -42,7 +42,7 @@ function islandora_alter_object(AbstractFedoraObject $object, array &$context) { /** * Allow modules to alter a datastream before a mutable event occurs. */ -function islandora_alter_datastream(AbstractFedoraObject $object, AbstractDatastream $datastream, array &$context) { +function islandora_alter_datastream(AbstractObject $object, AbstractDatastream $datastream, array &$context) { module_load_include('inc', 'islandora', 'includes/utilities'); $types = array(); foreach ($object->models as $model) { diff --git a/includes/utilities.inc b/includes/utilities.inc index fbc4585a..32b05158 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -256,8 +256,8 @@ function islandora_get_namespace($id) { */ function islandora_namespace_accessible($id) { if (variable_get('islandora_namespace_restriction_enforced', FALSE)) { - $namespace = islandora_get_namespace($id) . ':'; - $allowed_namespaces = explode(" ", variable_get('islandora_pids_allowed', 'default: demo: changeme: islandora: ilives: islandora-book: books: newspapers: ')); + $namespace = islandora_get_namespace($id); + $allowed_namespaces = islandora_get_allowed_namespaces(); return in_array($namespace, $allowed_namespaces); } return TRUE; @@ -271,14 +271,14 @@ function islandora_namespace_accessible($id) { * This function gets its info from the RELS-EXT directly rather than through an * risearch. * - * @param FedoraObject $object + * @param AbstractObject $object * The object whose parents will be returned. * * @return array * An array of FedoraObject's that the given object has a * (isMemberOf, isMemberOfCollection) relationship with. */ -function islandora_get_parents_from_rels_ext(FedoraObject $object) { +function islandora_get_parents_from_rels_ext(AbstractObject $object) { try { $collections = array_merge( $object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOfCollection'), @@ -298,7 +298,7 @@ function islandora_get_parents_from_rels_ext(FedoraObject $object) { /** * Gets the datastreams requirments that are missing. * - * @param FedoraObject $object + * @param AbstractObject $object * The object which models will be used to determine what datastreams it * should have. * @@ -306,7 +306,7 @@ function islandora_get_parents_from_rels_ext(FedoraObject $object) { * The DS-COMPOSITE-MODEL defined datastreams that are required for the given * object, but not already present. */ -function islandora_get_missing_datastreams_requirements(FedoraObject $object) { +function islandora_get_missing_datastreams_requirements(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/utilities'); $datastreams = islandora_get_datastreams_requirements($object); foreach ($datastreams as $dsid => $requirements) { @@ -331,7 +331,7 @@ function islandora_get_missing_datastreams_requirements(FedoraObject $object) { * * @see islandora_get_required_datastreams_from_content_model() * - * @param FedoraObject $object + * @param AbstractObject $object * The object which models will be used to determine what datastreams it * should have. * @@ -339,7 +339,7 @@ function islandora_get_missing_datastreams_requirements(FedoraObject $object) { * The DS-COMPOSITE-MODEL defined datastreams that are required for the given * object. */ -function islandora_get_datastreams_requirements(FedoraObject $object) { +function islandora_get_datastreams_requirements(AbstractObject $object) { return islandora_get_datastreams_requirements_from_models($object->models); } @@ -375,7 +375,7 @@ function islandora_get_datastreams_requirements_from_models(array $models) { * * @todo Add support for fetching the schema information. * - * @param FedoraObject $object + * @param AbstractObject $object * The content model whose DS-COMPOSITE-MODEL datastream will be used to * determine what datastreams are required. * @@ -388,7 +388,7 @@ function islandora_get_datastreams_requirements_from_models(array $models) { * - "mime": A array containing MIME-types the stream may have. * - "optional": A boolean indicating if the given stream is optional. */ -function islandora_get_datastreams_requirements_from_content_model(FedoraObject $object) { +function islandora_get_datastreams_requirements_from_content_model(AbstractObject $object) { if (empty($object[DS_COMP_STREAM])) { return array(); } @@ -636,6 +636,9 @@ function islandora_system_settings_form_default_value($name, $default_value, arr * is optional. */ function islandora_get_comp_ds_mappings($pid) { + $message = islandora_deprecated('7.x-1.2', t('Refactor to use the more flexible islandora_get_datastreams_requirements_from_content_model().')); + trigger_error(filter_xss($message), E_USER_DEPRECATED); + $cm_object = islandora_object_load($pid); if (!isset($cm_object) || !isset($cm_object['DS-COMPOSITE-MODEL'])) { return FALSE; @@ -709,7 +712,13 @@ function islandora_get_allowed_namespaces() { $matches = array(); $allowed_namespaces = variable_get('islandora_pids_allowed', 'default: demo: changeme: islandora:'); preg_match_all('/([A-Za-z0-9-\.]+):/', $allowed_namespaces, $matches); - return $matches[1]; + $accessible_namespaces = $matches[1]; + // Ensure that the "islandora" namespace is explicitly allowed + // no matter what happens. + if (!in_array('islandora', $accessible_namespaces)) { + $accessible_namespaces[] = 'islandora'; + } + return $accessible_namespaces; } /** @@ -817,3 +826,36 @@ function islandora_content_model_select_table_form_element($drupal_variable, $de return $element; } + +/** + * Convience function for generating a E_USER_DEPRECATED message. + * + * To utilitize this function pass the results to trigger_error() like so: + * + * @code + * $message = islandora_deprecated('7.x-1.1', t('Use more cowbell.')) + * trigger_error(filter_xss($message), E_USER_DEPRECATED) + * @endcode + * + * @param string $release + * The release the calling function was depreciated in. + * @param string $solution + * A message describing an alternative solution to the deprecated function. + * It's assumed to be already passed though the t() function. + * + * @return string + * The deprecated message. + */ +function islandora_deprecated($release, $solution = NULL) { + $bt = debug_backtrace(); + assert($bt[0]['function'] == __FUNCTION__); + $function = $bt[1]['function']; + $message = t('@function() has been deprecated. As of @release, please update your code before the next release.', array( + '@function' => $function, + '@release' => $release, + )); + if (isset($solution)) { + $message .= "
\n" . $solution; + } + return $message; +} diff --git a/islandora.api.php b/islandora.api.php index 17db59ad..89e1e048 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -8,7 +8,7 @@ /** * Generate a repository objects view. * - * @param FedoraObject $object + * @param AbstractObject $object * The object to display * @param object $user * The user accessing the object. @@ -29,7 +29,7 @@ function hook_islandora_view_object($object, $user, $page_number, $page_size) { * Content models PIDs have colons and hyphens changed to underscores, to * create the hook name. * - * @param FedoraObject $object + * @param AbstractObject $object * A Tuque FedoraObject * * @return array @@ -42,8 +42,8 @@ function hook_CMODEL_PID_islandora_view_object($object) { /** * Alter display output after it has been generated. * - * @param FedoraObject $object - * A Tuque FedoraObject being operated on. + * @param AbstractObject $object + * A Tuque AbstractObject being operated on. * @param array $rendered * The array of rendered views. */ @@ -55,8 +55,8 @@ function hook_islandora_view_object_alter(&$object, &$rendered) { * * @see hook_islandora_view_object_alter() * - * @param FedoraObject $object - * A Tuque FedoraObject being operated on. + * @param AbstractObject $object + * A Tuque AbstractObject being operated on. * @param array $rendered * The array of rendered views. */ @@ -66,7 +66,7 @@ function hook_CMODEL_PID_islandora_view_object_alter(&$object, &$rendered) { /** * Generate an object's management display. * - * @param FedoraObject $object + * @param AbstractObject $object * A Tuque FedoraObject * * @return array @@ -81,7 +81,7 @@ function hook_islandora_edit_object($object) { * Content models PIDs have colons and hyphens changed to underscores, to * create the hook name. * - * @param FedoraObject $object + * @param AbstractObject $object * A Tuque FedoraObject * * @return array @@ -93,7 +93,7 @@ function hook_CMODEL_PID_islandora_edit_object($object) { /** * Allow management display output to be altered. * - * @param FedoraObject $object + * @param AbstractObject $object * A Tuque FedoraObject * @param array $rendered * an arr of rendered views @@ -110,7 +110,7 @@ function hook_islandora_edit_object_alter(&$object, &$rendered) { * Changing object properties such as "label", or "state", are considered * modifications, where as manipulating an object's datstreams are not. * - * @param AbstractFedoraObject $object + * @param AbstractObject $object * The object to alter. * @param array $context * An associative array containing: @@ -130,7 +130,7 @@ function hook_islandora_edit_object_alter(&$object, &$rendered) { * * @see FedoraApiM::modifyObject() */ -function hook_islandora_object_alter(AbstractFedoraObject $object, array &$context) { +function hook_islandora_object_alter(AbstractObject $object, array &$context) { } /** @@ -138,7 +138,7 @@ function hook_islandora_object_alter(AbstractFedoraObject $object, array &$conte * * @see hook_islandora_object_alter() */ -function hook_CMODEL_PID_islandora_object_alter(AbstractFedoraObject $object, array &$context) { +function hook_CMODEL_PID_islandora_object_alter(AbstractObject $object, array &$context) { } /** @@ -151,15 +151,15 @@ function hook_CMODEL_PID_islandora_object_alter(AbstractFedoraObject $object, ar * immediately, instead it will be triggered for all datastreams at the time * of the NewFedoraObject's ingest. * - * Purging datastreams from a NewFedoraObject will not trigger this alter hook + * Purging datastreams from a AbstractObject will not trigger this alter hook * at all. * * Changing datastream's properties such as "label", or "state", are considered * modifications, as well as changing the datastreams content. * - * @param AbstractFedoraObject $object + * @param AbstractObject $object * The object to the datastream belong to. - * @param AbstractFedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to alter. * @param array $context * An associative array containing: @@ -179,7 +179,7 @@ function hook_CMODEL_PID_islandora_object_alter(AbstractFedoraObject $object, ar * * @see FedoraApiM::modifyDatastream() */ -function hook_islandora_datastream_alter(AbstractFedoraObject $object, AbstractFedoraDatastream $datastream, array &$context) { +function hook_islandora_datastream_alter(AbstractObject $object, AbstractDatastream $datastream, array &$context) { } /** @@ -187,7 +187,7 @@ function hook_islandora_datastream_alter(AbstractFedoraObject $object, AbstractF * * @see hook_islandora_datastream_alter() */ -function hook_CMODEL_PID_DSID_islandora_datastream_alter(AbstractFedoraObject $object, AbstractFedoraDatastream $datastream, array &$context) { +function hook_CMODEL_PID_DSID_islandora_datastream_alter(AbstractObject $object, AbstractDatastream $datastream, array &$context) { } /** @@ -200,10 +200,10 @@ function hook_CMODEL_PID_DSID_islandora_datastream_alter(AbstractFedoraObject $o * If ingested directly via the FedoraApiM object this will not be called as we * don't have access to the ingested object at that time. * - * @param FedoraObject $object + * @param AbstractObject $object * The object that was ingested. */ -function hook_islandora_object_ingested(FedoraObject $object) { +function hook_islandora_object_ingested(AbstractObject $object) { } /** @@ -211,7 +211,7 @@ function hook_islandora_object_ingested(FedoraObject $object) { * * @see hook_islandora_object_ingested() */ -function hook_CMODEL_PID_islandora_object_ingested(FedoraObject $object) { +function hook_CMODEL_PID_islandora_object_ingested(AbstractObject $object) { } /** @@ -222,13 +222,13 @@ function hook_CMODEL_PID_islandora_object_ingested(FedoraObject $object) { * Changing object properties such as "label", or "state", are considered * modifications, where as manipulating an object's datstreams are not. * - * @param FedoraObject $object + * @param AbstractObject $object * The object that was ingested. * * @todo We should also include what changes were made in a additional * parameter. */ -function hook_islandora_object_modified(FedoraObject $object) { +function hook_islandora_object_modified(AbstractObject $object) { } /** @@ -236,7 +236,7 @@ function hook_islandora_object_modified(FedoraObject $object) { * * @see hook_islandora_object_modified() */ -function hook_CMODEL_PID_islandora_object_modified(FedoraObject $object) { +function hook_CMODEL_PID_islandora_object_modified(AbstractObject $object) { } /** @@ -268,12 +268,12 @@ function hook_CMODEL_PID_islandora_object_purged($pid) { * If ingested directly via the FedoraApiM object this will not be called as we * don't have access to the ingested datastream at that time. * - * @param FedoraObject $object + * @param AbstractObject $object * The object the datastream belongs to. - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The ingested datastream. */ -function hook_islandora_datastream_ingested(FedoraObject $object, FedoraDatastream $datastream) { +function hook_islandora_datastream_ingested(AbstractObject $object, AbstractDatastream $datastream) { } /** @@ -281,7 +281,7 @@ function hook_islandora_datastream_ingested(FedoraObject $object, FedoraDatastre * * @see hook_islandora_object_ingested() */ -function hook_CMODEL_PID_DSID_islandora_datastream_ingested(FedoraObject $object, FedoraDatastream $datastream) { +function hook_CMODEL_PID_DSID_islandora_datastream_ingested(AbstractObject $object, AbstractDatastream $datastream) { } /** @@ -292,15 +292,15 @@ function hook_CMODEL_PID_DSID_islandora_datastream_ingested(FedoraObject $object * Changing datastream properties such as "label", or "state", are considered * modifications, as well as the datastreams content. * - * @param FedoraObject $object + * @param AbstractObject $object * The object the datastream belongs to. - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream that was ingested. * * @todo We should also include what changes were made in a additional * parameter. */ -function hook_islandora_datastream_modified(FedoraObject $object, FedoraDatastream $datastream) { +function hook_islandora_datastream_modified(AbstractObject $object, AbstractDatastream $datastream) { } /** @@ -308,7 +308,7 @@ function hook_islandora_datastream_modified(FedoraObject $object, FedoraDatastre * * @see hook_islandora_datastream_modified() */ -function hook_CMODEL_PID_islandora_datastream_modified(FedoraObject $object, FedoraDatastream $datastream) { +function hook_CMODEL_PID_islandora_datastream_modified(AbstractObject $object, AbstractDatastream $datastream) { } /** @@ -317,12 +317,12 @@ function hook_CMODEL_PID_islandora_datastream_modified(FedoraObject $object, Fed * This hook is called after an datastream has been successfully purged, or * when its state has been changed to "Deleted". * - * @param FedoraObject $object + * @param AbstractObject $object * The object the datastream belonged to. * @param string $dsid * The ID of the datastream that was purged/deleted. */ -function hook_islandora_datastream_purged(FedoraObject $object, $dsid) { +function hook_islandora_datastream_purged(AbstractObject $object, $dsid) { } /** @@ -330,13 +330,13 @@ function hook_islandora_datastream_purged(FedoraObject $object, $dsid) { * * @see hook_islandora_datastream_purged() */ -function hook_CMODEL_PID_islandora_datastream_purged(FedoraObject $object, $dsid) { +function hook_CMODEL_PID_islandora_datastream_purged(AbstractObject $object, $dsid) { } /** * Register a datastream edit route/form. * - * @param FedoraObject $object + * @param AbstractObject $object * The object to check. * @param string $dsid * todo diff --git a/islandora.info b/islandora.info index e44ec721..4f6a5858 100644 --- a/islandora.info +++ b/islandora.info @@ -11,8 +11,9 @@ files[] = includes/dublin_core.inc files[] = includes/tuque.inc files[] = includes/tuque_wrapper.inc files[] = includes/object.entity_controller.inc -files[] = tests/web_test_case.inc +files[] = tests/islandora_web_test_case.inc files[] = tests/authtokens.test files[] = tests/hooks.test +files[] = tests/ingest.test files[] = tests/islandora_manage_permissions.test php = 5.3 diff --git a/islandora.module b/islandora.module index ad9e569e..32410596 100644 --- a/islandora.module +++ b/islandora.module @@ -52,6 +52,9 @@ define('ISLANDORA_DATASTREAM_MODIFIED_HOOK', 'islandora_datastream_modified'); define('ISLANDORA_DATASTREAM_PURGED_HOOK', 'islandora_datastream_purged'); define('ISLANDORA_INGEST_STEP_HOOK', 'islandora_ingest_steps'); +// Autocomplete paths. +define('ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE', 'islandora/autocomplete/content-models'); + /** * Implements hook_menu(). * @@ -246,6 +249,15 @@ function islandora_menu() { 'access arguments' => array(FEDORA_VIEW_OBJECTS, 2), 'load arguments' => array(2), ); + $items[ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE] = array( + 'title' => 'Autocomplete callback', + 'description' => 'Autocomplete a Fedora content model PID.', + 'file' => 'includes/content_model.autocomplete.inc', + 'page callback' => 'islandora_content_model_autocomplete', + 'page arguments' => array(3), + 'access arguments' => array('administer site configuration'), + 'type' => MENU_CALLBACK, + ); return $items; } @@ -370,7 +382,7 @@ function islandora_forms($form_id) { * @global $user * * @param mixed $object - * The FedoraObject or FedoraDatastream to test for accessibility, if NULL + * The AbstractObject or AbstractDatastream to test for accessibility, if NULL * is given the object is assumed to not exist or be inaccessible. * @param array $permissions * The required user permissions. @@ -448,7 +460,7 @@ function islandora_user_access($object, array $permissions, $content_models = ar * * @param string $perm * User permission to test for. - * @param FedoraObject $object + * @param AbstractObject $object * The object to test, if NULL given the object doesn't exist or is * inaccessible. * @@ -474,10 +486,10 @@ function islandora_object_access_callback($perm, $object = NULL) { * * @param string $perm * The user permission to test for. - * @param FedoraObject $object + * @param AbstractObject $object * The object to test, if NULL given the object doesn't exist or is * inaccessible. - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to test, if NULL given the datastream doesn't exist * or is inaccessible. * @param StdObject $account @@ -525,7 +537,7 @@ function islandora_object_datastream_tokened_access_callback($perm, $object = NU * * @param array $perms * Array of user permission to test for. - * @param FedoraObject $object + * @param AbstractObject $object * The object to test, if NULL given the object doesn't exist or is * inaccessible. * @@ -551,13 +563,13 @@ function islandora_object_manage_access_callback($perms, $object = NULL) { /** * Renders the given objects manage overview page. * - * @param FedoraObject $object + * @param AbstractObject $object * The object to manage. * * @return string * The HTML repersentation of the manage object page. */ -function islandora_manage_overview_object(FedoraObject $object) { +function islandora_manage_overview_object(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/utilities'); $output = array(); foreach (islandora_build_hook_list(ISLANDORA_OVERVIEW_HOOK, $object->models) as $hook) { @@ -578,14 +590,14 @@ function islandora_manage_overview_object(FedoraObject $object) { /** * Renders the default manage object page for the given object. * - * @param FedoraObject $object + * @param AbstractObject $object * The object used to render the manage object page. * * @return array * The default rendering of the object manage page, indexed at * 'Default Edit output'. */ -function islandora_default_islandora_manage_overview_object(FedoraObject $object) { +function islandora_default_islandora_manage_overview_object(AbstractObject $object) { $output = theme('islandora_default_overview', array('islandora_object' => $object)); return array('Default overview output' => $output); } @@ -599,13 +611,13 @@ function islandora_default_islandora_manage_overview_object(FedoraObject $object * If no modules implement 'ISLANDORA_EDIT_HOOK' then this function returns the * default manage view. * - * @param FedoraObject $object + * @param AbstractObject $object * The object to manage. * * @return string * The HTML repersentation of the manage object page. */ -function islandora_edit_object(FedoraObject $object) { +function islandora_edit_object(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); module_load_include('inc', 'islandora', 'includes/utilities'); drupal_set_title($object->label); @@ -629,14 +641,14 @@ function islandora_edit_object(FedoraObject $object) { /** * Renders the default manage object page for the given object. * - * @param FedoraObject $object + * @param AbstractObject $object * The object used to render the manage object page. * * @return array * The default rendering of the object manage page, indexed at * 'Default Edit output'. */ -function islandora_default_islandora_edit_object(FedoraObject $object) { +function islandora_default_islandora_edit_object(AbstractObject $object) { $output = theme('islandora_default_edit', array('islandora_object' => $object)); return array('Default Edit output' => $output); } @@ -661,13 +673,13 @@ function islandora_view_default_object() { * If no modules implement the hook then the default view object page * will be rendered. * - * @param FedoraObject $object + * @param AbstractObject $object * The object to view. * * @return string * The html repersentation of this object. */ -function islandora_view_object(FedoraObject $object) { +function islandora_view_object(AbstractObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); module_load_include('inc', 'islandora', 'includes/utilities'); drupal_set_title($object->label); @@ -697,7 +709,7 @@ function islandora_view_object(FedoraObject $object) { /** * Renders the default view object page for the given object. * - * @param FedoraObject $object + * @param AbstractObject $object * The object used to render the view object page. * * @return array @@ -849,7 +861,7 @@ function islandora_tokened_datastream_load($datastream_id, $map) { * * @param mixed $object_id * The object to load the datastream from. This can be a Fedora PID or - * an instantiated IslandoraFedoraObject as it implements __toString() + * an instantiated IslandoraAbstractObject as it implements __toString() * returning the PID. * * @return FedoraDatastream @@ -872,7 +884,7 @@ function islandora_datastream_load($datastream_id, $object_id) { * attribute, as in: * repository->ingestObject($object); } +/** + * Creates a new object with the same properties as the old. + * + * @todo Make Tuque objects support cloneing. + * + * @param AbstractObject $object + * An existing or new Fedora Object. + * + * @return AbstractObject + * The new Fedora Object with properties identical to the object given. This + * returned object is not automatically ingested. + */ +function islandora_copy_object(AbstractObject $object) { + $clone = $object->repository->constructObject($object->id); + $object_properties = array( + 'state', + 'createdDate', + 'lastModifiedDate', + 'label', + 'owner', + 'logMessage', + ); + // Copy Properties. + foreach ($object_properties as $property) { + if (isset($object->$property)) { + $clone->$property = $object->$property; + } + } + // Copy Datastreams. + foreach ($object as $dsid => $datastream) { + if (empty($clone[$dsid])) { + $clone->ingestDatastream($datastream); + } + else { + // Get the content into a file, and add the file. + $temp_file = drupal_tempnam('temporary://', 'datastream'); + $datastream->getContent($temp_file); + $clone[$dsid]->setContentFromFile($temp_file); + drupal_unlink($temp_file); + } + } + return $clone; +} + /** * Delete's or purges the given object. * - * @param FedoraObject $object + * @param AbstractObject $object * An object to delete. * * @return bool * TRUE if successful, FALSE otherwise. */ -function islandora_delete_object(FedoraObject &$object) { +function islandora_delete_object(AbstractObject &$object) { try { $object->repository->purgeObject($object->id); $object = NULL; @@ -979,13 +1035,13 @@ function islandora_delete_object(FedoraObject &$object) { * Which types are undefined, but more than likely because of the hooks * there will be several kinds. * - * @param FedoraDatastream $datastream + * @param AbstractDatastream $datastream * The datastream to delete. * * @return bool * TRUE if successful, FALSE otherwise. */ -function islandora_delete_datastream(FedoraDatastream &$datastream) { +function islandora_delete_datastream(AbstractDatastream &$datastream) { $object = $datastream->parent; return $object->purgeDatastream($datastream->id); } @@ -1065,7 +1121,7 @@ function islandora_entity_property_info() { * Modules can either implement preprocess functions to append content onto the * 'content' variable, or override the display by providing a theme suggestion. * - * @param FedoraObject $object + * @param AbstractObject $object * The object. * * @return array @@ -1097,3 +1153,20 @@ function islandora_download_clip(AbstractObject $object) { } exit(); } + +/** + * Implements hook_file_mimetype_mapping_alter(). + * + * Grab custom islandora mime type list + * and add any missing ext/mimes to the drupal mapping + */ +function islandora_file_mimetype_mapping_alter(&$mapping) { + $mime_detect = new MimeDetect(); + $types = $mime_detect->getMimeTypes(); + $diff = array_diff_key($types, $mapping['extensions']); + foreach ($diff as $ext => $mime) { + $mapping['mimetypes'][] = $mime; + end($mapping['mimetypes']); + $mapping['extensions'][$ext] = key($mapping['mimetypes']); + } +} diff --git a/islandora.rules.inc b/islandora.rules.inc index 7a97e44a..4045b1b9 100644 --- a/islandora.rules.inc +++ b/islandora.rules.inc @@ -80,7 +80,7 @@ function islandora_rules_action_info() { /** * Checks that there is a relationship match on the given object. * - * Takes a subject (either a FedoraObject or a FedoraDatastream), as well as + * Takes a subject (either a AbstractObject or a FedoraDatastream), as well as * the parameters for FedoraRelsExt::get() or FedoraRelsInt::get(), to try to * find a match. * @@ -94,7 +94,7 @@ function islandora_object_has_relationship($sub, $pred_uri, $pred, $object, $typ /** * Remove a relationship from the given object. * - * Takes a subject (either a FedoraObject or a FedoraDatastream), as well as + * Takes a subject (either a AbstractObject or a FedoraDatastream), as well as * the parameters for FedoraRelsExt::remove() or FedoraRelsInt::remove(), to * try to find a match. * @@ -107,7 +107,7 @@ function islandora_object_remove_relationship($sub, $pred_uri, $pred, $object, $ /** * Add a relationship to the given object. * - * Takes a subject (either a FedoraObject or a FedoraDatastream), as well as + * Takes a subject (either a AbstractObject or a FedoraDatastream), as well as * the parameters for FedoraRelsExt::add() or FedoraRelsInt::add(), and adds * the represented relationship. * diff --git a/tests/README.txt b/tests/README.md similarity index 54% rename from tests/README.txt rename to tests/README.md index c03004ae..c4a0ae1a 100644 --- a/tests/README.txt +++ b/tests/README.md @@ -1,4 +1,4 @@ You can define your own configurations specific to your enviroment by copying default.test_config.ini to test_config.ini, making your changes in the copied -file. These test need write access to the system's $FEDORA_HOME/server/config -directory as well as the filter-drupal.xml file. \ No newline at end of file +file. These test need write access to the system's $FEDORA_HOME/server/config +directory as well as the filter-drupal.xml file. diff --git a/tests/ingest.test b/tests/ingest.test new file mode 100644 index 00000000..173b926f --- /dev/null +++ b/tests/ingest.test @@ -0,0 +1,118 @@ + 'Islandora Ingestion', + 'description' => 'Ensure that the ingest forms function correctly.', + 'group' => 'Islandora', + ); + } + + /** + * Creates an admin user and a connection to a fedora repository. + * + * @see IslandoraWebTestCase::setUp() + */ + public function setUp() { + parent::setUp('islandora_ingest_test'); + $this->repository = $this->admin->repository; + $this->purgeTestObjects(); + + } + + /** + * Free any objects/resources created for this test. + * + * @see IslandoraWebTestCase::tearDown() + */ + public function tearDown() { + $this->purgeTestObjects(); + unset($this->repository); + parent::tearDown(); + } + + /** + * Purge any objects created by the test's in this class. + */ + public function purgeTestObjects() { + $objects = array( + 'test:test', + ); + foreach ($objects as $object) { + try { + $object = $this->repository->getObject($object); + $this->repository->purgeObject($object->id); + } + catch (Exception $e) { + // Meh... Either it didn't exist or the purge failed. + } + } + } + + /** + * Test Ingest Steps. + */ + public function testIngest() { + // Login the Admin user. + $this->drupalLogin($this->admin); + // First step in form. + $this->drupalGet('test/ingest'); + // Default model selected, has no additional steps. + $this->assertFieldByName('ingest', 'Ingest'); + // Select a model with additional steps. + $edit = array( + 'model' => 'test:testcmodel', + ); + $this->drupalPostAJAX(NULL, $edit, 'model'); + // Form now reflexts multiple steps. + $this->assertFieldByName('label', ''); + $this->assertFieldByName('next', 'Next'); + // Move to next step. + $edit = array( + 'label' => 'foobar', + 'model' => 'test:testcmodel', + ); + $this->drupalPost(NULL, $edit, t('Next')); + $this->assertFieldByName('form_step_id', 'islandora_ingest_test_testcmodel'); + $this->assertFieldByName('ingest', 'Ingest'); + // Move back to first step. + $this->drupalPost(NULL, array(), t('Previous')); + // Try a different model that has an additional step. + $edit = array( + 'model' => 'test:testcmodel2', + ); + $this->drupalPostAJAX(NULL, $edit, 'model'); + $edit = array( + 'label' => 'foobar', + 'model' => 'test:testcmodel2', + ); + $this->drupalPost(NULL, $edit, t('Next')); + $this->assertFieldByName('form_step_id', 'islandora_ingest_test_testcmodel2'); + $this->assertFieldByName('ingest', 'Ingest'); + // Ingest the thing. + $this->drupalPost(NULL, array(), t('Ingest')); + // Test that the thing got made. + $object = islandora_object_load('test:test'); + $this->assertEqual($object->label, 'foobar', 'Ingest Object matches submitted form values.'); + $this->assertEqual($object->models, array('test:testcmodel2', 'fedora-system:FedoraObject-3.0'), 'Ingest Object matches submitted form values.'); + } + +} diff --git a/tests/islandora_hooks_test.module b/tests/islandora_hooks_test.module index 315b88ee..a6b8a5b6 100644 --- a/tests/islandora_hooks_test.module +++ b/tests/islandora_hooks_test.module @@ -8,7 +8,7 @@ /** * Implements hook_islandora_object_alter(). */ -function islandora_hooks_test_islandora_object_alter(AbstractFedoraObject $object, array &$context) { +function islandora_hooks_test_islandora_object_alter(AbstractObject $object, array &$context) { switch ($context['action']) { case 'ingest': if ($object->id == 'test:testIngestedObjectHook') { @@ -54,7 +54,7 @@ function islandora_hooks_test_islandora_object_alter(AbstractFedoraObject $objec /** * Implements hook_islandora_object_alter(). */ -function islandora_hooks_test_islandora_datastream_alter(AbstractFedoraObject $object, AbstractFedoraDatastream $datastream, array &$context) { +function islandora_hooks_test_islandora_datastream_alter(AbstractObject $object, AbstractDatastream $datastream, array &$context) { switch ($context['action']) { case 'ingest': if ($object->id == 'test:testIngestedDatastreamHook') { @@ -100,7 +100,7 @@ function islandora_hooks_test_islandora_datastream_alter(AbstractFedoraObject $o /** * Implements hook_islandora_object_ingested(). */ -function islandora_hooks_test_islandora_object_ingested(FedoraObject $object) { +function islandora_hooks_test_islandora_object_ingested(AbstractObject $object) { if ($object->id == 'test:testIngestedObjectHook') { $_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_INGESTED_HOOK] = TRUE; } @@ -109,7 +109,7 @@ function islandora_hooks_test_islandora_object_ingested(FedoraObject $object) { /** * Implements hook_islandora_object_modified(). */ -function islandora_hooks_test_islandora_object_modified(FedoraObject $object) { +function islandora_hooks_test_islandora_object_modified(AbstractObject $object) { if ($object->id == 'test:testModifiedObjectHook') { $_SESSION['islandora_hooks']['hook'][ISLANDORA_OBJECT_MODIFIED_HOOK] = TRUE; } @@ -127,7 +127,7 @@ function islandora_hooks_test_islandora_object_purged($pid) { /** * Implements hook_islandora_datastream_ingested(). */ -function islandora_hooks_test_islandora_datastream_ingested(FedoraObject $object, FedoraDatastream $datastream) { +function islandora_hooks_test_islandora_datastream_ingested(AbstractObject $object, AbstractDatastream $datastream) { if ($object->id == 'test:testIngestedDatastreamHook' && $datastream->id == "TEST") { $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_INGESTED_HOOK] = TRUE; } @@ -136,7 +136,7 @@ function islandora_hooks_test_islandora_datastream_ingested(FedoraObject $object /** * Implements hook_islandora_datastream_modified(). */ -function islandora_hooks_test_islandora_datastream_modified(FedoraObject $object, FedoraDatastream $datastream) { +function islandora_hooks_test_islandora_datastream_modified(AbstractObject $object, AbstractDatastream $datastream) { if ($object->id == 'test:testModifiedDatastreamHook' && $datastream->id == "TEST") { $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_MODIFIED_HOOK] = TRUE; } @@ -145,7 +145,7 @@ function islandora_hooks_test_islandora_datastream_modified(FedoraObject $object /** * Implements hook_islandora_datastream_purged(). */ -function islandora_hooks_test_islandora_datastream_purged(FedoraObject $object, $dsid) { +function islandora_hooks_test_islandora_datastream_purged(AbstractObject $object, $dsid) { if ($object->id == 'test:testPurgedDatastreamHook' && $dsid == "TEST") { $_SESSION['islandora_hooks']['hook'][ISLANDORA_DATASTREAM_PURGED_HOOK] = TRUE; } diff --git a/tests/islandora_ingest_test.info b/tests/islandora_ingest_test.info new file mode 100644 index 00000000..974a60f2 --- /dev/null +++ b/tests/islandora_ingest_test.info @@ -0,0 +1,7 @@ +name = Islandora Testing +description = Required for testing islandora web-test case. +core = 7.x +package = Testing +hidden = TRUE +dependencies[] = islandora +files[] = islandora_test.module diff --git a/tests/islandora_ingest_test.module b/tests/islandora_ingest_test.module new file mode 100644 index 00000000..d414c717 --- /dev/null +++ b/tests/islandora_ingest_test.module @@ -0,0 +1,166 @@ + array( + 'title' => 'Ingest Form', + 'page callback' => 'islandora_ingest_test_ingest', + 'type' => MENU_LOCAL_ACTION, + 'access callback' => TRUE, + ), + ); +} + +/** + * Render the ingest form. + */ +function islandora_ingest_test_ingest() { + $connection = islandora_get_tuque_connection(); + $object = $connection->repository->constructObject('test:test'); + $object->label = 'New Object'; + $configuration = array( + 'objects' => array($object), + ); + module_load_include('inc', 'islandora', 'includes/ingest.form'); + return drupal_get_form('islandora_ingest_form', $configuration); +} + +/** + * Implements hook_islandora_ingest_steps(). + */ +function islandora_ingest_test_islandora_ingest_steps(array &$form_state) { + return array( + 'islandora_ingest_test' => array( + 'type' => 'form', + 'form_id' => 'islandora_ingest_test_set_label_form', + 'weight' => -50, + 'module' => 'islandora_ingest_test', + ), + ); +} + +/** + * Implements hook_MODEL_PID_islandora_ingest_steps(). + */ +function islandora_ingest_test_test_testcmodel_islandora_ingest_steps(array &$form_state) { + return array( + 'islandora_ingest_test_testcmodel' => array( + 'type' => 'form', + 'form_id' => 'islandora_ingest_test_testcmodel_form', + 'weight' => -30, + 'module' => 'islandora_ingest_test', + ), + ); +} + +/** + * Implements hook_MODEL_PID_islandora_ingest_steps(). + */ +function islandora_ingest_test_test_testcmodel2_islandora_ingest_steps(array &$form_state) { + return array( + 'islandora_ingest_test_testcmodel2' => array( + 'type' => 'form', + 'form_id' => 'islandora_ingest_test_testcmodel2_form', + 'weight' => -40, + 'module' => 'islandora_ingest_test', + ), + ); +} + +/** + * Sets the label of the ingestable object. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + * + * @return array + * The Drupal form definition. + */ +function islandora_ingest_test_set_label_form(array $form, array &$form_state) { + $models = array('test:nomorestepscmodel', 'test:testcmodel', 'test:testcmodel2'); + $model = isset($form_state['values']['model']) ? $form_state['values']['model'] : reset($models); + $shared_storage = &islandora_ingest_form_get_shared_storage($form_state); + $shared_storage['models'] = array($model); + return array( + '#prefix' => '
', + '#suffix' => '
', + 'label' => array( + '#type' => 'textfield', + '#title' => t('Label'), + ), + 'model' => array( + '#type' => 'select', + '#title' => t('Select a Content Model to Ingest'), + '#options' => array_combine($models, $models), + '#default' => $model, + '#ajax' => array( + 'callback' => 'islandora_ingest_test_model_ajax_callback', + 'wrapper' => 'islandora-select-content-model-wrapper', + 'method' => 'replace', + 'effect' => 'fade', + ), + ), + ); +} + +/** + * Updates the model field. + */ +function islandora_ingest_test_model_ajax_callback(array $form, array &$form_state) { + return $form; +} + +/** + * Sets the label of the ingestable object. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_ingest_test_set_label_form_submit(array $form, array &$form_state) { + $object = islandora_ingest_form_get_object($form_state); + $object->label = $form_state['values']['label']; + unset($object->models); + $object->models = array($form_state['values']['model']); +} + +/** + * Test the First content model. + */ +function islandora_ingest_test_testcmodel_form(array $form, array &$form_state) { + return array( + ); +} + +/** + * Test the CModel submit. + */ +function islandora_ingest_test_testcmodel_form_submit(array $form, array &$form_state) { + +} + +/** + * Test the second content model. + */ +function islandora_ingest_test_testcmodel2_form(array $form, array &$form_state) { + return array( + ); +} + +/** + * Test the CModel submit. + */ +function islandora_ingest_test_testcmodel2_form_submit(array $form, array &$form_state) { + +} diff --git a/tests/web_test_case.inc b/tests/islandora_web_test_case.inc similarity index 55% rename from tests/web_test_case.inc rename to tests/islandora_web_test_case.inc index 8a5b9a00..de414c17 100644 --- a/tests/web_test_case.inc +++ b/tests/islandora_web_test_case.inc @@ -28,7 +28,7 @@ class IslandoraWebTestCase extends DrupalWebTestCase { $this->backUpDrupalFilter(); $this->setUpDrupalFilter(); } - $this->createAdminUser(); + $this->admin = $this->createAdminUser(); } /** @@ -90,15 +90,44 @@ class IslandoraWebTestCase extends DrupalWebTestCase { * Creates the a full fedora admin user with a repository connection. */ protected function createAdminUser() { - $this->admin = new stdClass(); - $this->admin->uid = 1; - $this->admin->name = $this->configuration['admin_user']; - $this->admin->pass = $this->configuration['admin_pass']; + $roles = user_roles(); + $index = array_search('administrator', $roles); + $user = $this->drupalCreateUser(); + $user->roles[$index] = 'administrator'; + $user->name = $this->configuration['admin_user']; + $user->pass = $this->configuration['admin_pass']; + $user = user_save($user); $url = variable_get('islandora_base_url', $this->configuration['fedora_url']); - $connection = islandora_get_tuque_connection($this->admin, $url); - $this->admin->repository = $connection->repository; - return $this->admin; + $connection = islandora_get_tuque_connection($user, $url); + $user->repository = $connection->repository; + return $user; } + + /** + * Logs in the given user, handles the special case where the user is admin. + * + * @see DrupalWebTestCase::drupalLogin() + */ + protected function drupalLogin(stdClass $account) { + if ($account->uid == $this->admin->uid) { + // Create password for Drupal. + $edit = array('pass' => user_password()); + $account = user_save($account, $edit); + // Raw password is used to login. + $account->pass_raw = $edit['pass']; + // We must login before changing the password for fedora. + parent::drupalLogin($account); + $account->name = $this->configuration['admin_user']; + $account->pass = $this->configuration['admin_pass']; + // Save the fedora admin credentials for later GET/POST requests. + $account = user_save($account); + } + else { + parent::drupalLogin($account); + } + } + + /** * Stores the content of the Drupal Filter for later restoration. */ @@ -126,4 +155,84 @@ class IslandoraWebTestCase extends DrupalWebTestCase { unset($this->configuration); parent::tearDown(); } + + /** + * Asserts that the given datastreams exist on the object. + * + * @param AbstractObject $object + * The PID of the object + * @param array $datastreams + * An array of strings containing datastream names + */ + public function assertDatastreams($object, array $datastreams) { + if (!is_object($object)) { + $this->fail("Failed. Object passed in is invalid."); + return; + } + + foreach ($datastreams as $datastream) { + if (isset($object[$datastream])) { + $this->pass("Loaded datastream {$datastream} from PID {$object->id}"); + } + else { + $this->fail("Failed to load datastream {$datastream} from PID {$object->id}"); + } + } + } + + /** + * Gets a tuque object from a path. + * + * @param string $path + * A full or partial path to an islandora object. + * + * @return AbstractObject + * The pid of the object or FALSE if a PID is not found. + */ + public function getObjectFromPath($path) { + $path_parts = explode('/', $path); + $array_length = count($path_parts); + for ($i = 0; $i < $array_length; $i++) { + if ($path_parts[$i] == 'islandora' && isset($path_parts[$i + 1]) && $path_parts[$i + 1] == 'object') { + if (isset($path_parts[$i + 2])) { + return islandora_object_load(urldecode($path_parts[$i + 2])); + } + } + } + $this->fail("Failed to parse path : $path."); + return FALSE; + } + + /** + * Deletes an object using the PID. This does the deletion using the UI. + * + * @param string $pid + * The PID of the collection to be deleted + */ + public function deleteObject($pid) { + $current_user = $this->loggedInUser; + $user = $this->drupalCreateUser(array( + 'manage object properties', + 'delete fedora objects and datastreams', + 'view fedora repository objects', + )); + + $this->drupalLogin($user); + + $path = 'islandora/object/' . $pid . '/manage/properties'; + $edit = array(); + $this->drupalPost($path, $edit, t('Delete')); + $this->drupalPost($this->url, $edit, t('Delete')); + $object = islandora_object_load($pid); + + $this->drupalGet("islandora/object/$pid"); + $this->assertResponse(404, "Object $pid successfully deleted."); + + if ($current_user) { + $this->drupalLogin($current_user); + } + else { + $this->drupalLogout(); + } + } } diff --git a/tests/scripts/travis_setup.sh b/tests/scripts/travis_setup.sh index c3515198..45dc3ab9 100755 --- a/tests/scripts/travis_setup.sh +++ b/tests/scripts/travis_setup.sh @@ -11,12 +11,16 @@ cd islandora_tomcat export CATALINA_HOME='.' ./bin/startup.sh cd $HOME -pyrus channel-discover pear.drush.org -pyrus channel-discover pear.phpqatools.org -pyrus channel-discover pear.netpirates.net -pyrus install drush/drush -pyrus install pear/PHP_CodeSniffer -pyrus install pear.phpunit.de/phpcpd +pear upgrade –force Console_Getopt +pear upgrade –force pear +pear upgrade-all +pear channel-discover pear.drush.org +pear channel-discover pear.drush.org +pear channel-discover pear.phpqatools.org +pear channel-discover pear.netpirates.net +pear install pear/PHP_CodeSniffer +pear install pear.phpunit.de/phpcpd +pear install drush/drush phpenv rehash drush dl --yes drupal cd drupal-* @@ -33,4 +37,4 @@ drush en --yes simpletest drush en --yes potx drush en --user=1 --yes islandora drush cc all -sleep 4 +sleep 20