diff --git a/.travis.yml b/.travis.yml index 660fb448..84b226d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,14 @@ branches: only: - /^7.x/ env: - - FEDORA_VERSION="3.5" - - FEDORA_VERSION="3.6.2" - - FEDORA_VERSION="3.7.0" + matrix: + - FEDORA_VERSION="3.5" + - FEDORA_VERSION="3.6.2" + - FEDORA_VERSION="3.7.0" + global: + # This key is unique to the Islandora/islandora repository; logging will + # fail on forked repositories unless a new unique key is generated for them. + - secure: "nTv2Zb/qKlECK+xE5ahbfXI9ZZbf2ZMd796q7oPlTxUwvu6nomHnUOjJATl6tq2cj23PyJ89Jlgl5cMZ5h0QMUzYpN5hPyY6oCJxWgFamFaE3bv5E/rBd1f6WVTJW7S4UKn8Mr9R2PrX+ZxQZGVIigAfR8VfhQuP8PcuO5eMLBk=" before_install: - export ISLANDORA_DIR=$TRAVIS_BUILD_DIR - $TRAVIS_BUILD_DIR/tests/scripts/travis_setup.sh @@ -19,3 +24,5 @@ script: - drush coder-review --reviews=production,security,style,i18n,potx,sniffer islandora - phpcpd --names *.module,*.inc,*.test sites/all/modules/islandora - drush test-run --uri=http://localhost:8081 Islandora +after_failure: + - $ISLANDORA_DIR/tests/scripts/travis_after_failure.sh diff --git a/README.md b/README.md index 90d935cf..371797b2 100644 --- a/README.md +++ b/README.md @@ -42,11 +42,16 @@ INSTALLATION Before installing Islandora the XACML policies located in the policies folder should be copied into the Fedora global XACML policies folder. This will allow -"authenticated users" in Drupal to access Fedora API-M functions. +"authenticated users" in Drupal to access Fedora API-M functions. It is to be +noted that the permit-upload-to-anonymous-user.xml and +permit-apim-to-anonymous-user.xml files do not need to be present unless +requirements for anonymous ingesting are present. -You will also have to remove some default policies if you want full functionality as well. +You will also have to remove some default policies if you want full +functionality as well. -Remove deny-purge-datastream-if-active-or-inactive.xml to allow for purging of datastream versions. +Remove deny-purge-datastream-if-active-or-inactive.xml to allow for purging of +datastream versions. CONFIGURATION ------------- diff --git a/includes/admin.form.inc b/includes/admin.form.inc index b0bb0642..3dc97091 100644 --- a/includes/admin.form.inc +++ b/includes/admin.form.inc @@ -27,7 +27,7 @@ function islandora_repository_admin(array $form, array &$form_state) { '#type' => 'vertical_tabs', 'islandora_general' => array( '#type' => 'fieldset', - '#title' => t('General Configuarion'), + '#title' => t('General Configuration'), 'wrapper' => array( '#prefix' => '
', '#suffix' => '
', diff --git a/includes/authtokens.inc b/includes/authtokens.inc index 36e8689f..d5d98117 100644 --- a/includes/authtokens.inc +++ b/includes/authtokens.inc @@ -36,12 +36,7 @@ define('ISLANDORA_AUTHTOKEN_TOKEN_TIMEOUT', 300); function islandora_get_object_token($pid, $dsid, $uses = 1) { global $user; $time = time(); - // The function mt_rand is not considered cryptographically secure - // and openssl_rando_pseudo_bytes() is only available in PHP > 5.3. - // We might be safe in this case because mt_rand should never be using - // the same seed, but this is still more secure. - $token = hash("sha256", mt_rand() . $time); - + $token = bin2hex(drupal_random_bytes(32)); $id = db_insert("islandora_authtokens")->fields( array( 'token' => $token, diff --git a/includes/derivatives.inc b/includes/derivatives.inc index d25789cc..635c1c54 100644 --- a/includes/derivatives.inc +++ b/includes/derivatives.inc @@ -49,7 +49,7 @@ function islandora_do_derivatives(AbstractObject $object, array $options) { } foreach ($hook['function'] as $function) { if (function_exists($function)) { - $logging = call_user_func($function, $object, $options['force']); + $logging = call_user_func($function, $object, $options['force'], $hook); if (!empty($logging)) { $results[] = $logging; } @@ -142,11 +142,15 @@ function islandora_do_batch_derivatives(AbstractObject $object, array $options) $file = $hook['file']; } foreach ($hook['function'] as $function) { - $operations[] = array('islandora_derivative_perform_batch_operation', array( - $function, - $file, - $object->id, - $options['force']), + $operations[] = array( + 'islandora_derivative_perform_batch_operation', + array( + $function, + $file, + $object->id, + $options['force'], + $hook, + ), ); } } diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 89376f7d..f7979063 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -467,12 +467,14 @@ function islandora_ingest_form_undo_consecutive_callback_steps(array $form, arra * The step which the undo callback is being called on. */ function islandora_ingest_form_undo_callback_step(array $form, array &$form_state, array $step) { - $args = array(&$form_state); - $args = isset($step['undo_function']['args']) ? array_merge($args, $step['undo_function']['args']) : $args; - if (isset($step['undo_function']['file'])) { - require_once drupal_get_path('module', $step['module']) . "/" . $step['undo_function']['file']; + if (isset($step['undo_function'])) { + $args = array(&$form_state); + $args = isset($step['undo_function']['args']) ? array_merge($args, $step['undo_function']['args']) : $args; + if (isset($step['undo_function']['file'])) { + require_once drupal_get_path('module', $step['module']) . "/" . $step['undo_function']['file']; + } + call_user_func_array($step['undo_function']['function'], $args); } - call_user_func_array($step['undo_function']['function'], $args); } /** @@ -769,7 +771,7 @@ function islandora_ingest_form_submit(array $form, array &$form_state) { islandora_ingest_form_execute_consecutive_callback_steps($form, $form_state, $step); } // Ingest the objects. - $set_redirect = TRUE; + $set_redirect = isset($form_state['redirect']) ? FALSE : TRUE; foreach ($form_state['islandora']['objects'] as &$object) { try { islandora_add_object($object); diff --git a/includes/manage_deleted_objects.inc b/includes/manage_deleted_objects.inc index 48796304..a6b5e96e 100644 --- a/includes/manage_deleted_objects.inc +++ b/includes/manage_deleted_objects.inc @@ -332,7 +332,7 @@ function islandora_get_deleted_query($content_models, $offset = 0) { $unions .= "UNION {?subject fm:hasModel ; fm:state fm:Deleted; fm:hasModel ?object; - } + } "; } $optional = "OPTIONAL{?subject fm:label ?label}"; diff --git a/includes/regenerate_derivatives.form.inc b/includes/regenerate_derivatives.form.inc index 7fd8d059..9a7a097e 100644 --- a/includes/regenerate_derivatives.form.inc +++ b/includes/regenerate_derivatives.form.inc @@ -142,15 +142,17 @@ function islandora_regenerate_datastream_derivative_batch(AbstractDatastream $da * The pid of the object we are performing. * @param bool $force * Whether we are forcing derivative regeneration or not. + * @param array $hook + * The derivative definition. * @param array $context * The context of the current batch operation. */ -function islandora_derivative_perform_batch_operation($function, $file, $pid, $force, &$context) { +function islandora_derivative_perform_batch_operation($function, $file, $pid, $force, $hook, &$context) { if ($file) { require_once $file; } if (function_exists($function)) { - $logging = call_user_func($function, islandora_object_load($pid), $force); + $logging = call_user_func($function, islandora_object_load($pid), $force, $hook); if (!empty($logging)) { $context['results']['logging'][] = $logging; } diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index e07e76e7..47a8f23c 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -256,7 +256,7 @@ function islandora_solution_pack_form_submit(array $form, array &$form_state) { * the batch. * @param array $not_checked * The object that will bot be install. - * + * * @return array * An array defining a batch which can be passed on to batch_set(). */ @@ -367,7 +367,7 @@ function islandora_install_solution_pack($module, $op = 'install', $force = FALS $t = get_t(); // Some general replacements. - $admin_link = l($t('Solution Pack admin'), 'admin/islandora/solution_packs'); + $admin_link = l($t('Solution Pack admin'), 'admin/islandora/solution_pack_config'); $config_link = l($t('Islandora configuration'), 'admin/islandora/configure'); $t_params = array( '@module' => $module, @@ -712,9 +712,8 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL, $model = * given, than any viewer that supports either the give $mimetype or $model will * be listed. * - * @param string $mimetype - * Specify a mimetype to return only viewers that support this certain - * mimetype. + * @param array $mimetype + * List of mimetypes that the viewer supports. * @param string $content_model * Specify a content model to return only viewers that support the content * model. @@ -722,14 +721,19 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL, $model = * @return array * Viewer definitions, or FALSE if none are found. */ -function islandora_get_viewers($mimetype = NULL, $content_model = NULL) { +function islandora_get_viewers($mimetype = array(), $content_model = NULL) { $viewers = array(); $defined_viewers = module_invoke_all('islandora_viewer_info'); + + if (!is_array($mimetype)) { + $mimetype = array($mimetype); + } + // Filter viewers by MIME type. foreach ($defined_viewers as $key => $value) { $value['mimetype'] = isset($value['mimetype']) ? $value['mimetype'] : array(); $value['model'] = isset($value['model']) ? $value['model'] : array(); - if (in_array($mimetype, $value['mimetype']) OR in_array($content_model, $value['model'])) { + if (array_intersect($mimetype, $value['mimetype']) OR in_array($content_model, $value['model'])) { $viewers[$key] = $value; } } diff --git a/includes/tuque_wrapper.inc b/includes/tuque_wrapper.inc index d30af147..573d7c62 100644 --- a/includes/tuque_wrapper.inc +++ b/includes/tuque_wrapper.inc @@ -115,6 +115,10 @@ class IslandoraFedoraRepository extends FedoraRepository { foreach ($object as $dsid => $datastream) { islandora_invoke_datastream_hooks(ISLANDORA_DATASTREAM_INGESTED_HOOK, $object->models, $dsid, $object, $datastream); } + // Fire of event if rules is enabled. + if (module_exists('rules')) { + rules_invoke_event('islandora_object_ingested', $object); + } return $ret; } catch (Exception $e) { diff --git a/islandora.api.php b/islandora.api.php index 0534ffe7..eeeeae1c 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -423,13 +423,13 @@ function hook_islandora_undeletable_datastreams(array $models) { * - form_id: The form building function to call to get the form structure * for this step. * - args: An array of arguments to pass to the form building function. - * Required "callback" type specific parameters: - * - do_function: An associate array including: + * "Callback" type specific parameters: + * - do_function: A required associative array including: * - 'function': The callback function to be called. * - 'args': An array of arguments to pass to the callback function. * - 'file': A file to include (relative to the module's path, including * the file's extension). - * - undo_function: An associate array including: + * - undo_function: An optional associative array including: * - 'function': The callback function to be called to reverse the * executed action in the ingest steps. * - 'args': An array of arguments to pass to the callback function. @@ -472,7 +472,7 @@ function hook_islandora_ingest_steps(array $form_state) { * * @param array $steps * An array of steps as generated by hook_islandora_ingest_steps(). - * + * * @param array $form_state * An array containing the Drupal form_state. */ @@ -497,7 +497,7 @@ function hook_CMODEL_PID_islandora_ingest_steps(array $form_state) { * * @param array $steps * An array of steps as generated by hook_islandora_ingest_steps(). - * + * * @param array $form_state * An array containing the Drupal form_state. */ @@ -635,10 +635,11 @@ function hook_CMODEL_PID_islandora_overview_object_alter(AbstractObject &$object * - function: An array of function(s) to be ran when constructing * derivatives. Functions that are defined to be called for derivation * creation must have the following structure: - * module_name_derivative_creation_function($object, $force = FALSE) + * module_name_derivative_creation_function($object, $force = FALSE, $hook) * These functions must return an array in the structure of: * - success: Bool denoting whether the operation was successful. - * - messages: An array structure containing: + * - messages: An array structure containing zero or more array's with the + * following fields: * - message: A string passed through t() describing the * outcome of the operation. * - message_sub: (Optional) Substitutions to be passed along to t() or @@ -704,7 +705,7 @@ function hook_CMODEL_PID_islandora_derivative() { function hook_islandora_update_related_objects_properties(AbstractObject $object) { $related_objects = get_all_children_siblings_and_friends($object); $pids_to_return = array(); - foreach($related_objects as $related_object) { + foreach ($related_objects as $related_object) { $pids_to_return[] = $related_object->id; } return $pids_to_return; diff --git a/islandora.module b/islandora.module index 9e7809eb..cc4cee4b 100644 --- a/islandora.module +++ b/islandora.module @@ -109,13 +109,35 @@ function islandora_menu() { 'file' => 'includes/metadata.inc', 'access arguments' => array('administer site configuration'), ); - $items['admin/islandora/solution_packs'] = array( - 'title' => 'Solution packs', + $items['admin/islandora/solution_pack_config'] = array( + 'title' => 'Solution pack configuration', + 'description' => 'Configure Islandora solution packs.', + 'access callback' => 'islandora_find_package', + 'access arguments' => array('Islandora Solution Packs'), + 'type' => MENU_NORMAL_ITEM, + ); + $items['admin/islandora/islandora_viewers'] = array( + 'title' => 'Islandora Viewers', + 'description' => 'Configure custom viewers.', + 'access callback' => 'islandora_find_package', + 'access arguments' => array('Islandora Viewers'), + 'type' => MENU_NORMAL_ITEM, + ); + $items['admin/islandora/tools'] = array( + 'title' => 'Islandora Utility Modules', + 'description' => 'Configure Islandora utility modules.', + 'access callback' => 'islandora_find_package', + 'access arguments' => array('Islandora Tools'), + 'type' => MENU_NORMAL_ITEM, + ); + $items['admin/islandora/solution_pack_config/solution_packs'] = array( + 'title' => 'Solution packs required objects', 'description' => 'Install content models and collections required by installed solution packs.', 'page callback' => 'islandora_solution_packs_admin', 'access arguments' => array(ISLANDORA_ADD_DS), 'file' => 'includes/solution_packs.inc', 'type' => MENU_NORMAL_ITEM, + 'weight' => -1, ); $items['islandora'] = array( 'title' => 'Islandora Repository', @@ -1531,6 +1553,11 @@ function islandora_entity_property_info() { 'label' => t('Content Models'), 'description' => t('The list of content models which the object has.'), ); + $p['createdDate'] = array( + 'type' => 'text', + 'label' => t('Created Date'), + 'description' => t('When the object was created.'), + ); return $info; } @@ -1825,9 +1852,9 @@ function islandora_repair_drupal_filter() { } } - /** - * Implements hook_islandora_metadata_display_info(). - */ +/** + * Implements hook_islandora_metadata_display_info(). + */ function islandora_islandora_metadata_display_info() { return array( 'dublin_core' => array( @@ -1864,3 +1891,24 @@ function islandora_islandora_datastream_access($op, AbstractDatastream $datastre } return $result; } + +/** + * Access for submenu items. + * + * @param string $package_name + * Name of the package + * + * @return bool + * Access granted + */ +function islandora_find_package($package_name) { + $results = system_get_info('module'); + $found = FALSE; + foreach ($results as $name => $values) { + if ($values['package'] == $package_name) { + $found = TRUE; + break; + } + } + return $found && user_access('administer site configuration'); +} diff --git a/islandora.rules.inc b/islandora.rules.inc index 4045b1b9..02f5c822 100644 --- a/islandora.rules.inc +++ b/islandora.rules.inc @@ -5,11 +5,30 @@ * Does rule type stuff, */ +/** + * Implements hook_rules_event_info(). + */ +function islandora_rules_event_info() { + return array( + 'islandora_object_ingested' => array( + 'group' => t('Islandora'), + 'label' => t('Object ingested'), + 'variables' => array( + 'object' => array( + 'type' => 'islandora_object', + 'label' => t('The ingested object'), + 'description' => t('A Tuque object for the ingested Fedora object, as an entity.'), + ), + ), + ), + ); +} + /** * Helper function to get reused "parameter" array. */ function islandora_rules_relationship_parameter_array() { - $to_return = array( + return array( 'subject' => array( 'type' => 'islandora_object', 'label' => t('Subject'), @@ -39,8 +58,6 @@ function islandora_rules_relationship_parameter_array() { 'default value' => 0, ), ); - - return $to_return; } /** diff --git a/islandora.rules_defaults.inc b/islandora.rules_defaults.inc new file mode 100644 index 00000000..17f83b63 --- /dev/null +++ b/islandora.rules_defaults.inc @@ -0,0 +1,26 @@ +label = 'E-mail admin'; + $rule->active = FALSE; + $rule + ->event('islandora_object_ingested') + ->action( + 'mail', + array( + 'to' => '[site:mail]', + 'subject' => '[[site:name]] "[object:label]" has been ingested', + 'message' => '[object:label] has been ingested as [object:id].', + ) + ); + return array('islandora_object_ingested_notify_admin' => $rule); +} diff --git a/policies/permit-apim-to-anonymous-user.xml b/policies/permit-apim-to-anonymous-user.xml new file mode 100644 index 00000000..4fc711f5 --- /dev/null +++ b/policies/permit-apim-to-anonymous-user.xml @@ -0,0 +1,31 @@ + + + note that other policies may provide exceptions to this broad policy. This policy assumes api-m users have to be authenticated + + + + + anonymous user + + + + + + + + + + + urn:fedora:names:fedora:2.1:action:api-m + + + + + + + diff --git a/policies/permit-upload-to-anonymous-user.xml b/policies/permit-upload-to-anonymous-user.xml new file mode 100644 index 00000000..bebcd37b --- /dev/null +++ b/policies/permit-upload-to-anonymous-user.xml @@ -0,0 +1,31 @@ + + + + + + + + anonymous user + + + + + + + + + + + urn:fedora:names:fedora:2.1:action:id-upload + + + + + + + diff --git a/tests/datastream_validators.inc b/tests/datastream_validators.inc index 854f6db5..802f32d2 100644 --- a/tests/datastream_validators.inc +++ b/tests/datastream_validators.inc @@ -192,7 +192,6 @@ abstract class DatastreamValidator { $this->params = $params; if ($object[$datastream]) { $this->datastreamContent = $object[$datastream]->content; - $this->runValidators(); } else { drupal_set_message(t("Error grabbing content from datastream %datastream in object %id", 'error'), array( @@ -226,6 +225,9 @@ abstract class DatastreamValidator { * The results. */ public function getResults() { + if (empty($this->results)) { + $this->runValidators(); + } return $this->results; } @@ -415,19 +417,24 @@ class PDFDatastreamValidator extends DatastreamValidator { * integer representing the number of times it should appear in the datastream. */ class TextDatastreamValidator extends DatastreamValidator { + /** + * Constructor override; blow up if we don't have our two values. + */ + public function __construct(IslandoraFedoraObject $object, $datastream, array $params = array()) { + if (count($params) < 2) { + throw new InvalidArgumentException('$params must contain at least two values to instantiate a TextDatastreamValidator.'); + } + parent::__construct($object, $datastream, $params); + } /** * Asserts that the string given appears the correct number of times. */ protected function assertTextStringCount() { - if (!isset($this->params[1])) { - $this->addResult(FALSE, "TextDatastreamValidator cannot be instantiated without two keys in the 'params' variable."); - return; - } $string_count = self::getTextStringCount(); - $expected = $this->params[1]; + list($string, $expected) = $this->params; $assertion = $string_count === $expected; - $this->addResult($assertion, "{$this->datastream} datastream contains the word(s) '{$this->params[0]}' repeated {$string_count} time(s) (expected: {$expected})."); + $this->addResult($assertion, "{$this->datastream} datastream contains the word(s) '{$string}' repeated {$string_count} time(s) (expected: {$expected})."); } /** @@ -463,12 +470,9 @@ class WAVDatastreamValidator extends DatastreamValidator { * @param array $params * An extra array of parameters the validator might need. */ - public function __construct($object, $datastream, array $params = array()) { - $this->object = $object; - $this->datastream = $datastream; - $this->params = $params; - $this->datastreamContent = bin2hex($object[$datastream]->content); - $this->runValidators(); + public function __construct(IslandoraFedoraObject $object, $datastream, array $params = array()) { + parent::__construct($object, $datastream, $params); + $this->datastreamContent = bin2hex($this->datastreamContent); } /** diff --git a/tests/islandora_web_test_case.inc b/tests/islandora_web_test_case.inc index e866a929..8a1e5ce8 100644 --- a/tests/islandora_web_test_case.inc +++ b/tests/islandora_web_test_case.inc @@ -345,7 +345,8 @@ class IslandoraWebTestCase extends DrupalWebTestCase { * An array containing object information using these keys: * 'label' - The object label; randomized if not set. * '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, or a + * string containing a single content model PID. * '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. @@ -361,8 +362,7 @@ class IslandoraWebTestCase extends DrupalWebTestCase { * FALSE if the object ingest failed, or the object array if successful. */ public function ingestConstructedObject(array $properties = array(), array $datastreams = array()) { - module_load_include('inc', 'islandora', 'includes/tuque'); - $tuque = new IslandoraTuque(); + $tuque = islandora_get_tuque_connection($this->admin); $repository = $tuque->repository; if (!isset($properties['pid'])) { $properties['pid'] = "islandora"; @@ -385,13 +385,14 @@ class IslandoraWebTestCase extends DrupalWebTestCase { $object->owner = $this->loggedInUser->name; } - if (isset($properties['models']) && is_array($properties['models'])) { - foreach ($properties['models'] as $model) { - $object->relationships->add(FEDORA_MODEL_URI, 'hasModel', $model); + if (isset($properties['models'])) { + try { + $object->models = (array) $properties['models']; + } + catch (Exception $e) { + $this->fail("Encountered an exception when trying to add content models to {$object->id}: $e"); + return FALSE; } - } - elseif (isset($properties['models']) && !is_array($properties['models'])) { - $this->fail(t("'models' key of properties variable is not an array. Content model(s) will not be set."), 'Islandora'); } $repository->ingestObject($object); @@ -472,4 +473,132 @@ QUERY; } } + /** + * These are a few quick helper functions to fill in a gap in the standard + * DrupalWebTestCase where no function exists to test for the simple existence + * or non-existence of an error. + */ + + /** + * Asserts that an error is found in $this->content. + * + * @param string $message + * The message to pass on to the results. + * @param string $group + * The group to place the result in. + * + * @return bool + * TRUE on success, FALSE on failure. + */ + public function assertError($message = '', $group = 'Other') { + if (!$message) { + $message = "Error found on current page when error was expected."; + } + return $this->assertRaw("
", $message, $group); + } + + /** + * Asserts that no error is found in $this->content. + * + * @param string $message + * The message to pass on to the results. + * @param string $group + * The group to place the result in. + * + * @return bool + * TRUE on success, FALSE on failure. + */ + public function assertNoError($message = '', $group = 'Other') { + if (!$message) { + $message = "No error found on current page when no error was expected."; + } + return $this->assertNoRaw("
", $message, $group); + } + + /** + * Asserts that a warning is found in $this->content. + * + * @param string $message + * The message to pass on to the results. + * @param string $group + * The group to place the result in. + * + * @return bool + * TRUE on success, FALSE on failure. + */ + public function assertWarning($message = '', $group = 'Other') { + if (!$message) { + $message = "Warning found on current page when warning was expected."; + } + return $this->assertRaw("
", $message, $group); + } + + /** + * Asserts that no warning is found in $this->content. + * + * @param string $message + * The message to pass on to the results. + * @param string $group + * The group to place the result in. + * + * @return bool + * TRUE on success, FALSE on failure. + */ + public function assertNoWarning($message = '', $group = 'Other') { + if (!$message) { + $message = "No warning found on current page when no warning was expected."; + } + return $this->assertNoRaw("
", $message, $group); + } + + /** + * Makes a drupalPost() request, using the form submit button's ID. + * + * Because drupalPost() is silly and doesn't let us choose which button we'd + * like to select if multiple buttons have the same value, this function + * allows us to select whatever button we'd like based on the ID instead. + * + * This is done via the absolutely hilarious method of fudging the actual + * button labels that don't have the ID we want, so that the only one left + * with the correct label is the one with the right ID. + * + * @see DrupalWebTestCase::drupalPost() + * + * @param string $path + * Location of the post form. + * @param array $edit + * Field data in an associative array. + * @param string $submit + * Value of the submit button whose click is to be emulated. + * @param string $id + * ID of the submit button whose click is to be emulated. + * @param array $options + * Options to be forwarded to url(). + * @param array $headers + * An array containing additional HTTP request headers, each formatted as + * "name: value". + * @param null $form_html_id + * (optional) HTML ID of the form to be submitted. + * @param null $extra_post + * (optional) A string of additional data to append to the POST submission. + * + * @return bool|string + * The content from the POST request's curlExec, or FALSE on fail. + */ + public function drupalPostByID($path, $edit, $submit, $id, array $options = array(), array $headers = array(), $form_html_id = NULL, $extra_post = NULL) { + $buttons = $this->xpath("//input[@type=\"submit\" and @value=\"{$submit}\"]"); + if (empty($buttons)) { + $this->fail("No buttons found on the page with value '$submit'"); + return FALSE; + } + $i = 0; + foreach ($buttons as $button) { + if ($button['id'] !== $id) { + $button['value'] .= "_$i"; + $i++; + } + } + return $this->drupalPost($path, $edit, $submit, $options, $headers, $form_html_id, $extra_post); + } + } diff --git a/tests/scripts/travis_after_failure.sh b/tests/scripts/travis_after_failure.sh new file mode 100755 index 00000000..288cb75c --- /dev/null +++ b/tests/scripts/travis_after_failure.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Get the end portion of the TRAVIS_REPO_SLUG for the branch name. +DELIMITED_SLUG = $(echo $TRAVIS_REPO_SLUG | tr "/" "\n") +CURRENT_REPO = "${DELIMITED_SLUG[1]}" + +# Git business +export VERBOSE_DIR = $HOME/sites/default/files/simpletest/verbose +cd $HOME +git clone https://islandora-logger:$LOGGER_PW@github.com/Islandora/islandora_travis_logs.git +cd islandora_travis_logs +git checkout -B $CURRENT_REPO + +# Out with the old, in with the new +git rm $HOME/islandora_travis_logs/*.* +cp $VERBOSE_DIR/*.* $HOME/islandora_travis_logs +git add -A +git commit -m "Job: $TRAVIS_JOB_NUMBER Commit: $TRAVIS_COMMIT" +git push origin $CURRENT_REPO diff --git a/tests/scripts/travis_setup.sh b/tests/scripts/travis_setup.sh index c1bd7751..3991afcd 100755 --- a/tests/scripts/travis_setup.sh +++ b/tests/scripts/travis_setup.sh @@ -12,15 +12,16 @@ export CATALINA_HOME='.' export JAVA_OPTS="-Xms1024m -Xmx1024m -XX:MaxPermSize=512m -XX:+CMSClassUnloadingEnabled -Djavax.net.ssl.trustStore=$CATALINA_HOME/fedora/server/truststore -Djavax.net.ssl.trustStorePassword=tomcat" ./bin/startup.sh cd $HOME +pear channel-discover pear.drush.org 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-1.4.8 -pear install pear.phpunit.de/phpcpd + +# "prefer-source" required due to SSL shenanigans on the Travis boxes... +composer global require --prefer-source 'squizlabs/php_codesniffer=*' 'sebastian/phpcpd=*' +# Because we can't add to the PATH here and this file is used in many repos, +# let's just throw symlinks in. +find $HOME/.composer/vendor/bin -executable \! -type d -exec sudo ln -s {} /usr/local/sbin/ \; # Install Drush git clone https://github.com/drush-ops/drush.git @@ -34,6 +35,10 @@ phpenv rehash drush dl --yes drupal cd drupal-* drush si minimal --db-url=mysql://drupal:drupal@localhost/drupal --yes +# Needs to make things from Composer be available (PHP CS, primarily) +sudo chmod a+w sites/default/settings.php +echo "include_once '$HOME/.composer/vendor/autoload.php';" >> sites/default/settings.php +sudo chmod a-w sites/default/settings.php drush runserver --php-cgi=$HOME/.phpenv/shims/php-cgi localhost:8081 &>/dev/null & ln -s $ISLANDORA_DIR sites/all/modules/islandora mv sites/all/modules/islandora/tests/travis.test_config.ini sites/all/modules/islandora/tests/test_config.ini diff --git a/theme/islandora-dublin-core-display.tpl.php b/theme/islandora-dublin-core-display.tpl.php index 2c2a02ee..52c80607 100644 --- a/theme/islandora-dublin-core-display.tpl.php +++ b/theme/islandora-dublin-core-display.tpl.php @@ -17,7 +17,7 @@
>
-
+ +
+

+
    + +
  • label, "islandora/object/{$collection->id}"); ?>
  • + +
+
+ diff --git a/theme/theme.inc b/theme/theme.inc index b783cfa8..feac06b2 100644 --- a/theme/theme.inc +++ b/theme/theme.inc @@ -109,6 +109,7 @@ function islandora_preprocess_islandora_default(&$variables) { $islandora_object = $variables['islandora_object']; module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/datastream'); + module_load_include('inc', 'islandora', 'includes/metadata'); $variables['parent_collections'] = islandora_get_parents_from_rels_ext($islandora_object); @@ -140,8 +141,13 @@ function islandora_preprocess_islandora_default(&$variables) { $dc_object = DublinCore::importFromXMLString($islandora_object['DC']->content); $dc_array = $dc_object->asArray(); } + // We should eventually remove the DC object and dc_array code as it only + // exists to not break legacy implementations. $variables['dc_array'] = isset($dc_array) ? $dc_array : array(); $variables['islandora_dublin_core'] = isset($dc_object) ? $dc_object : NULL; + + $variables['metadata'] = islandora_retrieve_metadata_markup($islandora_object, TRUE); + $variables['description'] = islandora_retrieve_description_markup($islandora_object); $variables['islandora_object_label'] = $islandora_object->label; if (isset($islandora_object['TN']) && islandora_datastream_access(ISLANDORA_VIEW_OBJECTS, $islandora_object['TN'])) { $variables['islandora_thumbnail_url'] = url("islandora/object/{$islandora_object->id}/datastream/TN/view");