diff --git a/css/islandora.admin.css b/css/islandora.admin.css index ab1e4e86..2e3a0f41 100644 --- a/css/islandora.admin.css +++ b/css/islandora.admin.css @@ -1,9 +1,11 @@ -/* - Document : islandora_basic_collection.admin.css - Created on : May 23, 2012, 11:23:06 AM - Description: - Purpose of the stylesheet follows. -*/ - +/** + * @file + * Css file for Islandora admin pages + */ +/* Solution pack admin page */ +.islandora-solution-pack-fieldset +{ + padding-top: 0.5em; +} \ No newline at end of file diff --git a/includes/islandora.ingest.inc b/includes/islandora.ingest.inc index bf33466a..5308006d 100644 --- a/includes/islandora.ingest.inc +++ b/includes/islandora.ingest.inc @@ -5,6 +5,9 @@ * This file contains ingest callback functions */ +/** + * @TODO: needs documentation + */ function islandora_ingest_get_information(AbstractFedoraObject $collection_object) { $models = $collection_object->models; $collection_info = module_invoke_all('islandora_ingest_get_information', $models, $collection_object); @@ -12,6 +15,9 @@ function islandora_ingest_get_information(AbstractFedoraObject $collection_objec return $collection_info; } +/** + * @TODO: needs documentation + */ function islandora_ingest_get_object($content_models, $collection_pid, $relationship, $namespace) { module_load_include('inc', 'islandora', 'includes/tuque'); global $user; @@ -25,8 +31,123 @@ function islandora_ingest_get_object($content_models, $collection_pid, $relation return $object; } +/** + * @TODO: needs documentation + */ +function islandora_ingest_new_object_prepare($namespace = NULL, $label = NULL, $datastreams = array(), $content_models = array(), $relationships = array(), $collection_pid = NULL) { + // include Tuque library + module_load_include('inc', 'islandora', 'includes/tuque'); + global $user; + // new connection + try { + $connection = new IslandoraTuque($user); + } catch (Exception $e) { + drupal_set_message(t('Unable to connect to the repository %e', array('%e' => $e)), 'error'); + return; + } + // construct new object + $object = $connection->repository->constructObject($namespace); + + // add label + if (!empty($label)) { + $object->label = $label; + } + // add content model relationship(s) + foreach ($content_models as $content_model) { + $object->relationships->add(FEDORA_MODEL_URI, 'hasModel', $content_model); + } + // add collection relationship(s) + if (!empty($relationships)) { + foreach ($relationships as $relationship) { + $object->relationships->add(FEDORA_RELS_EXT_URI, $relationship['relationship'], $relationship['pid']); + } + } + // add datastreams + foreach ((array) $datastreams as $ds) { + // variables + $ds_id = $ds['dsid']; + $ds_label = isset($ds['label']) ? $ds['label'] : ''; + $ds_mimetype = isset($ds['mimetype']) ? $ds['mimetype'] : 'text/xml'; + $ds_control_group = (isset($ds['control_group']) AND in_array($ds['control_group'], array('X', 'M', 'R', 'E'))) ? $ds['control_group'] : 'M'; + $ds_datastream_file = url($ds['datastream_file'], array('absolute' => TRUE)); + + // datastream object + $datastream = $object->constructDatastream($ds_id, $ds_control_group); + $datastream->label = $ds_label; + $datastream->mimetype = $ds_mimetype; + switch ($ds_control_group) { + case 'M': + $datastream->setContentFromUrl($ds_datastream_file); + break; + case 'X': + $datastream->setContentFromString(file_get_contents($ds_datastream_file)); + break; + } + $object->ingestDatastream($datastream); + } + + module_invoke_all('islandora_ingest_pre_ingest', $object, $content_models, $collection_pid); + return $object; +} + +/** + * @TODO: needs documentation + */ function islandora_ingest_add_object(&$object) { $object->repository->ingestObject($object); module_invoke_all('islandora_ingest_post_ingest', $object); return $object; -} \ No newline at end of file +} + + +function islandora_ingest_new_object($object_model) { + // prepare variables + // namespace + $namespace = $object_model['pid']; + // label + $label = !empty($object_model['label']) ? $object_model['label'] : NULL; + // datastreams + $datastreams = array(); + if (!empty($object_model['datastreams']) AND is_array($object_model['datastreams'])) { + $datastreams = $object_model['datastreams']; + } + // content models + $content_models = array(); + if (!empty($object_model['cmodel'])) { + if (is_array($object_model['cmodel'])) { + $content_models = $object_model['cmodel']; + } + else { + $content_models[] = $object_model['cmodel']; + } + } + // relationships + $relationships = array(); + // single parent + if (!empty($object_model['parent']) AND !is_array($object_model['parent'])) { + $relationships[] = array('relationship' => 'isMemberOfCollection', 'pid' => $object_model['parent']); + } + // parents array + if (!empty($object_model['parents']) AND is_array($object_model['parents'])) { + foreach ($object_model['parents'] as $parent) { + $relationships[] = array('relationship' => 'isMemberOfCollection', 'pid' => $parent); + } + } + // other relationships + if (!empty($object_model['relationships']) AND is_array($object_model['relationships'])) { + foreach ($object_model['relationships'] as $relationship) { + $relationships[] = array('relationship' => $relationship['relationship'], 'pid' => $relationship['pid']); + } + } + + // build new object + $object = islandora_ingest_new_object_prepare($namespace, $label, $datastreams, $content_models, $relationships); + + // ingest new object + islandora_ingest_add_object($object); +} + + + + + diff --git a/includes/purge.form.inc b/includes/purge.form.inc index 62c18ba9..32517933 100644 --- a/includes/purge.form.inc +++ b/includes/purge.form.inc @@ -26,36 +26,9 @@ function islandora_purge_object_submit($form, &$form_state) { $object_id = $form_state['values']['pid']; $collection = $form_state['values']['col']; - if (!$object_id) { - drupal_set_message(t('Cannot remove object, object id not set')); - return; - } + // purge object + islandora_object_purge($object_id); - $object = islandora_object_load($object_id); - - if (!$object) { - drupal_set_message(t('Could not remove object, object not found')); - return; - } - $content_models = $object->models; - $arr = module_invoke_all('islandora_pre_purge_object', $object); //notify modules of pending deletion - if (isset($arr['delete']) && $arr['delete']) { - try { - $object->delete(); - } catch (Exception $e) { - drupal_set_message(t('Error deleting Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error'); - return ""; - } - } - else { - try { - $object->repository->purgeObject($object_id); - } catch (Exception $e) { - drupal_set_message(t('Error purging Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error'); - return ""; - } - } - module_invoke_all('islandora_post_purge_object', $object_id, $content_models); //notify modules post deletion drupal_goto($collection); } diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc new file mode 100644 index 00000000..f24c269d --- /dev/null +++ b/includes/solution_packs.inc @@ -0,0 +1,257 @@ + $solution_pack_info) { + $objects = array(); + foreach ($solution_pack_info as $field => $value) { + switch ($field) { + case 'title': + $solution_pack_name = $value; + break; + case 'objects': + $objects = $value; + break; + } + } + // get form + $form_array = drupal_get_form('islandora_solution_pack_form_' . $solution_pack_module, $solution_pack_module, $solution_pack_name, $objects); + // render form + $output .= drupal_render($form_array); + } + + return $output; +} + + +function islandora_solution_pack_form($form, &$form_state, $solution_pack_module, $solution_pack_name, $objects = array()) { + + // set variables + global $base_path; + $needs_update = FALSE; + $needs_install = FALSE; + $form = array(); + + $form['solution_pack'] = array( + '#type' => 'fieldset', + '#collapsible' => FALSE, + '#collapsed' => FALSE, + '#attributes' => array('class' => array('islandora-solution-pack-fieldset')), + ); + + // adding values + $form['solution_pack']['solution_pack_module'] = array( + '#type' => 'value', + '#value' => $solution_pack_module, + ); + $form['solution_pack']['solution_pack_name'] = array( + '#type' => 'value', + '#value' => $solution_pack_name, + ); + $form['solution_pack']['objects'] = array( + '#type' => 'value', + '#value' => $objects, + ); + + // table + // header + $table_header = array('PID', 'Status'); + $table_rows = array(); + + // loop over defined objects + foreach ($objects as $object) { + $datastreams = NULL; + if (isset($object['pid'])) { + $pid = $object['pid']; + + // load object + $item = islandora_object_load($pid); + + $table_row = array($object['pid']); + $object_status = t('Up-to-date'); + if (!$item) { + $object_status = t('Missing'); + $needs_install = TRUE; + } + else { + if (isset($object['dsid']) && isset($object['datastream_file']) && isset($object['dsversion'])) { + $datastreams = array( + array( + 'dsid' => $object['dsid'], + 'datastream_file' => $object['datastream_file'], + 'dsversion' => $object['dsversion'], + ), + ); + } + elseif (!empty($object['datastreams'])) { + $datastreams = $object['datastreams']; + } + if (!empty($datastreams) && is_array($datastreams)) { + foreach ($datastreams as $ds) { + + $ds_id = $ds['dsid']; + // check if defined datastream exists in the object + if (!$item[$ds_id]) { + $needs_update = TRUE; + $object_status = t('Missing datastream'); + break; + } + elseif (isset($ds['dsversion'])) { + // Check if the datastream is versioned and needs updating. + $installed_version = islandora_get_islandora_datastream_version($item, $ds['dsid']); + $available_version = islandora_get_islandora_datastream_version(NULL, NULL, $ds['datastream_file']); + + if ($available_version > $installed_version) { + $needs_update = TRUE; + $object_status = t('Out of date'); + break; + } + } + } + } + } + array_push($table_row, $object_status); + $table_rows[] = $table_row; + } + } + + // title + if (!$form_state['submitted']) { + $form['solution_pack']['solution_pack_label'] = array( + '#markup' => filter_xss($solution_pack_name), + '#prefix' => '

', + '#suffix' => '

', + ); + + $form['solution_pack']['install_status'] = array( + '#markup' => '' . t('Object status:') . ' ', + '#prefix' => '
', + '#suffix' => '
', + ); + if (!$needs_install && !$needs_update) { + $form['solution_pack']['install_status']['#markup'] .= ' ' . theme('image', array('path' => 'misc/watchdog-ok.png')) . ' ' . t('All required objects are installed and up-to-date.'); + $submit_button_text = t("Force reinstallation of objects"); + } + else { + $form['solution_pack']['install_status']['#markup'] .= ' ' . theme('image', array('path' => 'misc/watchdog-warning.png')) . ' ' . t('Some objects must be re-ingested. See objects list for details.'); + $submit_button_text = t("Install objects"); + + } + + $form['solution_pack']['table'] = array( + '#type' => 'item', + '#markup' => theme('table', array('header' => $table_header, 'rows' => $table_rows)), + ); + } + + $form['solution_pack']['submit'] = array( + '#value' => $submit_button_text, + '#type' => 'submit', + '#name' => $solution_pack_module, + '#attributes' => array('class' => array('islandora-solution-pack-submit')), + '#weight' => 40, + ); + + $form['solution_pack']['#submit'] = array( + 'islandora_solution_pack_form_submit', + ); + + return $form; +} + +/** + * Submit handler for solution pack form. + * + * @param array $form + * The form submitted. + * @param array_reference $form_state + * The state of the form submited. + */ +function islandora_solution_pack_form_submit($form, &$form_state) { + + // get variables + $solution_pack_module = $form_state['values']['solution_pack_module']; + $solution_pack_name = $form_state['values']['solution_pack_name']; + $objects = $form_state['values']['objects']; + + $batch = array( + 'title' => t('Installing / updating solution pack objects'), + 'file' => drupal_get_path('module', 'islandora') . '/includes/solution_packs.inc', + 'operations' => array(), + ); + + foreach ($objects as $object) { + // Add this object to the batch job queue. + $batch['operations'][] = array('islandora_batch_reingest_object', array($object)); + } + + batch_set($batch); + + // Hook to let solution pack objects be modified. + // Not using module_invoke so solution packs can be expanded by other modules. + module_invoke_all('islandora_postprocess_solution_pack', $solution_pack_module); + +} + + + + +/** + * Batch reingest object + * + * @param type $object + * @param type $context + * @return type + */ +function islandora_batch_reingest_object($object, &$context) { + + module_load_include('inc', 'islandora', 'includes/utilities'); + module_load_include('inc', 'islandora', 'includes/islandora.ingest'); + // include Tuque library + module_load_include('inc', 'islandora', 'includes/tuque'); + global $user; + // new connection + try { + $connection = new IslandoraTuque($user); + } catch (Exception $e) { + drupal_set_message(t('Unable to connect to the repository %e', array('%e' => $e)), 'error'); + return; + } + + if (!empty($object) && is_array($object)) { + // set and validate PID + $pid = $object['pid']; + if (!islandora_validate_pid($pid)) { + return NULL; + } + + // purge object + // check if object already exits + $object_query = $connection->api->a->findObjects('query', 'pid=' . $pid); + if (!empty($object_query['results'])) { + islandora_object_purge($pid); + } + else { + drupal_set_message(t('Content models for the basic image module already exist!'), 'warning'); + } + + // build and ingest new object + islandora_ingest_new_object($object); + } +} + + + + + + + diff --git a/islandora.info b/islandora.info index 1179f00b..188380f9 100644 --- a/islandora.info +++ b/islandora.info @@ -1,4 +1,4 @@ -name = Islandora Repository +name = Islandora description = "View and manage Fedora objects" package = Islandora version = 7.x-dev diff --git a/islandora.module b/islandora.module index 4a0fbd6a..a506ae23 100644 --- a/islandora.module +++ b/islandora.module @@ -59,6 +59,15 @@ function islandora_menu() { 'weight' => -1, ); + $items['admin/islandora/solution_packs'] = array( + 'title' => 'Solution packs', + 'description' => 'Install content models and collections required by installed solution packs.', + 'page callback' => 'islandora_solution_packs_admin', + 'access arguments' => array(FEDORA_ADD_DS), + 'file' => 'includes/solution_packs.inc', + 'type' => MENU_NORMAL_ITEM, + ); + $items['islandora/object/%islandora_object/manage/ingest'] = array( 'title' => 'Add an object', 'page callback' => 'islandora_ingest_callback', @@ -208,6 +217,7 @@ function islandora_admin_paths() { $paths = array(); $paths['islandora/object/*/manage*'] = TRUE; $paths['islandora/object/*/delete'] = TRUE; + $paths['islandora/object/*/datastream/*/edit'] = TRUE; return $paths; } @@ -253,6 +263,19 @@ function islandora_init() { } } +/** + * Implements hook_forms(). + */ +function islandora_forms($form_id) { + $forms = array(); + if (strpos($form_id, 'islandora_solution_pack_form_') !== FALSE) { + $forms[$form_id] = array( + 'callback' => 'islandora_solution_pack_form', + ); + } + return $forms; +} + /** * a function to call other modules edit page. If there are not any modules * that handle this function this module will build a default page. @@ -456,6 +479,48 @@ function islandora_object_load($object_id) { } } +/** + * A helper function to get a connection and purge an object + * + * @global object $user + * @param string $object_id + * @return FedoraObject + */ +function islandora_object_purge($object_id) { + if (!$object_id) { + drupal_set_message(t('Cannot remove object, object id not set')); + return; + } + + // load object + $object = islandora_object_load($object_id); + + if (!$object) { + drupal_set_message(t('Could not remove object, object not found')); + return; + } + $content_models = $object->models; + $arr = module_invoke_all('islandora_pre_purge_object', $object); // notify modules of pending deletion + if (isset($arr['delete']) && $arr['delete']) { + try { + $object->delete(); + } catch (Exception $e) { + drupal_set_message(t('Error deleting Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error'); + return ""; + } + } + else { + try { + $object->repository->purgeObject($object_id); + } catch (Exception $e) { + drupal_set_message(t('Error purging Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error'); + return ""; + } + } + module_invoke_all('islandora_post_purge_object', $object_id, $content_models); // notify modules post deletion +} + + /** * Ingest access callback */ @@ -472,4 +537,32 @@ function islandora_ingest_access_callback($object, $perm) { else { return FALSE; } +} + +/** + * Content model, collection view and collection policy datastreams may now optionally define a version + * number in their top-level XML element as an attribute, as in: + * content); + } + elseif (!empty($datastream_file)) { + $doc = simplexml_load_file($datastream_file); + } + + if (!empty($doc) && $version = (int)$doc->attributes()->version) { + $return = $version; + } + + return $return; } \ No newline at end of file